diff --git a/handler/graphql.go b/handler/graphql.go index 810ffa3deaa..d027adf28c6 100644 --- a/handler/graphql.go +++ b/handler/graphql.go @@ -24,7 +24,7 @@ import ( const ( defaultMaxMemory = 32 << 20 // 32 MB - variablePrefix = "variables." + variablePrefix = "variables." ) type params struct { @@ -551,7 +551,7 @@ func addUploadToOperations(operations interface{}, upload graphql.Upload, path s var parts []interface{} for _, p := range strings.Split(path, ".") { if isNumber, err := regexp.MatchString(`\d+`, p); err != nil { - return err + return errors.New(fmt.Sprintf("failed to parse path, path: %s, subpath: %s", path, p)) } else if isNumber { index, _ := strconv.Atoi(p) parts = append(parts, index) @@ -564,7 +564,7 @@ func addUploadToOperations(operations interface{}, upload graphql.Upload, path s switch idx := p.(type) { case string: if operations == nil { - operations = map[string]interface{}{} + return errors.New(fmt.Sprintf("variables is missing, path: %s", path)) } if last { operations.(map[string]interface{})[idx] = upload @@ -573,7 +573,7 @@ func addUploadToOperations(operations interface{}, upload graphql.Upload, path s } case int: if operations == nil { - operations = map[string]interface{}{} + return errors.New(fmt.Sprintf("variables is missing, path: %s", path)) } if last { operations.([]interface{})[idx] = upload diff --git a/handler/graphql_test.go b/handler/graphql_test.go index 73f5f66c755..7fd3a30e00f 100644 --- a/handler/graphql_test.go +++ b/handler/graphql_test.go @@ -7,6 +7,7 @@ import ( "mime/multipart" "net/http" "net/http/httptest" + "os" "strings" "testing" @@ -251,7 +252,7 @@ func TestProcessMultipart(t *testing.T) { }, } - t.Run("parse multipart form failure", func(t *testing.T) { + t.Run("fail to parse multipart", func(t *testing.T) { req := &http.Request{ Method: "POST", Header: http.Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}}, @@ -294,7 +295,7 @@ func TestProcessMultipart(t *testing.T) { require.Equal(t, err.Error(), "failed to get key 0 from form") }) - t.Run("fail if map entry with two values", func(t *testing.T) { + t.Run("fail map entry with two values", func(t *testing.T) { mapData := `{ "0": ["variables.file", "variables.file"] }` req := createUploadRequest(t, validOperations, mapData, validFiles) @@ -304,7 +305,7 @@ func TestProcessMultipart(t *testing.T) { require.Equal(t, err.Error(), "invalid value for key 0") }) - t.Run("fail if map entry with invalid prefix", func(t *testing.T) { + t.Run("fail map entry with invalid prefix", func(t *testing.T) { mapData := `{ "0": ["var.file"] }` req := createUploadRequest(t, validOperations, mapData, validFiles) @@ -335,6 +336,85 @@ func TestProcessMultipart(t *testing.T) { }) } +func TestAddUploadToOperations(t *testing.T) { + + t.Run("fail missing all variables", func(t *testing.T) { + file, err := os.Open("path/to/file") + var operations map[string]interface{} + upload := graphql.Upload{ + File: file, + Filename: "a.txt", + Size: int64(5), + } + path := "variables.req.0.file" + err = addUploadToOperations(operations, upload, path) + require.NotNil(t, err) + require.Equal(t, "variables is missing, path: variables.req.0.file", err.Error()) + }) + + t.Run("valid variable", func(t *testing.T) { + file, err := os.Open("path/to/file") + operations := map[string]interface{}{ + "variables": map[string]interface{}{ + "file": nil, + }, + } + + upload := graphql.Upload{ + File: file, + Filename: "a.txt", + Size: int64(5), + } + + expected := map[string]interface{}{ + "variables": map[string]interface{}{ + "file": upload, + }, + } + + path := "variables.file" + err = addUploadToOperations(operations, upload, path) + require.Nil(t, err) + + require.Equal(t, operations, expected) + }) + + t.Run("valid nested variable", func(t *testing.T) { + file, err := os.Open("path/to/file") + operations := map[string]interface{}{ + "variables": map[string]interface{}{ + "req": []interface{}{ + map[string]interface{}{ + "file": nil, + }, + }, + }, + } + + upload := graphql.Upload{ + File: file, + Filename: "a.txt", + Size: int64(5), + } + + expected := map[string]interface{}{ + "variables": map[string]interface{}{ + "req": []interface{}{ + map[string]interface{}{ + "file": upload, + }, + }, + }, + } + + path := "variables.req.0.file" + err = addUploadToOperations(operations, upload, path) + require.Nil(t, err) + + require.Equal(t, operations, expected) + }) +} + func TestHandlerOptions(t *testing.T) { h := GraphQL(&executableSchemaStub{}) @@ -382,35 +462,6 @@ func createUploadRequest(t *testing.T, operations, mapData string, files []file) return req } -func createInvalidUploadRequest(t *testing.T, operations, mapData string, files []file) *http.Request { - bodyBuf := &bytes.Buffer{} - bodyWriter := multipart.NewWriter(bodyBuf) - - err := bodyWriter.WriteField("invalidFormParameter", "") - require.NoError(t, err) - - err = bodyWriter.WriteField("operations", operations) - require.NoError(t, err) - - err = bodyWriter.WriteField("map", mapData) - require.NoError(t, err) - - for i := range files { - ff, err := bodyWriter.CreateFormFile(files[i].mapKey, files[i].name) - require.NoError(t, err) - _, err = ff.Write([]byte(files[i].content)) - require.NoError(t, err) - } - err = bodyWriter.Close() - require.NoError(t, err) - - req, err := http.NewRequest("POST", "/graphql", bodyBuf) - require.NoError(t, err) - - req.Header.Set("Content-Type", bodyWriter.FormDataContentType()) - return req -} - func doRequest(handler http.Handler, method string, target string, body string) *httptest.ResponseRecorder { r := httptest.NewRequest(method, target, strings.NewReader(body)) w := httptest.NewRecorder()