From baf5db0da16fe9eac204eb6665b45b3c1b2d9725 Mon Sep 17 00:00:00 2001 From: ShocOne <62835948+ShocOne@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:53:17 +0100 Subject: [PATCH] chore: experimenting with using a streaming technique rather than a block request --- httpclient/multipartrequest.go | 41 ++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/httpclient/multipartrequest.go b/httpclient/multipartrequest.go index 2954d46..96029e2 100644 --- a/httpclient/multipartrequest.go +++ b/httpclient/multipartrequest.go @@ -85,12 +85,18 @@ func (c *Client) DoMultiPartRequest(method, endpoint string, files map[string][] log.Debug("Executing multipart request", zap.String("method", method), zap.String("endpoint", endpoint)) - body, contentType, err := createMultipartRequestBody(files, formDataFields, fileContentTypes, formDataPartHeaders, log) + // body, contentType, err := createMultipartRequestBody(files, formDataFields, fileContentTypes, formDataPartHeaders, log) + // if err != nil { + // return nil, err + // } + + // Call the helper function to create a streaming multipart request body + body, contentType, err := createStreamingMultipartRequestBody(files, formDataFields, fileContentTypes, formDataPartHeaders, log) if err != nil { return nil, err } - logMultiPartRequestBody(body, log) + //logMultiPartRequestBody(body, log) url := c.APIHandler.ConstructAPIResourceEndpoint(endpoint, log) @@ -130,6 +136,37 @@ func (c *Client) DoMultiPartRequest(method, endpoint string, files map[string][] return resp, response.HandleAPIErrorResponse(resp, log) } +// createStreamingMultipartRequestBody creates a streaming multipart request body with the provided files and form fields. +// This function constructs the body of a multipart/form-data request using an io.Pipe, allowing the request to be sent in chunks. + +func createStreamingMultipartRequestBody(files map[string][]string, formDataFields map[string]string, fileContentTypes map[string]string, formDataPartHeaders map[string]http.Header, log logger.Logger) (io.Reader, string, error) { + pr, pw := io.Pipe() + writer := multipart.NewWriter(pw) + + go func() { + defer pw.Close() + defer writer.Close() + + for fieldName, filePaths := range files { + for _, filePath := range filePaths { + if err := addFilePart(writer, fieldName, filePath, fileContentTypes, formDataPartHeaders, log); err != nil { + pw.CloseWithError(err) + return + } + } + } + + for key, val := range formDataFields { + if err := addFormField(writer, key, val, log); err != nil { + pw.CloseWithError(err) + return + } + } + }() + + return pr, writer.FormDataContentType(), nil +} + // createMultipartRequestBody creates a multipart request body with the provided files and form fields, supporting custom content types and headers. // This function constructs the body of a multipart/form-data request by adding each file and form field to the multipart writer, // setting custom content types and headers for each part as specified.