mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-10-28 16:46:57 +08:00
fix(task-plugin): set multipart content type for upstream requests (#7655)
* fix(task-plugin): set multipart content type for upstream requests * refactor(task-plugin): copy the rebuilt multipart Content-Type as is BuildRequestBody stores writer.FormDataContentType() on the client request right before BuildRequestHeader runs, so the media type and boundary checks could never fail. Copy the value directly, as the sora adaptor did before task plugins. The test plugin now forwards the client's Content-Type, whose boundary differs from the rebuilt body, so the test also fails if a plugin header wins over the host value. --------- Co-authored-by: CaIon <i@caion.me>
This commit is contained in:
1 parent
6370b29424
commit
7aa3531ef4
2 files changed
+16
-3
No files matched your search
@@ -262,13 +262,18 @@ func (a *TaskAdaptor) BuildRequestURL(info *relaycommon.RelayInfo) (string, erro
|
||||
return a.submit.URL, pluginruntime.ValidateRequestURL(a.submit.URL, info.ChannelBaseUrl, a.plugin.Meta.AllowedHosts)
|
||||
}
|
||||
|
||||
func (a *TaskAdaptor) BuildRequestHeader(_ *gin.Context, req *http.Request, _ *relaycommon.RelayInfo) error {
|
||||
func (a *TaskAdaptor) BuildRequestHeader(c *gin.Context, req *http.Request, _ *relaycommon.RelayInfo) error {
|
||||
if a.submit == nil {
|
||||
return fmt.Errorf("plugin submit request was not built")
|
||||
}
|
||||
for name, value := range a.submit.Headers {
|
||||
req.Header.Set(name, value)
|
||||
}
|
||||
// BuildRequestBody rebuilt the multipart body with a new boundary and put its
|
||||
// Content-Type on the client request; a plugin's own Content-Type cannot match it.
|
||||
if a.submit.BodyType == "multipart" {
|
||||
req.Header.Set("Content-Type", c.Request.Header.Get("Content-Type"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -83,9 +84,10 @@ func TestTaskAdaptorRejectsDeprecatedClientResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTaskAdaptorBuildsMultipartFromOpaqueFileReference(t *testing.T) {
|
||||
// The plugin forwards the client's Content-Type, whose boundary is not the one of the rebuilt body.
|
||||
source := `
|
||||
export const meta = {apiVersion:1,key:"multipart",name:"Multipart",version:"1.0.0",author:{name:"Test"},models:["m"],fetchMode:"per_task"};
|
||||
export function buildSubmitRequest(ctx) { return {url:ctx.baseUrl+"/submit",bodyType:"multipart",parts:[{name:"model",value:"m"},{name:"input_reference",fileRef:ctx.files[0].ref}]}; }
|
||||
export function buildSubmitRequest(ctx) { return {url:ctx.baseUrl+"/submit",headers:{"Content-Type":ctx.requestHeaders["Content-Type"]},bodyType:"multipart",parts:[{name:"model",value:"m"},{name:"input_reference",fileRef:ctx.files[0].ref}]}; }
|
||||
export function parseSubmitResponse(ctx,r){return {taskId:"1"}} export function buildQueryRequest(){return {url:"https://example.com"}} export function parseTaskResult(){return {status:"SUCCESS"}}
|
||||
`
|
||||
plugin, err := pluginruntime.NewRegistry().Register(source, pluginruntime.Options{})
|
||||
@@ -108,7 +110,13 @@ export function parseSubmitResponse(ctx,r){return {taskId:"1"}} export function
|
||||
require.NoError(t, err)
|
||||
requestBytes, err := io.ReadAll(body)
|
||||
require.NoError(t, err)
|
||||
reader := multipart.NewReader(bytes.NewReader(requestBytes), strings.TrimPrefix(c.GetHeader("Content-Type"), "multipart/form-data; boundary="))
|
||||
upstreamRequest := httptest.NewRequest(http.MethodPost, "https://provider.example/submit", bytes.NewReader(requestBytes))
|
||||
require.NoError(t, adaptor.BuildRequestHeader(c, upstreamRequest, info))
|
||||
mediaType, params, err := mime.ParseMediaType(upstreamRequest.Header.Get("Content-Type"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "multipart/form-data", mediaType)
|
||||
require.NotEmpty(t, params["boundary"])
|
||||
reader := multipart.NewReader(bytes.NewReader(requestBytes), params["boundary"])
|
||||
form, err := reader.ReadForm(1024)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"m"}, form.Value["model"])
|
||||
|
||||
Reference in new issue
Block a user