heya everyone: Got a short question, I would like to post(http) a file. I figured, since os.Open returns an io.Reader and http.Post takes an io.Reader I do not have read the file into memory in a separate step and can just pass around the Reader. However, the Content-Length will be set to zero- which kinda makes sense but is not what I need.
file, _ := os.Open("some file")
req, _ := http.NewRequest("POST", "some url", file)
dump, _ := httputil.DumpRequestOut(req, false)
fmt.Println(string(dump))
My question: Do i have to read the file into memory (with ioutil.ReadFile or some such) and make a new reader or is there a way to pass the reader from the file directly to the Post request without the "Reading" step?
I guess I could set the Content-Length by getting it via file.Stat, but I was wondering if there is a more elegant way of doing this?
Short answer is: you are absolutely right about giving the os.File to http.Request and about using os.File.Stat() to get the file size and setting it on the http.Request headers. Personally I've found it to be the simplest way around.
i.e.
file, _ := os.Open("some file")
info, _ := file.Stat()
req, _ := http.NewRequest("POST", "http://bla.com", file)
req.ContentLength = info.Size()
dump, _ := httputil.DumpRequestOut(req, false)
fmt.Println(string(dump))
Also note that as per http.Request.Write() documentation (I quote):
If Body is present, Content-Length is <= 0 and TransferEncoding hasn't been set to "identity", Write adds "Transfer-Encoding: chunked" to the header. Body is closed after it is sent.
So in that case the client itself would do the (arguably) most sensible thing to do for you.
Yes, it's possible to pass whatever os.Open()
returned directly as the body of a HTTP request to be made.
But there are only two ways to deal with the content length of that file's data. They are different, but they both revolve around the idea that the receiving side either must know the content length in advance—that is, from the HTTP response headers is receives before the body or it must use a mechanism which allows to not know it, and then the sender must have a way to signal that it's done sending the data.
A "classic" one—working even with HTTP/1.0— is to calculate it before sending. This indeed means either reading the whole thing into memory or doing a stat
call (you can do it on an opened file BTW).
HTTP/1.1 supports the so-called "chunked" transfer encoding of the data it sends. In this case, the payload is cut into pieces and each piece is sent in turn—using certain framing. A special frame signalizes the end of the data stream. In this case it's OK to set Content-Type to 0, but the client must support chunked encoding (not all do).