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

Consume body on res.respond if user does not call req.body #49

Closed
wants to merge 4 commits into from

Conversation

kevinkassimo
Copy link
Contributor

Fix #40

Consume body on req.respond() if the user fails to call req.body()

net/http_test.ts Outdated
});
// Body should have been secretly consumed by here
const body = dec.decode(await req.body());
assertEqual(body, "");
Copy link
Member

Choose a reason for hiding this comment

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

Should we allow to consume body multiple times?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean that you expect req.body() to return the content even after respond, or do you mean that invoking multiple times of req.body() would all yield empty string here?

Copy link
Member

Choose a reason for hiding this comment

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

IMHO error should be thrown if one tries to consume body after respond - it'll be less surprising for users and would allow to spot mistakes in code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. Updated.

@ry
Copy link
Member

ry commented Jan 2, 2019

@kevinkassimo I'm a little concerned about this patch. I'm imaging an HTTP/1.0 connection (i.e. without keep-alive) in which the requester is uploading a file. Imagine the server gets the request, processes it and decides that it will not accept the upload, it wants to send back an html page with status 401 (Unauthorized). The server should simply stop reading from the socket - send the response - and then close the connection. If the server is forced to read a potentially very large upload every time it wants to reply, then this could be a DoS attack vector.

@bartlomieju
Copy link
Member

I guess it becomes related to #22 as well, probably we should check how Go's server handles that case and follow similar pattern. OTOH if request has Connection: Keep-Alive and user doesn't consume body before responding we should consume it or error from #40 emerges.

@ry
Copy link
Member

ry commented Jan 2, 2019

Since our server is a close port of Go's, I think it would be good if we researched how Go handles this situation. Does anyone have time to dive into https://github.com/golang/go/tree/master/src/net/http and pull up some links?

@bartlomieju
Copy link
Member

I already read through some of it for #22, so I can handle that

@bartlomieju
Copy link
Member

I went digging through Golang's codebase. Here some sythesis with links.

https://github.com/golang/go/blob/9e277f7d554455e16ba3762541c53e9bfc1d8188/src/net/http/server.go#L1818

// after establishing connection

w, err := c.readRequest(ctx)  // 1.
...
if err != nil {
    ...
}

// Expect 100 Continue support
...
serverHandler{c.server}.ServeHTTP(w, w.req)  // 2.
...
w.finishRequest()  // 3.
if !w.shouldReuseConnection() {  // 4.
    if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
        c.closeWriteAndWait()
    }
    return
}
...
  1. Read request from connection:
    1. parse first line
    2. headers
    3. quirk with host
    4. establish req.Close result of shouldClose
    5. set up body
    6. some check I do not understand, that actually controls what happens with body
  2. Call user provided handler
  3. Finish request
    1. ensure headers, flush writers, etc.
    2. close the body - this function checks if body was already consumed and if not it decides whether to consume or discard based on result from 1.6
  4. Check if connection should be reused
    • basically if there was something to read in 3.2 and body was closed connection will not be reused

I have to admit that this logic is very complicated and I'm not experienced with Golang so please could someone double-check it?

@ry
Copy link
Member

ry commented Jan 3, 2019

Thank you!

closedRequestBodyEarly and closeWriteAndWait is the smart idea I think we need here.

@kevinkassimo
Copy link
Contributor Author

@bartlomieju I'll also look into details tonight. Thanks for diving in!

@kevinkassimo
Copy link
Contributor Author

Actually, I'm planning to make HTTP more Go-ish in the next few days. It would probably be nice to just directly replicating the structure instead of developing some unreliable design ourselves...

@kevinkassimo
Copy link
Contributor Author

kevinkassimo commented Jan 4, 2019

Also, let's complete #76 first. Closing this.

I'll work on a best effort Go port after completing reorg

@ry
Copy link
Member

ry commented Jan 25, 2019

I went digging through Golang's codebase. Here some sythesis with links.

closedRequestBodyEarly and closeWriteAndWait is the smart idea I think we need here.

@kevinkassimo @bartlomieju any updates on this?

@kevinkassimo
Copy link
Contributor Author

@ry Quite busy these days and probably won't involve very much in the coming month. Hope someone else could take on the task.

@bartlomieju
Copy link
Member

I'll look into it this week

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.

3 participants