From 19ec2e3a81d03f28d5cd98b86330d04422e80109 Mon Sep 17 00:00:00 2001 From: Daichi Ueura Date: Sat, 23 Sep 2023 14:52:39 +0900 Subject: [PATCH] Support application/octet-stream via http --- http.go | 29 ++++++++++++++++++++++++++++- http_test.go | 17 +++++++++++++++++ testdata/book/http.yml | 10 ++++++++++ testdata/http.yml.debugger.golden | Bin 6156 -> 7346 bytes testdata/http.yml.runbook.golden | 28 ++++++++++++++++++++++++++++ testdata/openapi3.yml | 4 ++++ yaml.go | 1 + 7 files changed, 88 insertions(+), 1 deletion(-) diff --git a/http.go b/http.go index a127b172..fc24d1df 100644 --- a/http.go +++ b/http.go @@ -29,6 +29,7 @@ const ( MediaTypeTextPlain = "text/plain" MediaTypeApplicationFormUrlencoded = "application/x-www-form-urlencoded" MediaTypeMultipartFormData = "multipart/form-data" + MediaTypeApplicationOctetStream = "application/octet-stream" ) const ( @@ -111,7 +112,7 @@ func (r *httpRequest) validate() error { return nil } switch r.mediaType { - case MediaTypeApplicationJSON, MediaTypeTextPlain, MediaTypeApplicationFormUrlencoded, "": + case MediaTypeApplicationJSON, MediaTypeTextPlain, MediaTypeApplicationFormUrlencoded, MediaTypeApplicationOctetStream, "": default: return fmt.Errorf("unsupported mediaType: %s", r.mediaType) } @@ -142,6 +143,32 @@ func (r *httpRequest) encodeBody() (io.Reader, error) { return nil, err } return buf, nil + case MediaTypeApplicationOctetStream: + switch v := r.body.(type) { + case map[string]any: + vv, ok := v["filename"] + if !ok { + return nil, fmt.Errorf("invalid body: %v", r.body) + } + fileName, ok := vv.(string) + if !ok { + return nil, fmt.Errorf("invalid body: %v", r.body) + } + b, err := readFile(filepath.Join(r.root, fileName)) + if err != nil { + return nil, err + } + return bytes.NewBuffer(b), nil + case string: + s, ok := r.body.(string) + if !ok { + return nil, fmt.Errorf("invalid body: %v", r.body) + } + return strings.NewReader(s), nil + case []byte: + return bytes.NewBuffer(r.body.([]byte)), nil + } + return nil, fmt.Errorf("invalid body: %v", r.body) case MediaTypeTextPlain: s, ok := r.body.(string) if !ok { diff --git a/http_test.go b/http_test.go index e3686158..5090782f 100644 --- a/http_test.go +++ b/http_test.go @@ -100,6 +100,11 @@ func TestHTTPRunnerRunUsingGitHubAPI(t *testing.T) { } func TestRequestBody(t *testing.T) { + dummy, err := os.ReadFile("testdata/dummy.png") + if err != nil { + t.Fatal(err) + } + tests := []struct { in string mediaType string @@ -133,6 +138,18 @@ two: ni`, MediaTypeApplicationFormUrlencoded, `one=ichi&two=ni`, }, + { + ` +filename: testdata/dummy.png`, + MediaTypeApplicationOctetStream, + string(dummy), + }, + { + ` +!!binary QUJD`, + MediaTypeApplicationOctetStream, + `ABC`, + }, } for _, tt := range tests { diff --git a/testdata/book/http.yml b/testdata/book/http.yml index 408a3d44..72343d73 100644 --- a/testdata/book/http.yml +++ b/testdata/book/http.yml @@ -95,6 +95,16 @@ steps: upload0: ../dummy.png test: | current.res.status == 201 + dataupload: + desc: Post /upload with octet-stream + req: + /upload: + post: + body: + application/octet-stream: + filename: ../dummy.jpg + test: | + current.res.status == 201 severalvalues: desc: Get several values req: diff --git a/testdata/http.yml.debugger.golden b/testdata/http.yml.debugger.golden index 69dd3069b530b8b9d8738c2e48de983d752ec16b..360c770f554c0fff97c55fe5a371b44e468b03c4 100644 GIT binary patch delta 897 zcmeA%*krk3f!O49E{Dl>96a^;$t9^Jy2T|$sfoF~T)bTWZ~TA2AmHWZ>Bhjw$jFcY zgbe@xG1xf=xjKgU2U#hkr|4!Cq^2vB8R{7*Xp|Ob=A|omdbulj1-QB^lvx;P>L{e7 zrX`l&CY&d$ln!NnuO%frphBUvvb%r7DnI}gNkudQ4=SZ zn7D+bl&YG#hNhN@shPQjrIoXbtDC!rr&n-DXjpiCL}XMlFuc+;GP89XZ3R<7E#dCS&q+js2Tb?ESsqsNY)IC<*QuS~;l_iU%Emz-M3agxa*3&!JXHM%@*LQ2 zSiFYCXH6Jht0%^9aIYbJc8h_BnGqO)%z_N|3_t&MX)Itu!+i5Xwr0q`aXR2JX^}(v zBqli-nT;$w@?R_OPJ6ns$24_`RZiQ-o|IOm-O{1D{RYJicM5Mj-|zQ(x=|Oyz0JOs zB~Ro^mrVZIb-;ro_o+O?B!(LjYL&->Ds0kTIl5e|U-@~@#^;sRWqBu$nf=*co>zF^ b)US&{V-Y6)e{=FjG1tk`OwyZK#5kA$j#N0s delta 12 TcmdmF*<-L_f!Jm@=^RD?A|wQl diff --git a/testdata/http.yml.runbook.golden b/testdata/http.yml.runbook.golden index c675e482..76a55bca 100644 --- a/testdata/http.yml.runbook.golden +++ b/testdata/http.yml.runbook.golden @@ -105,6 +105,34 @@ steps: && current.res.headers["Content-Type"][0] == "text/html; charset=utf-8" && "Date" in current.res.headers && current.res.rawBody == "

Posted

" +- req: + /upload: + post: + body: + application/octet-stream: !!binary | + /9j/4AAQSkZJRgABAQEAYABgAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZy + BJSkcgSlBFRyB2ODApLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAIBgYHBgUIBwcHCQkICgwU + DQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQw + EJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy + MjIyMjIyMjIyMjIy/8AAEQgAKAA8AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAA + ABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQy + gZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWV + pjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrC + w8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQ + EAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEH + YXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSl + NUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKz + tLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQ + MRAD8A+f6KKKACiiigAooooAKKKKACiiigDp5UtWgf7ELASJKiQGeSAh4cHLEEDB/1ed2W + 5bGMNWWkOmyG8YyFArsbVS2PMHOA3HHY579O+5cyigDes005dOQedaST+YrASAht5R8Akg + DYGCZ5x1J4PGbqQUTRf6nzvLHneTt2bsnGNvy/d25x3zVOigAooooAKKKKACiiigAooooA + KKKKAP/Z + test: | + current.res.status == 201 + && current.res.headers["Content-Length"][0] == "15" + && current.res.headers["Content-Type"][0] == "text/html; charset=utf-8" + && "Date" in current.res.headers + && current.res.rawBody == "

Posted

" - req: /ping: get: diff --git a/testdata/openapi3.yml b/testdata/openapi3.yml index 2276e24e..c20f6c49 100644 --- a/testdata/openapi3.yml +++ b/testdata/openapi3.yml @@ -101,6 +101,10 @@ paths: post: requestBody: content: + application/octet-stream: + schema: + type: string + format: binary multipart/form-data: schema: type: object diff --git a/yaml.go b/yaml.go index 1b299528..05e3c45c 100644 --- a/yaml.go +++ b/yaml.go @@ -140,6 +140,7 @@ func CreateHTTPStepMapSlice(key string, req *http.Request) (yaml.MapSlice, error } default: // case contentType == runn.MediaTypeTextPlain: + // case contentType == runn.MediaTypeApplicationOctetStream b, err := io.ReadAll(save) if err != nil { return nil, fmt.Errorf("failed to io.ReadAll: %w", err)