aboutsummaryrefslogtreecommitdiff
path: root/lib/http
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2024-02-15 02:28:30 +0700
committerShulhan <ms@kilabit.info>2024-02-15 02:28:30 +0700
commit6ef5bdfc203a5d5e3648c59edd158db51ee289c0 (patch)
tree3352b1740abe5a5c6c6177e5c2b6fc758564bd7b /lib/http
parent48e6dced72d470d78c8f58f4dc703528eb092c3c (diff)
downloadpakakeh.go-6ef5bdfc203a5d5e3648c59edd158db51ee289c0.tar.xz
lib/http: export function to generate "multipart/form-data"
The GenerateFormData generate the request body with boundary for HTTP content-type "multipart/form-data" from map[string][]byte.
Diffstat (limited to 'lib/http')
-rw-r--r--lib/http/client.go24
-rw-r--r--lib/http/client_example_test.go47
-rw-r--r--lib/http/client_request.go2
3 files changed, 65 insertions, 8 deletions
diff --git a/lib/http/client.go b/lib/http/client.go
index 05368092..cdfb1979 100644
--- a/lib/http/client.go
+++ b/lib/http/client.go
@@ -21,6 +21,7 @@ import (
"net/http"
"net/url"
"path"
+ "sort"
"strings"
"time"
@@ -243,7 +244,7 @@ func (client *Client) GenerateHttpRequest(
case RequestTypeMultipartForm:
paramsAsMultipart, ok := params.(map[string][]byte)
if ok {
- contentType, strBody, err = generateFormData(paramsAsMultipart)
+ contentType, strBody, err = GenerateFormData(paramsAsMultipart)
if err != nil {
return nil, fmt.Errorf("%s: %w", logp, err)
}
@@ -336,7 +337,7 @@ func (client *Client) PostFormData(
) (
res *http.Response, resBody []byte, err error,
) {
- contentType, strBody, err := generateFormData(params)
+ contentType, strBody, err := GenerateFormData(params)
if err != nil {
return nil, nil, fmt.Errorf("http: PostFormData: %w", err)
}
@@ -393,7 +394,7 @@ func (client *Client) PutFormData(rpath string, hdr http.Header, params map[stri
body *strings.Reader
)
- contentType, strBody, err = generateFormData(params)
+ contentType, strBody, err = GenerateFormData(params)
if err != nil {
return nil, nil, fmt.Errorf(`http: PutFormData: %w`, err)
}
@@ -540,21 +541,30 @@ func (client *Client) uncompress(res *http.Response, body []byte) (
return out, err
}
-// generateFormData generate multipart/form-data body from params.
-func generateFormData(params map[string][]byte) (contentType, body string, err error) {
+// GenerateFormData generate multipart/form-data body from params.
+func GenerateFormData(params map[string][]byte) (contentType, body string, err error) {
var (
sb = new(strings.Builder)
w = multipart.NewWriter(sb)
+ k string
+ listKey []string
+ )
+ for k = range params {
+ listKey = append(listKey, k)
+ }
+ sort.Strings(listKey)
+
+ var (
part io.Writer
- k string
v []byte
)
- for k, v = range params {
+ for _, k = range listKey {
part, err = w.CreateFormField(k)
if err != nil {
return "", "", err
}
+ v = params[k]
_, err = part.Write(v)
if err != nil {
return "", "", err
diff --git a/lib/http/client_example_test.go b/lib/http/client_example_test.go
new file mode 100644
index 00000000..2d7d3bdf
--- /dev/null
+++ b/lib/http/client_example_test.go
@@ -0,0 +1,47 @@
+package http_test
+
+import (
+ "crypto/rand"
+ "fmt"
+ "log"
+ "strings"
+
+ libhttp "github.com/shuLhan/share/lib/http"
+ "github.com/shuLhan/share/lib/test/mock"
+)
+
+func ExampleGenerateFormData() {
+ // Mock the random reader for predictable output.
+ // NOTE: do not do this on real code.
+ rand.Reader = mock.NewRandReader([]byte(`randomseed`))
+
+ var data = map[string][]byte{
+ `name`: []byte(`test.txt`),
+ `size`: []byte(`42`),
+ }
+
+ var (
+ contentType string
+ body string
+ err error
+ )
+ contentType, body, err = libhttp.GenerateFormData(data)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Println(`contentType:`, contentType)
+ fmt.Println(`body:`)
+ fmt.Println(strings.ReplaceAll(body, "\r\n", "\n"))
+ // Output:
+ // contentType: multipart/form-data; boundary=72616e646f6d7365656472616e646f6d7365656472616e646f6d73656564
+ // body:
+ // --72616e646f6d7365656472616e646f6d7365656472616e646f6d73656564
+ // Content-Disposition: form-data; name="name"
+ //
+ // test.txt
+ // --72616e646f6d7365656472616e646f6d7365656472616e646f6d73656564
+ // Content-Disposition: form-data; name="size"
+ //
+ // 42
+ // --72616e646f6d7365656472616e646f6d7365656472616e646f6d73656564--
+}
diff --git a/lib/http/client_request.go b/lib/http/client_request.go
index 03496e45..635c88da 100644
--- a/lib/http/client_request.go
+++ b/lib/http/client_request.go
@@ -113,7 +113,7 @@ func (creq *ClientRequest) toHTTPRequest(client *Client) (httpReq *http.Request,
case RequestTypeMultipartForm:
paramsAsMultipart, ok := creq.Params.(map[string][]byte)
if ok {
- contentType, strBody, err = generateFormData(paramsAsMultipart)
+ contentType, strBody, err = GenerateFormData(paramsAsMultipart)
if err != nil {
return nil, fmt.Errorf("%s: %w", logp, err)
}