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

net/http: document more how to abort a response from Handlers #17790

Closed
jech opened this issue Nov 4, 2016 · 8 comments
Closed

net/http: document more how to abort a response from Handlers #17790

jech opened this issue Nov 4, 2016 · 8 comments
Labels
Documentation FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Milestone

Comments

@jech
Copy link

jech commented Nov 4, 2016

HTTP/1.1 doesn't provide a way to signal an error to the client after we have started writing out a body (not sure about HTTP/2). When serving a chunked reply, an error can only be signaled by interrupting the connection without terminating the chunked framing.

I'm currently doing the following to abort a reply prematurely, which is less than obvious and does nothing useful with HTTP/2:

hj, ok := w.(http.Hijacker)
if ok {
        conn, _, err := hj.Hijack()
        if err != nil {
                return;
        }
        conn.Close()
}
return

(This can be tested with curl, which should display "transfer closed with outstanding read data remaining" when this code triggers.)

Please provide an official, documented way to brutally interrupt a reply after the headers have been sent.

@bradfitz
Copy link
Contributor

bradfitz commented Nov 4, 2016

Calling panic works for both http1 and http2 and does the right thing in both, and we have tests for both.

See #16542 (comment) for some background.

The docs already say:

If ServeHTTP panics, the server (the caller of ServeHTTP) assumes that the effect of the panic was isolated to the active request. It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.

I suppose you want a way to do this without the stack trace, though?

I thought we had a bug open about that, but I can't find it, so we'll use this one. Thanks for filing.

@bradfitz bradfitz changed the title http: no obvious way to abort a chunked reply net/http: document more how to abort a response from Handlers Nov 4, 2016
@bradfitz bradfitz self-assigned this Nov 4, 2016
@bradfitz bradfitz added this to the Go1.8 milestone Nov 4, 2016
@jech
Copy link
Author

jech commented Nov 4, 2016

If ServeHTTP panics [...] hangs up the connection.

Ah, right.

I suppose you want a way to do this without the stack trace, though?

Yes, this is meant to happen when the backend times out, and it's part of
the normal behaviour of the application.

-- Juliusz

@rhysh
Copy link
Contributor

rhysh commented Nov 7, 2016

I've found that runtime.Goexit() and panic(nil) both work well for this—they interrupt the request and do not cause a stack track to be printed. @bradfitz , are these behaviors intentional and supported?

https://play.golang.org/p/96dhROeoTh
https://play.golang.org/p/g_1P56OIKr

@quentinmit quentinmit added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Nov 7, 2016
@bradfitz
Copy link
Contributor

@rhysh, neither of those were intentional. panic(nil) looks like it only works for HTTP/1. In the http2.Server, the code looks like:

// Run on its own goroutine.                                                                                                                                                                                                                           
func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
        didPanic := true
        defer func() {
                rw.rws.stream.cancelCtx()
                if didPanic {
                        e := recover()
                        // Same as net/http:                                                                                                                                                                                                           
                        const size = 64 << 10
                        buf := make([]byte, size)
                        buf = buf[:runtime.Stack(buf, false)]
// ...
                        sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
                        return
                }
                rw.handlerDone()
        }()
        handler(rw, req)
        didPanic = false
}

Likewise, it looks like http2.Server would interpret a runtime.Goexit as if it were a panic.

I suppose we could make that the official way, though. One one official way.

I think I'd prefer to make an explicit panic value, though, so if you're using a different http server hosting http.Handlers and that implementation forgets to do the recover() thing, at least the error message will be explicit about the Handler's intentions, rather than a mystery panic.

@gopherbot
Copy link

CL https://golang.org/cl/33099 mentions this issue.

gopherbot pushed a commit that referenced this issue Nov 10, 2016
Add an explicit way for Handlers to abort their response to the client
and also not spam their error log with stack traces.

panic(nil) also worked in the past (for http1 at least), so continue
to make that work (and test it). But ErrAbortHandler is more explicit.

Updates #17790 (needs http2 updates also)

Change-Id: Ib1456905b27e2ae8cf04c0983dc73e314a4a751e
Reviewed-on: https://go-review.googlesource.com/33099
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
@gopherbot
Copy link

CL https://golang.org/cl/33102 mentions this issue.

gopherbot pushed a commit to golang/net that referenced this issue Nov 10, 2016
…et/http

Updates golang/go#17790

Change-Id: I7bc596d9a80490d545ad3d1de5859efce34714f6
Reviewed-on: https://go-review.googlesource.com/33102
TryBot-Result: Gobot Gobot <gobot@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
@gopherbot
Copy link

CL https://golang.org/cl/33103 mentions this issue.

@jech
Copy link
Author

jech commented Nov 11, 2016 via email

@golang golang locked and limited conversation to collaborators Nov 11, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Documentation FrozenDueToAge NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
None yet
Development

No branches or pull requests

5 participants