| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/tls" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"regexp" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/api/pluginproxy" | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | 	contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" | 
					
						
							| 
									
										
										
										
											2023-03-08 00:22:30 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings" | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-17 19:37:03 +08:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	once                 sync.Once | 
					
						
							|  |  |  | 	pluginProxyTransport *http.Transport | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | func (hs *HTTPServer) ProxyPluginRequest(c *contextmodel.ReqContext) { | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	once.Do(func() { | 
					
						
							|  |  |  | 		pluginProxyTransport = &http.Transport{ | 
					
						
							|  |  |  | 			TLSClientConfig: &tls.Config{ | 
					
						
							|  |  |  | 				InsecureSkipVerify: hs.Cfg.PluginsAppsSkipVerifyTLS, | 
					
						
							|  |  |  | 				Renegotiation:      tls.RenegotiateFreelyAsClient, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Proxy: http.ProxyFromEnvironment, | 
					
						
							|  |  |  | 			DialContext: (&net.Dialer{ | 
					
						
							|  |  |  | 				Timeout:   30 * time.Second, | 
					
						
							|  |  |  | 				KeepAlive: 30 * time.Second, | 
					
						
							|  |  |  | 			}).DialContext, | 
					
						
							|  |  |  | 			TLSHandshakeTimeout: 10 * time.Second, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pluginID := web.Params(c.Req)[":pluginId"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	plugin, exists := hs.pluginStore.Plugin(c.Req.Context(), pluginID) | 
					
						
							|  |  |  | 	if !exists { | 
					
						
							|  |  |  | 		c.JsonApiErr(http.StatusNotFound, "Plugin not found, no installed plugin with that id", nil) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-10 20:42:23 +08:00
										 |  |  | 	query := pluginsettings.GetByPluginIDArgs{OrgID: c.GetOrgID(), PluginID: plugin.ID} | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	ps, err := hs.PluginSettings.GetPluginSettingByPluginID(c.Req.Context(), &query) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.JsonApiErr(http.StatusInternalServerError, "Failed to fetch plugin settings", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	proxyPath := getProxyPath(c) | 
					
						
							| 
									
										
										
										
											2024-01-17 23:32:23 +08:00
										 |  |  | 	p, err := pluginproxy.NewPluginProxy(ps, plugin.Routes, c, proxyPath, hs.Cfg, hs.SecretsService, hs.tracer, pluginProxyTransport, hs.AccessControl, hs.Features) | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.JsonApiErr(http.StatusInternalServerError, "Failed to create plugin proxy", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p.HandleRequest() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var pluginProxyPathRegexp = regexp.MustCompile(`^\/api\/plugin-proxy\/([\w\-]+)\/?`) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func extractProxyPath(originalRawPath string) string { | 
					
						
							|  |  |  | 	return pluginProxyPathRegexp.ReplaceAllString(originalRawPath, "") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 15:50:36 +08:00
										 |  |  | func getProxyPath(c *contextmodel.ReqContext) string { | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	return extractProxyPath(c.Req.URL.EscapedPath()) | 
					
						
							|  |  |  | } |