summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2022-10-28 10:42:16 +0700
committerShulhan <ms@kilabit.info>2022-10-28 11:10:29 +0700
commit542a11bc463dfaea70ba95fd089b4e1c820f2b38 (patch)
tree5be7377ee3ef79e8b2856fc62a2e6d69f9adc109
parent8080dad8f616f5e82a4967de449a97423245cfc2 (diff)
downloadpakakeh.go-542a11bc463dfaea70ba95fd089b4e1c820f2b38.tar.xz
lib/http: sanitize ServerUrl and request path
This is to fix double slash in case the ServerUrl end with it and the request path begin with it. For example, "http://127.0.0.1/" and "/" should send request to "http://127.0.0.1/" not "http://127.0.0.1//".
-rw-r--r--lib/http/client.go53
-rw-r--r--lib/http/client_options.go2
-rw-r--r--lib/http/endpoint_example_test.go11
3 files changed, 39 insertions, 27 deletions
diff --git a/lib/http/client.go b/lib/http/client.go
index 4fc51c68..477d506e 100644
--- a/lib/http/client.go
+++ b/lib/http/client.go
@@ -21,6 +21,7 @@ import (
"net/http"
"net/http/httputil"
"net/url"
+ "path"
"strings"
"time"
@@ -81,14 +82,14 @@ func NewClient(opts *ClientOptions) (client *Client) {
// Delete send the DELETE request to server using path and params as query
// parameters.
// On success, it will return the uncompressed response body.
-func (client *Client) Delete(path string, headers http.Header, params url.Values) (
+func (client *Client) Delete(requestPath string, headers http.Header, params url.Values) (
httpRes *http.Response, resBody []byte, err error,
) {
if params != nil {
- path += "?" + params.Encode()
+ requestPath += `?` + params.Encode()
}
- return client.doRequest(http.MethodDelete, headers, path, "", nil)
+ return client.doRequest(http.MethodDelete, headers, requestPath, ``, nil)
}
// Do overwrite the standard http Client.Do to allow debugging request and
@@ -216,7 +217,7 @@ out:
// be encoded as JSON in body.
func (client *Client) GenerateHttpRequest(
method RequestMethod,
- path string,
+ requestPath string,
requestType RequestType,
headers http.Header,
params interface{},
@@ -242,7 +243,7 @@ func (client *Client) GenerateHttpRequest(
RequestMethodTrace:
if isParamsUrlValues {
- path += "?" + paramsAsUrlValues.Encode()
+ requestPath += `?` + paramsAsUrlValues.Encode()
}
case RequestMethodPatch,
@@ -251,7 +252,7 @@ func (client *Client) GenerateHttpRequest(
switch requestType {
case RequestTypeQuery:
if isParamsUrlValues {
- path += "?" + paramsAsUrlValues.Encode()
+ requestPath += `?` + paramsAsUrlValues.Encode()
}
case RequestTypeForm:
@@ -282,7 +283,8 @@ func (client *Client) GenerateHttpRequest(
}
}
- fullURL := client.opts.ServerUrl + path
+ requestPath = path.Join(`/`, requestPath)
+ fullURL := client.opts.ServerUrl + requestPath
httpRequest, err = http.NewRequest(method.String(), fullURL, body)
if err != nil {
@@ -302,42 +304,42 @@ func (client *Client) GenerateHttpRequest(
// Get send the GET request to server using path and params as query
// parameters.
// On success, it will return the uncompressed response body.
-func (client *Client) Get(path string, headers http.Header, params url.Values) (
+func (client *Client) Get(requestPath string, headers http.Header, params url.Values) (
httpRes *http.Response, resBody []byte, err error,
) {
if params != nil {
- path += "?" + params.Encode()
+ requestPath += `?` + params.Encode()
}
- return client.doRequest(http.MethodGet, headers, path, "", nil)
+ return client.doRequest(http.MethodGet, headers, requestPath, ``, nil)
}
// Post send the POST request to path without setting "Content-Type".
// If the params is not nil, it will send as query parameters in the path.
-func (client *Client) Post(path string, headers http.Header, params url.Values) (
+func (client *Client) Post(requestPath string, headers http.Header, params url.Values) (
httpRes *http.Response, resBody []byte, err error,
) {
if params != nil {
- path += "?" + params.Encode()
+ requestPath += `?` + params.Encode()
}
- return client.doRequest(http.MethodPost, headers, path, "", nil)
+ return client.doRequest(http.MethodPost, headers, requestPath, ``, nil)
}
// PostForm send the POST request to path using
// "application/x-www-form-urlencoded".
-func (client *Client) PostForm(path string, headers http.Header, params url.Values) (
+func (client *Client) PostForm(requestPath string, headers http.Header, params url.Values) (
httpRes *http.Response, resBody []byte, err error,
) {
body := strings.NewReader(params.Encode())
- return client.doRequest(http.MethodPost, headers, path, ContentTypeForm, body)
+ return client.doRequest(http.MethodPost, headers, requestPath, ContentTypeForm, body)
}
// PostFormData send the POST request to path with all parameters is send
// using "multipart/form-data".
func (client *Client) PostFormData(
- path string,
+ requestPath string,
headers http.Header,
params map[string][]byte,
) (
@@ -350,12 +352,12 @@ func (client *Client) PostFormData(
body := strings.NewReader(strBody)
- return client.doRequest(http.MethodPost, headers, path, contentType, body)
+ return client.doRequest(http.MethodPost, headers, requestPath, contentType, body)
}
// PostJSON send the POST request with content type set to "application/json"
// and params encoded automatically to JSON.
-func (client *Client) PostJSON(path string, headers http.Header, params interface{}) (
+func (client *Client) PostJSON(requestPath string, headers http.Header, params interface{}) (
httpRes *http.Response, resBody []byte, err error,
) {
paramsJSON, err := json.Marshal(params)
@@ -365,21 +367,21 @@ func (client *Client) PostJSON(path string, headers http.Header, params interfac
body := bytes.NewReader(paramsJSON)
- return client.doRequest(http.MethodPost, headers, path, ContentTypeJSON, body)
+ return client.doRequest(http.MethodPost, headers, requestPath, ContentTypeJSON, body)
}
// Put send the HTTP PUT request with specific content type and body to
// specific path at the server.
-func (client *Client) Put(path string, headers http.Header, body []byte) (
+func (client *Client) Put(requestPath string, headers http.Header, body []byte) (
*http.Response, []byte, error,
) {
bodyReader := bytes.NewReader(body)
- return client.doRequest(http.MethodPut, headers, path, "", bodyReader)
+ return client.doRequest(http.MethodPut, headers, requestPath, ``, bodyReader)
}
// PutJSON send the PUT request with content type set to "application/json"
// and params encoded automatically to JSON.
-func (client *Client) PutJSON(path string, headers http.Header, params interface{}) (
+func (client *Client) PutJSON(requestPath string, headers http.Header, params interface{}) (
httpRes *http.Response, resBody []byte, err error,
) {
paramsJSON, err := json.Marshal(params)
@@ -389,18 +391,19 @@ func (client *Client) PutJSON(path string, headers http.Header, params interface
body := bytes.NewReader(paramsJSON)
- return client.doRequest(http.MethodPut, headers, path, ContentTypeJSON, body)
+ return client.doRequest(http.MethodPut, headers, requestPath, ContentTypeJSON, body)
}
func (client *Client) doRequest(
httpMethod string,
headers http.Header,
- path, contentType string,
+ requestPath, contentType string,
body io.Reader,
) (
httpRes *http.Response, resBody []byte, err error,
) {
- fullURL := client.opts.ServerUrl + path
+ requestPath = path.Join(`/`, requestPath)
+ fullURL := client.opts.ServerUrl + requestPath
httpReq, err := http.NewRequest(httpMethod, fullURL, body)
if err != nil {
diff --git a/lib/http/client_options.go b/lib/http/client_options.go
index 2357fd6d..d881ba12 100644
--- a/lib/http/client_options.go
+++ b/lib/http/client_options.go
@@ -2,6 +2,7 @@ package http
import (
"net/http"
+ "strings"
"time"
)
@@ -38,4 +39,5 @@ func (opts *ClientOptions) init() {
if opts.Timeout <= 0 {
opts.Timeout = defClientTimeout
}
+ opts.ServerUrl = strings.TrimSuffix(opts.ServerUrl, `/`)
}
diff --git a/lib/http/endpoint_example_test.go b/lib/http/endpoint_example_test.go
index e5e8238b..231421ce 100644
--- a/lib/http/endpoint_example_test.go
+++ b/lib/http/endpoint_example_test.go
@@ -6,6 +6,7 @@ package http
import (
"fmt"
+ "log"
"net/http"
"net/url"
"strconv"
@@ -58,11 +59,17 @@ func ExampleEndpoint_errorHandler() {
params := url.Values{}
params.Set("error", "400:error with status code")
- httpres, resbody, _ := client.Get("/", nil, params)
+ httpres, resbody, err := client.Get(`/`, nil, params)
+ if err != nil {
+ log.Fatal(err)
+ }
fmt.Printf("%d: %s\n", httpres.StatusCode, resbody)
params.Set("error", "error without status code")
- httpres, resbody, _ = client.Get("/", nil, params)
+ httpres, resbody, err = client.Get(`/`, nil, params)
+ if err != nil {
+ log.Fatal(err)
+ }
fmt.Printf("%d: %s\n", httpres.StatusCode, resbody)
// Output: