diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2025-04-10 15:09:06 +0200 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2025-04-11 10:07:50 +0000 |
| commit | 4d9e57eb150fee8d24ff32fb4a8a414c77d246e6 (patch) | |
| tree | 9214e0b17c3aa833b9f812b52c5ecf7b28b4d741 /syz-cluster/pkg/api | |
| parent | dfb5be349af98db984a0944f49896f454e4bc8a6 (diff) | |
syz-cluster: provide API for uploading artifacts archive
The archive would be a useful source of debugging information.
Provide an HTTP endpoint that accepts a multipart form request with
the archived data.
Provide an *api.Client method to encapsulate the encoding of the data.
Add a test.
Diffstat (limited to 'syz-cluster/pkg/api')
| -rw-r--r-- | syz-cluster/pkg/api/client.go | 11 | ||||
| -rw-r--r-- | syz-cluster/pkg/api/http.go | 24 |
2 files changed, 35 insertions, 0 deletions
diff --git a/syz-cluster/pkg/api/client.go b/syz-cluster/pkg/api/client.go index d0509cfe0..787748e51 100644 --- a/syz-cluster/pkg/api/client.go +++ b/syz-cluster/pkg/api/client.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net/http" + "net/url" "strings" "time" ) @@ -75,6 +76,16 @@ func (client Client) UploadTestResult(ctx context.Context, req *TestResult) erro return err } +func (client Client) UploadTestArtifacts(ctx context.Context, sessionID, testName string, + tarGzContent io.Reader) error { + v := url.Values{} + v.Add("session", sessionID) + v.Add("test", testName) + url := client.baseURL + "/tests/upload_artifacts?" + v.Encode() + _, err := postMultiPartFile[any](ctx, url, tarGzContent) + return err +} + func (client Client) UploadFinding(ctx context.Context, req *NewFinding) error { _, err := postJSON[NewFinding, any](ctx, client.baseURL+"/findings/upload", req) return err diff --git a/syz-cluster/pkg/api/http.go b/syz-cluster/pkg/api/http.go index 420b787a7..4523b5374 100644 --- a/syz-cluster/pkg/api/http.go +++ b/syz-cluster/pkg/api/http.go @@ -7,7 +7,9 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" + "mime/multipart" "net/http" ) @@ -32,6 +34,28 @@ func postJSON[Req any, Resp any](ctx context.Context, url string, req *Req) (*Re return finishRequest[Resp](httpReq) } +func postMultiPartFile[Resp any](ctx context.Context, url string, reader io.Reader) (*Resp, error) { + // TODO: this will work well only up to some size of the file. We need a pipe and a goroutine. + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile("content", "content") + if err != nil { + return nil, fmt.Errorf("failed to create a form file part: %w", err) + } + if _, err := io.Copy(part, reader); err != nil { + return nil, err + } + if err := writer.Close(); err != nil { + return nil, err + } + httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body) + if err != nil { + return nil, err + } + httpReq.Header.Set("Content-Type", writer.FormDataContentType()) + return finishRequest[Resp](httpReq) +} + func ReplyJSON[T any](w http.ResponseWriter, resp T) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(resp) |
