I observed that Content-Length header is not getting set for PATCH requests with empty/nil payload. Even if we manually set it by req.Header.Set("content-length", "0") it is not actually getting set in the out going request.
This strange behaviour (Go bug?) happens only for PATCH requests and only when the payload is empty or nil (or set to http.NoBody)
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
func main() {
url := "http://localhost:9999"
method := "PATCH"
payload := strings.NewReader("")
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
}
req.Header.Set("Authorization", "Bearer my-token")
req.Header.Set("Content-Length", "0") //this is not honoured
res, err := client.Do(req)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
fmt.Println(string(body))
}
This is reproducible even in the latest go version 1.15.
Just run the above code against a simple http server and see for yourself.
Is there any solution/workaround to send a PATCH request with Content-Length set to 0 ?
You can tell the HTTP client to include a
Content-Lengthheader with value 0 by setting TransferEncoding toidentityas follows:Note the following changes to your original code:
req.TransferEncoding = []string{"identity"}http.NoBody(no impact on sending the length)req.Header.Set("Content-Length", "0"), the client fills it in by itselfThe transfer encoding of
identityis not written to the request, so except for the headerContent-Length = 0, the request looks the same as before.This is unfortunately not documented (feel free to file an issue with the Go team), but can be seen in the following code:
The tedious details:
transferWriter.writeHeader checks the following to write the
Content-Lengthheader:In turn, shouldCheckContentLength looks at the transfer encoding in case of zero length:
The isIdentity verifies that
TransferEncodingis exactly[]string{"identity"}: