Why not set Request.ContentLength beforehand (you know it)? dmo...@synack.com a következőt írta (2022. január 14., péntek, 18:56:57 UTC+1):
> Sorry to insist, but I think there's also a performance issue with the > current implementation. Given that the service I need to communicate to > requires me to send Content-Length header I am forced to read into memory > potentially large files that I want to send them, buffering them in one of > the three (undocumented!) *structs that are known > (*bytes.Buffer, *bytes.Reader or *strings.Reader) instead of being able to > just pass the *os.File. Thing is, I could analyze the size of each file, > break it down into parts that I can read into memory and make a request for > each part that the service would later join into a single file, but that > sounds like overkill and also sounds like a lot of work and overhead for > something that could be done with a simple io.Reader. > > I think that the easiest way to overcome this issue and at the same time > not break the promises made would be to do something like: > > func readerLength(body io.Reader) (int64, error) { > if f, _ := body.(fs.File); f != nil { > if i, err := f.Stat(); err == nil { // discard error and > try io.Seeker interface later (it's cheaper to stat instead of seeking) > return i.Size(), nil > } > } > > if s, _ := body.(interface { // covers *bytes.Reader and other > Size() int64 > }); s != nil { > return s.Size(), nil > } > > if l, _ := body.(interface { // covers all the three current > undocumented items: *bytes.Buffer, *bytes.Reader and *strings.Reader > Len() int > }); l != nil { > return int64(l.Len()), nil > } > > if s, _ := body.(io.Seeker); s != nil { // covers a lot of other > cases, like multipart.File, errors statting *os.File, etc. > cur, err := s.Seek(0, io.SeekCurrent) > if err != nil { > return -1, fmt.Errorf("error checking current > position: %w", err) > } > > end, err := s.Seek(0, io.SeekEnd) > if err != nil { > return -1, fmt.Errorf("error seeking end position: > %w", err) > } > > _, err = s.Seek(cur, io.SeekStart) > if err != nil { > return -1, fmt.Errorf("error going back to initial > position: %w", err) > } > > return end - cur, nil > } > > return -1, errors.New("unknown body, don't send the Content-Length > header") > } > > > > On Friday, September 17, 2021 at 2:23:50 PM UTC-3 Diego Molina wrote: > >> Ok, that makes total sense. I'm now using `req.TransferEncoding = >> []string{"identity"}` and this behaviour is suppressed, but of course I >> still don't get the Content-Length, which is fair. >> >> Thanks all! >> >> On Fri, Sep 17, 2021 at 2:09 PM Brian Candler <b.ca...@pobox.com> wrote: >> >>> All chunks must be prefixed by a chunk length - even if that length is >>> zero. >>> >>> On Friday, 17 September 2021 at 16:53:07 UTC+1 dmo...@synack.com wrote: >>> >>>> Oh, thanks for clarifying that. But still, even if transfer encoding >>>> will be chunked, I don't see why it would make up a body of "0\r\n\r\n" if >>>> the nop body wouldn't give away any bytes at all. >>>> >>>> On Friday, September 17, 2021 at 7:56:21 AM UTC-3 seank...@gmail.com >>>> wrote: >>>> >>>>> This was an intentional change in 1.8 >>>>> https://github.com/golang/go/issues/20257#issuecomment-299509391 >>>>> >>>>> On Friday, September 17, 2021 at 6:45:13 AM UTC+2 dmo...@synack.com >>>>> wrote: >>>>> >>>>>> Hi, when using a custom io.ReadCloser nop as body with method POST, >>>>>> PUT, PATCH, TRACE or custom then (*http.Request).Write outputs a body of >>>>>> the form "0\r\n\r\n" (without the quotes). Proof-of-concept: >>>>>> https://play.golang.org/p/Rg2cZ0wihdd >>>>>> >>>>>> Besides the fix, I think it would be useful to have body checked if >>>>>> it satisfies interface{ Len() int } or something similar (this would >>>>>> simplify code too by removing several type assertions, e.g., >>>>>> isKnownInMemoryReader func in net/http/trans...@go1.17.1) so that we can >>>>>> avoid chunked transfer encoding. >>>>>> >>>>>> This email may contain material that is confidential for the sole use >>>>>> of the intended recipient(s). Any review, reliance or distribution or >>>>>> disclosure by others without express permission is strictly prohibited. >>>>>> If >>>>>> you are not the intended recipient, please contact the sender and delete >>>>>> all copies of this message. >>>>>> >>>>> -- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "golang-nuts" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/golang-nuts/ZlhK8whGwck/unsubscribe. >>> To unsubscribe from this group and all its topics, send an email to >>> golang-nuts...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/6847c965-3325-40f1-825e-2ccafa70cd3an%40googlegroups.com >>> >>> <https://groups.google.com/d/msgid/golang-nuts/6847c965-3325-40f1-825e-2ccafa70cd3an%40googlegroups.com?utm_medium=email&utm_source=footer> >>> . >>> >> >> This email may contain material that is confidential for the sole use of >> the intended recipient(s). Any review, reliance or distribution or >> disclosure by others without express permission is strictly prohibited. If >> you are not the intended recipient, please contact the sender and delete >> all copies of this message. >> > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/859e6212-efd1-4cf0-9bc5-e33449534ed8n%40googlegroups.com.