mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 20:12:19 +08:00
Backend plugins: Prepare and clean request headers before resource calls (#22321)
Moves common request proxy utilities to proxyutil package with support for removing X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto headers, setting X-Forwarded-For header and cleaning Cookie header. Using the proxyutil package to prepare and clean request headers before resource calls. Closes #21512
This commit is contained in:

committed by
GitHub

parent
8b122ee464
commit
e6cec8dbdc
@ -205,12 +205,17 @@ func (p *BackendPlugin) callResource(ctx context.Context, req CallResourceReques
|
||||
reqHeaders[k] = &pluginv2.CallResource_StringList{Values: v}
|
||||
}
|
||||
|
||||
jsonDataBytes, err := req.Config.JSONData.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protoReq := &pluginv2.CallResource_Request{
|
||||
Config: &pluginv2.PluginConfig{
|
||||
OrgId: req.Config.OrgID,
|
||||
PluginId: req.Config.PluginID,
|
||||
PluginType: req.Config.PluginType,
|
||||
JsonData: req.Config.JSONData,
|
||||
JsonData: jsonDataBytes,
|
||||
DecryptedSecureJsonData: req.Config.DecryptedSecureJSONData,
|
||||
UpdatedMS: req.Config.Updated.UnixNano() / int64(time.Millisecond),
|
||||
},
|
||||
|
@ -1,10 +1,11 @@
|
||||
package backendplugin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
|
||||
)
|
||||
|
||||
@ -69,7 +70,7 @@ type PluginConfig struct {
|
||||
OrgID int64
|
||||
PluginID string
|
||||
PluginType string
|
||||
JSONData json.RawMessage
|
||||
JSONData *simplejson.Json
|
||||
DecryptedSecureJSONData map[string]string
|
||||
Updated time.Time
|
||||
DataSourceConfig *DataSourceConfig
|
||||
|
@ -6,6 +6,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/util/proxyutil"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@ -41,7 +44,7 @@ type Manager interface {
|
||||
// CheckHealth checks the health of a registered backend plugin.
|
||||
CheckHealth(ctx context.Context, pluginID string) (*CheckHealthResult, error)
|
||||
// CallResource calls a plugin resource.
|
||||
CallResource(ctx context.Context, req CallResourceRequest) (*CallResourceResult, error)
|
||||
CallResource(pluginConfig PluginConfig, ctx *models.ReqContext, path string)
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
@ -170,18 +173,46 @@ func (m *manager) CheckHealth(ctx context.Context, pluginID string) (*CheckHealt
|
||||
}
|
||||
|
||||
// CallResource calls a plugin resource.
|
||||
func (m *manager) CallResource(ctx context.Context, req CallResourceRequest) (*CallResourceResult, error) {
|
||||
func (m *manager) CallResource(config PluginConfig, c *models.ReqContext, path string) {
|
||||
m.pluginsMu.RLock()
|
||||
p, registered := m.plugins[req.Config.PluginID]
|
||||
p, registered := m.plugins[config.PluginID]
|
||||
m.pluginsMu.RUnlock()
|
||||
|
||||
if !registered {
|
||||
return nil, ErrPluginNotRegistered
|
||||
c.JsonApiErr(404, "Plugin not registered", nil)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := p.callResource(ctx, req)
|
||||
clonedReq := c.Req.Clone(c.Req.Context())
|
||||
keepCookieNames := []string{}
|
||||
if config.JSONData != nil {
|
||||
if keepCookies := config.JSONData.Get("keepCookies"); keepCookies != nil {
|
||||
keepCookieNames = keepCookies.MustStringArray()
|
||||
}
|
||||
}
|
||||
|
||||
proxyutil.ClearCookieHeader(clonedReq, keepCookieNames)
|
||||
proxyutil.PrepareProxyRequest(clonedReq)
|
||||
|
||||
body, err := c.Req.Body().Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
c.JsonApiErr(500, "Failed to read request body", err)
|
||||
return
|
||||
}
|
||||
|
||||
req := CallResourceRequest{
|
||||
Config: config,
|
||||
Path: path,
|
||||
Method: clonedReq.Method,
|
||||
URL: clonedReq.URL.String(),
|
||||
Headers: clonedReq.Header,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
res, err := p.callResource(clonedReq.Context(), req)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to call resource", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sure a content type always is returned in response
|
||||
@ -189,7 +220,20 @@ func (m *manager) CallResource(ctx context.Context, req CallResourceRequest) (*C
|
||||
res.Headers["Content-Type"] = []string{"application/json"}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
for k, values := range res.Headers {
|
||||
if k == "Set-Cookie" {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, v := range values {
|
||||
c.Resp.Header().Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
c.WriteHeader(res.Status)
|
||||
if _, err := c.Write(res.Body); err != nil {
|
||||
p.logger.Error("Failed to write resource response", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func startPluginAndRestartKilledProcesses(ctx context.Context, p *BackendPlugin) error {
|
||||
|
Reference in New Issue
Block a user