Skip to content
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

allow the expect 100 continue workflow to deny requests #787

Merged
merged 3 commits into from Apr 27, 2020
Merged

allow the expect 100 continue workflow to deny requests #787

merged 3 commits into from Apr 27, 2020

Conversation

mmacdermaid
Copy link
Contributor

@mmacdermaid mmacdermaid commented Apr 21, 2020

Fixes #783

An okay solution right now which allows servers to deny reading the request body after reading the request headers via a server callback configuration.

A more long term solution later on might be to give full control to the user during their handler callback, but that would definitely require a lot more work and be more error prone for the user.

One unfortunate issue with this is, if you do any major work in processing headers before accepting or denying a request, you likely will have to re-process the headers on the other side. It might be worth sticking a

func() interface[}

callback out of the deny which can be passed to a new handler, so people can pass state between the two.

if s.DenyRequest != nil {
if deniedRequest = s.DenyRequest(&ctx.Request.Header); deniedRequest {
if br != nil {
br.Reset(ctx.c)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erikdubbelboer After debugging the strange relationship between the headers and request bodies, this ended up being the "correct" way to reproduce whatever is currently happening inside of serveConn.

Someone more familiar with the code definitely needs to weigh in on this piece here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? Shouldn't the reader be empty at this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I have tested it is 100% needed. If not the loop will come back around, attempt a call on if err = ctx.Request.Header.Read(br); err == nil { and fail with server_test.go:1705: Unexpected error from serveConn: error when reading request headers: EOF.

I believe this is because br is not nil so

br = acquireReader(ctx)

Does not get called, which means it's already in a place somewhere but hasn't been fully read or reset. The function that would normally change it's position or use it later on ctx.Request.ContinueReadBody hasn't been called in this case because the request was abandoned.

At least that's what I think?

br.Reset(ctx.c)
}

ctx.SetStatusCode(StatusExpectationFailed)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seemed to be the most reasonable and clean way to allow setting the response code without calling flush etc, and letting the connection continue as it would have if someone's handler been called and written the same status code.

server.go Outdated
//https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3
//https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.1
//Using DenyRequest a server can make decisioning on whether or not
//to read a potentially large request body based on the headers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are spaces missing after the //, in many other places as well.

server.go Outdated
@@ -172,6 +172,17 @@ type Server struct {
// non zero RequestConfig field values will overwrite the default configs
HeaderReceived func(header *RequestHeader) RequestConfig

// DenyRequest is called after receiving the Expect 100 Continue Header
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think DenyRequest is not a clear name for this. Maybe just call it ContinueHandler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if s.DenyRequest != nil {
if deniedRequest = s.DenyRequest(&ctx.Request.Header); deniedRequest {
if br != nil {
br.Reset(ctx.c)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? Shouldn't the reader be empty at this point?

@erikdubbelboer erikdubbelboer merged commit 3294097 into valyala:master Apr 27, 2020
@erikdubbelboer
Copy link
Collaborator

Thanks!

@mmacdermaid
Copy link
Contributor Author

👍 Happy to help.

@mmacdermaid mmacdermaid deleted the deny_requests branch May 7, 2020 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Expect 100 Continue example/support?
2 participants