Skip to content

Commit 26703a8

Browse files
committed
Refactor MarshalMultipartRequest to handle file contents as byte slices
1 parent ac01d37 commit 26703a8

File tree

4 files changed

+67
-58
lines changed

4 files changed

+67
-58
lines changed

apiintegrations/apihandler/apihandler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type APIHandler interface {
1414
ConstructAPIResourceEndpoint(endpointPath string, log logger.Logger) string
1515
ConstructAPIAuthEndpoint(endpointPath string, log logger.Logger) string
1616
MarshalRequest(body interface{}, method string, endpoint string, log logger.Logger) ([]byte, error)
17-
MarshalMultipartRequest(fields map[string]string, files map[string]string, log logger.Logger) ([]byte, string, error)
17+
MarshalMultipartRequest(formFields map[string]string, fileContents map[string][]byte, log *zap.Logger) ([]byte, string, string, error)
1818
GetContentTypeHeader(method string, log logger.Logger) string
1919
GetAcceptHeader() string
2020
GetDefaultBaseDomain() string

apiintegrations/jamfpro/jamfpro_api_request.go

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@ import (
55
"bytes"
66
"encoding/json"
77
"encoding/xml"
8-
"io"
98
"mime/multipart"
10-
"path/filepath"
119
"strings"
1210

13-
"github.com/deploymenttheory/go-api-http-client/helpers"
1411
"github.com/deploymenttheory/go-api-http-client/logger"
1512
"go.uber.org/zap"
1613
)
@@ -57,42 +54,49 @@ func (j *JamfAPIHandler) MarshalRequest(body interface{}, method string, endpoin
5754
}
5855

5956
// MarshalMultipartRequest handles multipart form data encoding with secure file handling and returns the encoded body and content type.
60-
func (j *JamfAPIHandler) MarshalMultipartRequest(fields map[string]string, files map[string]string, log logger.Logger) ([]byte, string, error) {
61-
body := &bytes.Buffer{}
62-
writer := multipart.NewWriter(body)
63-
64-
// Add the simple fields to the form data
65-
for field, value := range fields {
66-
if err := writer.WriteField(field, value); err != nil {
67-
return nil, "", err
57+
func (j *JamfAPIHandler) MarshalMultipartRequest(formFields map[string]string, fileContents map[string][]byte, log *zap.Logger) ([]byte, string, string, error) {
58+
const snippetLength = 20
59+
var b bytes.Buffer
60+
writer := multipart.NewWriter(&b)
61+
62+
// Log form fields
63+
for key, val := range formFields {
64+
err := writer.WriteField(key, val)
65+
if err != nil {
66+
log.Error("Failed to add form field to multipart request", zap.String("key", key), zap.Error(err))
67+
return nil, "", "", err
6868
}
69+
log.Debug("Added form field", zap.String("key", key), zap.String("value", val))
6970
}
7071

71-
// Add the files to the form data, using safeOpenFile to ensure secure file access
72-
for formField, filePath := range files {
73-
file, err := helpers.SafeOpenFile(filePath)
74-
if err != nil {
75-
log.Error("Failed to open file securely", zap.String("file", filePath), zap.Error(err))
76-
return nil, "", err
72+
// Log file contents snippets
73+
for key, val := range fileContents {
74+
contentSnippet := string(val)
75+
if len(contentSnippet) > snippetLength {
76+
contentSnippet = contentSnippet[:snippetLength] + "..."
7777
}
78-
defer file.Close()
78+
log.Debug("File content snippet", zap.String("key", key), zap.String("snippet", contentSnippet))
7979

80-
part, err := writer.CreateFormFile(formField, filepath.Base(filePath))
80+
part, err := writer.CreateFormFile(key, key)
8181
if err != nil {
82-
return nil, "", err
82+
log.Error("Failed to create form file in multipart request", zap.String("key", key), zap.Error(err))
83+
return nil, "", "", err
8384
}
84-
if _, err := io.Copy(part, file); err != nil {
85-
return nil, "", err
85+
_, err = part.Write(val)
86+
if err != nil {
87+
log.Error("Failed to write file to multipart request", zap.String("key", key), zap.Error(err))
88+
return nil, "", "", err
8689
}
8790
}
8891

89-
// Close the writer to finish writing the multipart message
90-
if err := writer.Close(); err != nil {
91-
return nil, "", err
92+
// Close the writer
93+
err := writer.Close()
94+
if err != nil {
95+
log.Error("Failed to close multipart writer", zap.Error(err))
96+
return nil, "", "", err
9297
}
9398

94-
contentType := writer.FormDataContentType()
95-
log.Debug("Multipart request body", zap.String("Body", body.String())) // Log the body
99+
log.Debug("Multipart request constructed", zap.Any("formFields", formFields))
96100

97-
return body.Bytes(), contentType, nil
101+
return b.Bytes(), writer.FormDataContentType(), b.String()[:snippetLength], nil
98102
}

apiintegrations/msgraph/msgraph_api_request.go

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@ package msgraph
44
import (
55
"bytes"
66
"encoding/json"
7-
"io"
87
"mime/multipart"
9-
"path/filepath"
108

11-
"github.com/deploymenttheory/go-api-http-client/helpers"
129
"github.com/deploymenttheory/go-api-http-client/logger"
1310
"go.uber.org/zap"
1411
)
@@ -31,41 +28,49 @@ func (g *GraphAPIHandler) MarshalRequest(body interface{}, method string, endpoi
3128
}
3229

3330
// MarshalMultipartRequest handles multipart form data encoding with secure file handling and returns the encoded body and content type.
34-
func (g *GraphAPIHandler) MarshalMultipartRequest(fields map[string]string, files map[string]string, log logger.Logger) ([]byte, string, error) {
31+
func (g *GraphAPIHandler) MarshalMultipartRequest(formFields map[string]string, fileContents map[string][]byte, log *zap.Logger) ([]byte, string, string, error) {
32+
const snippetLength = 20
33+
var b bytes.Buffer
34+
writer := multipart.NewWriter(&b)
3535

36-
body := &bytes.Buffer{}
37-
writer := multipart.NewWriter(body)
38-
39-
// Add the simple fields to the form data
40-
for field, value := range fields {
41-
if err := writer.WriteField(field, value); err != nil {
42-
return nil, "", err
36+
// Log form fields
37+
for key, val := range formFields {
38+
err := writer.WriteField(key, val)
39+
if err != nil {
40+
log.Error("Failed to add form field to multipart request", zap.String("key", key), zap.Error(err))
41+
return nil, "", "", err
4342
}
43+
log.Debug("Added form field", zap.String("key", key), zap.String("value", val))
4444
}
4545

46-
// Add the files to the form data, using safeOpenFile to ensure secure file access
47-
for formField, filePath := range files {
48-
file, err := helpers.SafeOpenFile(filePath)
49-
if err != nil {
50-
log.Error("Failed to open file securely", zap.String("file", filePath), zap.Error(err))
51-
return nil, "", err
46+
// Log file contents snippets
47+
for key, val := range fileContents {
48+
contentSnippet := string(val)
49+
if len(contentSnippet) > snippetLength {
50+
contentSnippet = contentSnippet[:snippetLength] + "..."
5251
}
53-
defer file.Close()
52+
log.Debug("File content snippet", zap.String("key", key), zap.String("snippet", contentSnippet))
5453

55-
part, err := writer.CreateFormFile(formField, filepath.Base(filePath))
54+
part, err := writer.CreateFormFile(key, key)
5655
if err != nil {
57-
return nil, "", err
56+
log.Error("Failed to create form file in multipart request", zap.String("key", key), zap.Error(err))
57+
return nil, "", "", err
5858
}
59-
if _, err := io.Copy(part, file); err != nil {
60-
return nil, "", err
59+
_, err = part.Write(val)
60+
if err != nil {
61+
log.Error("Failed to write file to multipart request", zap.String("key", key), zap.Error(err))
62+
return nil, "", "", err
6163
}
6264
}
6365

64-
// Close the writer to finish writing the multipart message
65-
contentType := writer.FormDataContentType()
66-
if err := writer.Close(); err != nil {
67-
return nil, "", err
66+
// Close the writer
67+
err := writer.Close()
68+
if err != nil {
69+
log.Error("Failed to close multipart writer", zap.Error(err))
70+
return nil, "", "", err
6871
}
6972

70-
return body.Bytes(), contentType, nil
73+
log.Debug("Multipart request constructed", zap.Any("formFields", formFields))
74+
75+
return b.Bytes(), writer.FormDataContentType(), b.String()[:snippetLength], nil
7176
}

httpclient/multipartrequest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
// - method: The HTTP method to use (e.g., POST, PUT).
2020
// - endpoint: The API endpoint to which the request will be sent.
2121
// - fields: A map of form fields and their values to include in the multipart message.
22-
// - files: A map of file field names to file paths that will be included as file attachments.
22+
// - files: A map of file field names to file content that will be included as file attachments (as byte slices).
2323
// - out: A pointer to a variable where the unmarshaled response will be stored.
2424
//
2525
// Returns:
@@ -38,7 +38,7 @@ import (
3838
//
3939
// Note:
4040
// The caller should handle closing the response body when successful.
41-
func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]string, files map[string]string, out interface{}) (*http.Response, error) {
41+
func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]string, files map[string][]byte, out interface{}) (*http.Response, error) {
4242
log := c.Logger
4343

4444
// Auth Token validation check

0 commit comments

Comments
 (0)