Rendering: Remove SVG sanitization (#109797)
This commit is contained in:
@@ -18,7 +18,6 @@ type CapabilityName string
|
||||
const (
|
||||
ScalingDownImages CapabilityName = "ScalingDownImages"
|
||||
FullHeightImages CapabilityName = "FullHeightImages"
|
||||
SVGSanitization CapabilityName = "SvgSanitization"
|
||||
PDFRendering CapabilityName = "PdfRendering"
|
||||
)
|
||||
|
||||
|
||||
@@ -74,15 +74,6 @@ type ErrorOpts struct {
|
||||
ErrorRenderUnavailable bool
|
||||
}
|
||||
|
||||
type SanitizeSVGRequest struct {
|
||||
Filename string
|
||||
Content []byte
|
||||
}
|
||||
|
||||
type SanitizeSVGResponse struct {
|
||||
Sanitized []byte
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
FilePath string
|
||||
FileName string
|
||||
@@ -99,7 +90,6 @@ type RenderCSVResult struct {
|
||||
|
||||
type renderFunc func(ctx context.Context, renderType RenderType, renderKey string, options Opts) (*RenderResult, error)
|
||||
type renderCSVFunc func(ctx context.Context, renderKey string, options CSVOpts) (*RenderCSVResult, error)
|
||||
type sanitizeFunc func(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error)
|
||||
|
||||
type renderKeyProvider interface {
|
||||
get(ctx context.Context, opts AuthOpts) (string, error)
|
||||
@@ -121,16 +111,15 @@ type CapabilitySupportRequestResult struct {
|
||||
SemverConstraint string
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mock.go -package=rendering github.com/grafana/grafana/pkg/services/rendering Service
|
||||
//go:generate go run go.uber.org/mock/mockgen@v0.5.2 -destination=mock.go -package=rendering github.com/grafana/grafana/pkg/services/rendering Service
|
||||
type Service interface {
|
||||
IsAvailable(ctx context.Context) bool
|
||||
Version() string
|
||||
Render(ctx context.Context, renderType RenderType, opts Opts, session Session) (*RenderResult, error)
|
||||
RenderCSV(ctx context.Context, opts CSVOpts, session Session) (*RenderCSVResult, error)
|
||||
RenderErrorImage(theme models.Theme, error error) (*RenderResult, error)
|
||||
RenderErrorImage(theme models.Theme, err error) (*RenderResult, error)
|
||||
GetRenderUser(ctx context.Context, key string) (*RenderUser, bool)
|
||||
HasCapability(ctx context.Context, capability CapabilityName) (CapabilitySupportRequestResult, error)
|
||||
IsCapabilitySupported(ctx context.Context, capability CapabilityName) error
|
||||
CreateRenderingSession(ctx context.Context, authOpts AuthOpts, sessionOpts SessionOpts) (Session, error)
|
||||
SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/grafana/grafana/pkg/services/rendering (interfaces: Service)
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -destination=mock.go -package=rendering github.com/grafana/grafana/pkg/services/rendering Service
|
||||
//
|
||||
|
||||
// Package rendering is a generated GoMock package.
|
||||
package rendering
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
models "github.com/grafana/grafana/pkg/models"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockService is a mock of Service interface.
|
||||
type MockService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockServiceMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockServiceMockRecorder is the mock recorder for MockService.
|
||||
@@ -45,7 +51,7 @@ func (m *MockService) CreateRenderingSession(ctx context.Context, authOpts AuthO
|
||||
}
|
||||
|
||||
// CreateRenderingSession indicates an expected call of CreateRenderingSession.
|
||||
func (mr *MockServiceMockRecorder) CreateRenderingSession(ctx, authOpts, sessionOpts interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) CreateRenderingSession(ctx, authOpts, sessionOpts any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRenderingSession", reflect.TypeOf((*MockService)(nil).CreateRenderingSession), ctx, authOpts, sessionOpts)
|
||||
}
|
||||
@@ -60,7 +66,7 @@ func (m *MockService) GetRenderUser(ctx context.Context, key string) (*RenderUse
|
||||
}
|
||||
|
||||
// GetRenderUser indicates an expected call of GetRenderUser.
|
||||
func (mr *MockServiceMockRecorder) GetRenderUser(ctx, key interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) GetRenderUser(ctx, key any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRenderUser", reflect.TypeOf((*MockService)(nil).GetRenderUser), ctx, key)
|
||||
}
|
||||
@@ -75,25 +81,11 @@ func (m *MockService) HasCapability(ctx context.Context, capability CapabilityNa
|
||||
}
|
||||
|
||||
// HasCapability indicates an expected call of HasCapability.
|
||||
func (mr *MockServiceMockRecorder) HasCapability(ctx, capability interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) HasCapability(ctx, capability any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasCapability", reflect.TypeOf((*MockService)(nil).HasCapability), ctx, capability)
|
||||
}
|
||||
|
||||
// IsCapabilitySupported mocks base method.
|
||||
func (m *MockService) IsCapabilitySupported(ctx context.Context, capability CapabilityName) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsCapabilitySupported", ctx, capability)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsCapabilitySupported indicates an expected call of IsCapabilitySupported.
|
||||
func (mr *MockServiceMockRecorder) IsCapabilitySupported(ctx, capability interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsCapabilitySupported", reflect.TypeOf((*MockService)(nil).IsCapabilitySupported), ctx, capability)
|
||||
}
|
||||
|
||||
// IsAvailable mocks base method.
|
||||
func (m *MockService) IsAvailable(ctx context.Context) bool {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -103,11 +95,25 @@ func (m *MockService) IsAvailable(ctx context.Context) bool {
|
||||
}
|
||||
|
||||
// IsAvailable indicates an expected call of IsAvailable.
|
||||
func (mr *MockServiceMockRecorder) IsAvailable(ctx interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) IsAvailable(ctx any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAvailable", reflect.TypeOf((*MockService)(nil).IsAvailable), ctx)
|
||||
}
|
||||
|
||||
// IsCapabilitySupported mocks base method.
|
||||
func (m *MockService) IsCapabilitySupported(ctx context.Context, capability CapabilityName) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsCapabilitySupported", ctx, capability)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsCapabilitySupported indicates an expected call of IsCapabilitySupported.
|
||||
func (mr *MockServiceMockRecorder) IsCapabilitySupported(ctx, capability any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsCapabilitySupported", reflect.TypeOf((*MockService)(nil).IsCapabilitySupported), ctx, capability)
|
||||
}
|
||||
|
||||
// Render mocks base method.
|
||||
func (m *MockService) Render(ctx context.Context, renderType RenderType, opts Opts, session Session) (*RenderResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -118,7 +124,7 @@ func (m *MockService) Render(ctx context.Context, renderType RenderType, opts Op
|
||||
}
|
||||
|
||||
// Render indicates an expected call of Render.
|
||||
func (mr *MockServiceMockRecorder) Render(ctx, renderType, opts, session interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) Render(ctx, renderType, opts, session any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Render", reflect.TypeOf((*MockService)(nil).Render), ctx, renderType, opts, session)
|
||||
}
|
||||
@@ -133,7 +139,7 @@ func (m *MockService) RenderCSV(ctx context.Context, opts CSVOpts, session Sessi
|
||||
}
|
||||
|
||||
// RenderCSV indicates an expected call of RenderCSV.
|
||||
func (mr *MockServiceMockRecorder) RenderCSV(ctx, opts, session interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) RenderCSV(ctx, opts, session any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RenderCSV", reflect.TypeOf((*MockService)(nil).RenderCSV), ctx, opts, session)
|
||||
}
|
||||
@@ -148,24 +154,9 @@ func (m *MockService) RenderErrorImage(theme models.Theme, err error) (*RenderRe
|
||||
}
|
||||
|
||||
// RenderErrorImage indicates an expected call of RenderErrorImage.
|
||||
func (mr *MockServiceMockRecorder) RenderErrorImage(theme, error interface{}) *gomock.Call {
|
||||
func (mr *MockServiceMockRecorder) RenderErrorImage(theme, err any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RenderErrorImage", reflect.TypeOf((*MockService)(nil).RenderErrorImage), theme, error)
|
||||
}
|
||||
|
||||
// SanitizeSVG mocks base method.
|
||||
func (m *MockService) SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SanitizeSVG", ctx, req)
|
||||
ret0, _ := ret[0].(*SanitizeSVGResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SanitizeSVG indicates an expected call of SanitizeSVG.
|
||||
func (mr *MockServiceMockRecorder) SanitizeSVG(ctx, req interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SanitizeSVG", reflect.TypeOf((*MockService)(nil).SanitizeSVG), ctx, req)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RenderErrorImage", reflect.TypeOf((*MockService)(nil).RenderErrorImage), theme, err)
|
||||
}
|
||||
|
||||
// Version mocks base method.
|
||||
|
||||
@@ -31,8 +31,6 @@ type RenderingService struct {
|
||||
plugin Plugin
|
||||
renderAction renderFunc
|
||||
renderCSVAction renderCSVFunc
|
||||
sanitizeSVGAction sanitizeFunc
|
||||
sanitizeURL string
|
||||
domain string
|
||||
inProgressCount int32
|
||||
version string
|
||||
@@ -75,21 +73,14 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, remot
|
||||
|
||||
logger := log.New("rendering")
|
||||
|
||||
// URL for HTTP sanitize API
|
||||
var sanitizeURL string
|
||||
|
||||
// value used for domain attribute of renderKey cookie
|
||||
var domain string
|
||||
|
||||
// value used by the image renderer to make requests to Grafana
|
||||
rendererCallbackURL := cfg.RendererCallbackUrl
|
||||
if cfg.RendererServerUrl != "" {
|
||||
sanitizeURL = getSanitizerURL(cfg.RendererServerUrl)
|
||||
|
||||
// Default value for callback URL using a remote renderer should be AppURL
|
||||
if rendererCallbackURL == "" {
|
||||
rendererCallbackURL = cfg.AppURL
|
||||
}
|
||||
// Default value for callback URL using a remote renderer should be AppURL
|
||||
if cfg.RendererServerUrl != "" && rendererCallbackURL == "" {
|
||||
rendererCallbackURL = cfg.AppURL
|
||||
}
|
||||
|
||||
switch {
|
||||
@@ -140,10 +131,6 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, remot
|
||||
name: ScalingDownImages,
|
||||
semverConstraint: ">= 3.4.0",
|
||||
},
|
||||
{
|
||||
name: SVGSanitization,
|
||||
semverConstraint: ">= 3.5.0",
|
||||
},
|
||||
{
|
||||
name: PDFRendering,
|
||||
semverConstraint: ">= 3.10.0",
|
||||
@@ -155,7 +142,6 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, remot
|
||||
RendererPluginManager: rm,
|
||||
log: logger,
|
||||
domain: domain,
|
||||
sanitizeURL: sanitizeURL,
|
||||
pluginAvailable: exists,
|
||||
rendererCallbackURL: rendererCallbackURL,
|
||||
}
|
||||
@@ -165,11 +151,6 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, remot
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func getSanitizerURL(rendererURL string) string {
|
||||
rendererBaseURL := strings.TrimSuffix(rendererURL, "/render")
|
||||
return rendererBaseURL + "/sanitize"
|
||||
}
|
||||
|
||||
func (rs *RenderingService) Run(ctx context.Context) error {
|
||||
if rs.remoteAvailable() {
|
||||
rs.log = rs.log.New("renderer", "http")
|
||||
@@ -188,7 +169,6 @@ func (rs *RenderingService) Run(ctx context.Context) error {
|
||||
})
|
||||
rs.renderAction = rs.renderViaHTTP
|
||||
rs.renderCSVAction = rs.renderCSVViaHTTP
|
||||
rs.sanitizeSVGAction = rs.sanitizeViaHTTP
|
||||
|
||||
refreshTicker := time.NewTicker(remoteVersionRefreshInterval)
|
||||
|
||||
@@ -213,7 +193,6 @@ func (rs *RenderingService) Run(ctx context.Context) error {
|
||||
rs.version = rp.Version()
|
||||
rs.renderAction = rs.renderViaPlugin
|
||||
rs.renderCSVAction = rs.renderCSVViaPlugin
|
||||
rs.sanitizeSVGAction = rs.sanitizeSVGViaPlugin
|
||||
<-ctx.Done()
|
||||
|
||||
return nil
|
||||
@@ -367,24 +346,6 @@ func (rs *RenderingService) RenderCSV(ctx context.Context, opts CSVOpts, session
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (rs *RenderingService) SanitizeSVG(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) {
|
||||
capability, err := rs.HasCapability(ctx, SVGSanitization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !capability.IsSupported {
|
||||
return nil, fmt.Errorf("svg sanitization unsupported, requires image renderer version: %s", capability.SemverConstraint)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
action, err := rs.sanitizeSVGAction(ctx, req)
|
||||
rs.log.Info("svg sanitization finished", "duration", time.Since(start), "filename", req.Filename, "isError", err != nil)
|
||||
|
||||
return action, err
|
||||
}
|
||||
|
||||
func (rs *RenderingService) renderCSV(ctx context.Context, opts CSVOpts, renderKeyProvider renderKeyProvider) (*RenderCSVResult, error) {
|
||||
logger := rs.log.FromContext(ctx)
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
package rendering
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
|
||||
)
|
||||
|
||||
var (
|
||||
domPurifySvgConfig = map[string]any{
|
||||
// domPurifyConfig is passed directly to DOMPurify https://github.com/cure53/DOMPurify#can-i-configure-dompurify
|
||||
"domPurifyConfig": map[string]any{
|
||||
"USE_PROFILES": map[string]bool{"svg": true, "svgFilters": true},
|
||||
"ADD_TAGS": []string{"use"},
|
||||
},
|
||||
// allowAllLinksInSvgUseTags will preserve all `use` tags.
|
||||
// By default, we remove all non-self-referential `use` tags, i.e. those which `href` attribute does not start with `#`
|
||||
"allowAllLinksInSvgUseTags": false,
|
||||
}
|
||||
domPurifyConfigType = "DOMPurify"
|
||||
)
|
||||
|
||||
type formFile struct {
|
||||
fileName string
|
||||
key string
|
||||
contentType string
|
||||
content io.Reader
|
||||
}
|
||||
|
||||
func createMultipartRequestBody(values []formFile) (bytes.Buffer, string, error) {
|
||||
var b bytes.Buffer
|
||||
w := multipart.NewWriter(&b)
|
||||
for _, f := range values {
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`, f.key, f.fileName))
|
||||
h.Set("Content-Type", f.contentType)
|
||||
formWriter, err := w.CreatePart(h)
|
||||
|
||||
if err != nil {
|
||||
return bytes.Buffer{}, "", err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(formWriter, f.content); err != nil {
|
||||
return bytes.Buffer{}, "", err
|
||||
}
|
||||
|
||||
if x, ok := f.content.(io.Closer); ok {
|
||||
_ = x.Close()
|
||||
}
|
||||
}
|
||||
|
||||
if err := w.Close(); err != nil {
|
||||
return bytes.Buffer{}, "", err
|
||||
}
|
||||
|
||||
return b, w.FormDataContentType(), nil
|
||||
}
|
||||
|
||||
func (rs *RenderingService) sanitizeViaHTTP(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) {
|
||||
sanitizerUrl, err := url.Parse(rs.sanitizeURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configJson, err := json.Marshal(map[string]any{
|
||||
"config": domPurifySvgConfig,
|
||||
"configType": domPurifyConfigType,
|
||||
})
|
||||
if err != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to create the request config", "error", err, "filename", req.Filename)
|
||||
return nil, fmt.Errorf("config creation fail: %s", err)
|
||||
}
|
||||
|
||||
body, contentType, err := createMultipartRequestBody([]formFile{
|
||||
{
|
||||
fileName: "config",
|
||||
key: "config",
|
||||
contentType: "application/json",
|
||||
content: bytes.NewReader(configJson),
|
||||
},
|
||||
{
|
||||
fileName: req.Filename,
|
||||
key: "file",
|
||||
contentType: "image/svg+xml",
|
||||
content: bytes.NewReader(req.Content),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to create the request body", "error", err, "filename", req.Filename)
|
||||
return nil, fmt.Errorf("body creation fail: %s", err)
|
||||
}
|
||||
|
||||
reqContext, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
httpReq, err := http.NewRequestWithContext(reqContext, "POST", sanitizerUrl.String(), &body)
|
||||
if err != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to create the HTTP request", "error", err, "filename", req.Filename)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpReq.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", rs.Cfg.BuildVersion))
|
||||
httpReq.Header.Set("Content-Type", contentType)
|
||||
|
||||
rs.log.Debug("Sanitizer - HTTP: calling", "filename", req.Filename, "contentLength", len(req.Content), "url", sanitizerUrl)
|
||||
// make request to renderer server
|
||||
resp, err := netClient.Do(httpReq)
|
||||
if err != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to send request", "error", err)
|
||||
return nil, fmt.Errorf("sanitizer - HTTP: failed to send request: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to close response body", "statusCode", resp.StatusCode, "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if body, err := io.ReadAll(resp.Body); body != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to sanitize", "statusCode", resp.StatusCode, "error", err, "resp", string(body))
|
||||
} else {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to sanitize", "statusCode", resp.StatusCode, "error", err)
|
||||
}
|
||||
return nil, fmt.Errorf("sanitizer - HTTP: failed to sanitize %s", req.Filename)
|
||||
}
|
||||
|
||||
sanitized, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
rs.log.Error("Sanitizer - HTTP: failed to read response body", "error", err, "filename", req.Filename)
|
||||
return nil, fmt.Errorf("sanitizer - HTTP: failed to read response body: %s", err)
|
||||
}
|
||||
|
||||
return &SanitizeSVGResponse{Sanitized: sanitized}, nil
|
||||
}
|
||||
|
||||
func (rs *RenderingService) sanitizeSVGViaPlugin(ctx context.Context, req *SanitizeSVGRequest) (*SanitizeSVGResponse, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*20)
|
||||
defer cancel()
|
||||
|
||||
domPurifyConfig, err := json.Marshal(domPurifySvgConfig)
|
||||
if err != nil {
|
||||
rs.log.Error("Sanitizer - plugin: failed to parse domPurifyConfig")
|
||||
return nil, fmt.Errorf("sanitizer - plugin: failed to parse domPurifyConfig %s", err)
|
||||
}
|
||||
grpcReq := &pluginextensionv2.SanitizeRequest{
|
||||
Filename: req.Filename,
|
||||
Content: req.Content,
|
||||
ConfigType: domPurifyConfigType,
|
||||
Config: domPurifyConfig,
|
||||
}
|
||||
rs.log.Debug("Sanitizer - plugin: calling", "filename", req.Filename, "contentLength", len(req.Content))
|
||||
|
||||
rc, err := rs.plugin.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp, err := rc.Sanitize(ctx, grpcReq)
|
||||
if err != nil {
|
||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||
rs.log.Info("Sanitizer - plugin: time out")
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rsp.Error != "" {
|
||||
return nil, fmt.Errorf("sanitizer - plugin: failed to sanitize: %s", rsp.Error)
|
||||
}
|
||||
|
||||
return &SanitizeSVGResponse{Sanitized: rsp.Sanitized}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user