Skip to content

Commit 778ea08

Browse files
authored
Merge pull request #234 from deploymenttheory/dev-multipartfix
Dev multipartfix
2 parents 961b316 + 959e29f commit 778ea08

File tree

1 file changed

+43
-24
lines changed

1 file changed

+43
-24
lines changed

httpclient/multipartrequestwithretry.go

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -93,36 +93,36 @@ func (c *Client) DoMultiPartRequest(method, endpoint string, files map[string][]
9393

9494
url := c.APIHandler.ConstructAPIResourceEndpoint(endpoint, log)
9595

96-
var resp *http.Response
97-
var requestErr error
96+
// Create a context with timeout based on the custom timeout duration
97+
ctx, cancel := context.WithTimeout(context.Background(), c.clientConfig.ClientOptions.Timeout.CustomTimeout.Duration())
98+
defer cancel()
9899

99-
// Retry logic
100-
maxRetries := 3
101-
for attempt := 1; attempt <= maxRetries; attempt++ {
102-
// Create a context with timeout based on the custom timeout duration
103-
ctx, cancel := context.WithTimeout(context.Background(), c.clientConfig.ClientOptions.Timeout.CustomTimeout.Duration())
104-
defer cancel()
100+
body, contentType, err := createStreamingMultipartRequestBody(files, formDataFields, fileContentTypes, formDataPartHeaders, log)
101+
if err != nil {
102+
log.Error("Failed to create streaming multipart request body", zap.Error(err))
103+
return nil, err
104+
}
105105

106-
body, contentType, err := createStreamingMultipartRequestBody(files, formDataFields, fileContentTypes, formDataPartHeaders, log)
107-
if err != nil {
108-
log.Error("Failed to create streaming multipart request body", zap.Error(err))
109-
return nil, err
110-
}
106+
req, err := http.NewRequestWithContext(ctx, method, url, body)
107+
if err != nil {
108+
log.Error("Failed to create HTTP request", zap.Error(err))
109+
return nil, err
110+
}
111111

112-
req, err := http.NewRequestWithContext(ctx, method, url, body)
113-
if err != nil {
114-
log.Error("Failed to create HTTP request", zap.Error(err))
115-
return nil, err
116-
}
112+
cookiejar.ApplyCustomCookies(req, c.clientConfig.ClientOptions.Cookies.CustomCookies, c.Logger)
117113

118-
cookiejar.ApplyCustomCookies(req, c.clientConfig.ClientOptions.Cookies.CustomCookies, c.Logger)
114+
req.Header.Set("Content-Type", contentType)
119115

120-
req.Header.Set("Content-Type", contentType)
116+
headerHandler := headers.NewHeaderHandler(req, c.Logger, c.APIHandler, c.AuthTokenHandler)
117+
headerHandler.SetRequestHeaders(endpoint)
118+
headerHandler.LogHeaders(c.clientConfig.ClientOptions.Logging.HideSensitiveData)
121119

122-
headerHandler := headers.NewHeaderHandler(req, c.Logger, c.APIHandler, c.AuthTokenHandler)
123-
headerHandler.SetRequestHeaders(endpoint)
124-
headerHandler.LogHeaders(c.clientConfig.ClientOptions.Logging.HideSensitiveData)
120+
var resp *http.Response
121+
var requestErr error
125122

123+
// Retry logic
124+
maxRetries := 3
125+
for attempt := 1; attempt <= maxRetries; attempt++ {
126126
startTime := time.Now()
127127

128128
resp, requestErr = c.httpClient.Do(req)
@@ -159,7 +159,26 @@ func (c *Client) DoMultiPartRequest(method, endpoint string, files map[string][]
159159

160160
// createStreamingMultipartRequestBody creates a streaming multipart request body with the provided files and form fields.
161161
// This function constructs the body of a multipart/form-data request using an io.Pipe, allowing the request to be sent in chunks.
162-
// createStreamingMultipartRequestBody creates a streaming multipart request body with the provided files and form fields.
162+
// It supports custom content types and headers for each part of the multipart request, and logs the process for debugging
163+
// and monitoring purposes.
164+
165+
// Parameters:
166+
// - files: A map where the key is the field name and the value is a slice of file paths to be included in the request.
167+
// Each file path corresponds to a file that will be included in the multipart request.
168+
// - formDataFields: A map of additional form fields to be included in the multipart request, where the key is the field name
169+
// and the value is the field value. These are regular form fields that accompany the file uploads.
170+
// - fileContentTypes: A map specifying the content type for each file part. The key is the field name and the value is the
171+
// content type (e.g., "image/jpeg").
172+
// - formDataPartHeaders: A map specifying custom headers for each part of the multipart form data. The key is the field name
173+
// and the value is an http.Header containing the headers for that part.
174+
// - log: An instance of a logger implementing the logger.Logger interface, used to log informational messages, warnings,
175+
// and errors encountered during the construction of the multipart request body.
176+
177+
// Returns:
178+
// - io.Reader: The constructed multipart request body reader. This reader streams the multipart form data payload ready to be sent.
179+
// - string: The content type of the multipart request body. This includes the boundary string used by the multipart writer.
180+
// - error: An error object indicating failure during the construction of the multipart request body. This could be due to issues
181+
// such as file reading errors or multipart writer errors.
163182
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) {
164183
pr, pw := io.Pipe()
165184
writer := multipart.NewWriter(pw)

0 commit comments

Comments
 (0)