| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | package pluginproxy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2023-02-01 23:37:08 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2020-06-12 03:15:17 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 	"text/template" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | // interpolateString accepts template data and return a string with substitutions
 | 
					
						
							|  |  |  | func interpolateString(text string, data templateData) (string, error) { | 
					
						
							| 
									
										
										
										
											2023-08-30 23:46:47 +08:00
										 |  |  | 	extraFuncs := map[string]any{ | 
					
						
							|  |  |  | 		"orEmpty": func(v any) any { | 
					
						
							| 
									
										
										
										
											2021-05-18 21:36:58 +08:00
										 |  |  | 			if v == nil { | 
					
						
							|  |  |  | 				return "" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return v | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t, err := template.New("content").Funcs(extraFuncs).Parse(text) | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("could not parse template %s", text) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var contentBuf bytes.Buffer | 
					
						
							|  |  |  | 	err = t.Execute(&contentBuf, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("failed to execute template %s", text) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return contentBuf.String(), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | // addHeaders interpolates route headers and injects them into the request headers
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func addHeaders(reqHeaders *http.Header, route *plugins.Route, data templateData) error { | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 	for _, header := range route.Headers { | 
					
						
							|  |  |  | 		interpolated, err := interpolateString(header.Content, data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 		reqHeaders.Set(header.Name, interpolated) | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // addQueryString interpolates route params and injects them into the request object
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func addQueryString(req *http.Request, route *plugins.Route, data templateData) error { | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 	q := req.URL.Query() | 
					
						
							|  |  |  | 	for _, param := range route.URLParams { | 
					
						
							|  |  |  | 		interpolatedName, err := interpolateString(param.Name, data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		interpolatedContent, err := interpolateString(param.Content, data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		q.Add(interpolatedName, interpolatedContent) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	req.URL.RawQuery = q.Encode() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-12 03:15:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func setBodyContent(req *http.Request, route *plugins.Route, data templateData) error { | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 	if route.Body != nil { | 
					
						
							|  |  |  | 		interpolatedBody, err := interpolateString(string(route.Body), data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 23:37:08 +08:00
										 |  |  | 		if !json.Valid([]byte(interpolatedBody)) { | 
					
						
							|  |  |  | 			return errors.New("body is not valid JSON") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 		req.Body = io.NopCloser(strings.NewReader(interpolatedBody)) | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 		req.ContentLength = int64(len(interpolatedBody)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |