-
Notifications
You must be signed in to change notification settings - Fork 415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nil buffer fix #136
nil buffer fix #136
Conversation
Hi @jaytaylor, |
Hi @parnurzeal! I agree, it is not immediately obvious what's going on or why this is needed. From Example gorequest code(Extremely basic) package main
import (
"github.com/parnurzeal/gorequest"
)
func main() {
request := gorequest.New()
request.Get("http://localhost:9000/").EndBytes()
} Previous working f441e24 (Jan 9, 2017)Launch $ nc -l -v 127.0.0.1 9000
GET / HTTP/1.1
Host: localhost:9000
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
Connection: close #129 a578a48 (Feb 10, 2017)Launch $ nc -l -v 127.0.0.1 9000
GET / HTTP/1.1
Host: localhost:9000
User-Agent: Go-http-client/1.1
Content-Type: application/json
Accept-Encoding: gzip
Connection: close Notice the new "application/json" content-type header. Since no JSON has been specified, this seems like undesirable behavior. To be candid, I'm not sure if this PR even resolves that piece. Also, I agree with the merge request which caused/revealed these issues - imho it's good to allow any request type to have a body attached to it and let people make their own decision. With that said, looking through net.NewRequest(...) src code, there is a fair amount of logic dependent on whether or not the body is null. This is why it seems highly undesirable to send a non-nil body buffer wrapping nil contents to I'll update this PR to address the nil-body aspect for all specially-cased content-types (originally this PR only fixed the JSON case). |
Update I've added handling for all cases except for |
Additionally, the results of the experiment outlined above with this PR applied are as follows: $ nc -l -v 127.0.0.1 9000
GET / HTTP/1.1
Host: localhost:9000
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
Connection: close Which is back to looking good. |
Interesting! Thank you for a deep dive into the issue. For improving the code, how about taking For example:
I know it might not be straightforward to read but we can add more comments to make it clear. WDYT? I am also open to ideas :) |
Sure, updating the PR to reflect the proposed approach now :) |
@parnurzeal Alright, I think we're so close! Everything seems to work swell, except for the multipart form tests. A test-case failure and an NPE are being triggered. I'm not entirely clear on what we're testing for in these cases. Failing cases: near line 724 in gorequest_test.go: const _24K = (1 << 20) * 24
err := r.ParseMultipartForm(_24K)
if err != nil {
t.Errorf("Error: %v", err)
}
near line 756 in gorequest_test.go: if val, ok := r.MultipartForm.Value["query1"]; ok {
t.Error("Expected no value", "| but got", val)
}
There is also a failure around line 722 which goes away if I force the content-type header to be sent regardless of whether anything has been encoded:
Your thoughts on how we should proceed are appreciated :) |
I think the failures in those cases, they are sending zero body content and also checking whether there is a "Content-Type" multi-part or not. And because we changed the behavior not to send "Content-Type", this then makes it fail. But anyway @jaytaylor , when seeing this error, it made think twice whether we should add logic under it to bounce back to no "Content-Type" if there is no body content. I am terribly sorry about this but I think we might think too much about this. If a user forces Type("multipart") or Type("form") or ... anything explicitly, we maybe should just let the "Content-Type" be whatever the user wants it to be. The user should be the one who is responsible to not send zero body content her/himself. So, the easier way to fix this, we need to go look back to the issue cause of when that PR #129 introduced. And it is just coincidentally I made s.TargetType default to "json" since the beginning of this project. That's why after that PR #129, it sets GET request's content-type to json.
Again, really sorry that I might waste your time on the incorrect direction. |
This is an interesting turn of perspective! I agree that if a user forces a type, then it should be respected. At the same time, what we've done here to make a best effort to avoid sending non-nil buffers with nil contents to Also, I've found that adding a simple body ( The functionality you're describing doesn't seem mutually exclusive. Is there room for both? How would you feel about merging this and filing an issue for the target type updates? |
Ok cool :) SGTM. |
gorequest.go
Outdated
if contentJson != nil { | ||
contentReader = bytes.NewReader(contentJson) | ||
contentType = "application/json" | ||
} | ||
req, err = http.NewRequest(s.Method, s.Url, contentReader) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be taken out to outside of this if-else.
gorequest.go
Outdated
if len(contentForm) != 0 { | ||
contentReader = bytes.NewReader(contentForm) | ||
contentType = "application/x-www-form-urlencoded" | ||
} | ||
req, err = http.NewRequest(s.Method, s.Url, contentReader) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
gorequest.go
Outdated
} | ||
|
||
req, err = http.NewRequest(s.Method, s.Url, contentReader) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. This can be taken out of if-else code here.
req, err = http.NewRequest(s.Method, s.Url, contentReader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} else { | ||
// let's return an error instead of an nil pointer exception here | ||
return nil, errors.New("TargetType '" + s.TargetType + "' could not be determined") | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should move those error checks in if-else code to here:
Add:
if err != nil {
return nil, err
}
- Don't allow buffers with nil contents to be passed to `http.NewRequest' constructor. Fixes errors like: Get https://[SOME-WEBSITE]: stream error: stream ID 1; REFUSED_STREAM See #136 for further information.
@parnurzeal Excellent feedback, I had the impulse to do it earlier but refrained on the principle of min-diff. Let me know how this looks~ Cheers, |
Super good! |
Likewise, thank you! :) |
Fixed nil reader content regression introduced with PR #129.
Don't allow buffers with nil contents to be passed to
http.NewRequest
constructor.Fixes errors like:
Get https://[SOME-WEBSITE]: stream error: stream ID 1; REFUSED_STREAM