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

x/net/http2: server appears to send DATA_FRAME before END_HEADERS for a stream #12923

Closed
bmizerany opened this issue Oct 13, 2015 · 6 comments
Closed

Comments

@bmizerany
Copy link
Contributor

@bmizerany bmizerany commented Oct 13, 2015

func TestServer_Response_LargeWrite_Concurrent(t *testing.T) {
    const size = 1 << 20
    const maxFrameSize = 16 << 10
    testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
        n, err := w.Write(bytes.Repeat([]byte("a"), size))
        if err != nil {
            return fmt.Errorf("Write error: %v", err)
        }
        if n != size {
            return fmt.Errorf("wrong size %d from Write", n)
        }
        return nil
    }, func(st *serverTester) {
        if err := st.fr.WriteSettings(
            Setting{SettingInitialWindowSize, 0},
            Setting{SettingMaxFrameSize, maxFrameSize},
        ); err != nil {
            t.Fatal(err)
        }
        st.wantSettingsAck()

        nreqs := 1000
        streamID := uint32(1) // clients send odd ids
        for i := 0; i < nreqs; i++ {
            println("sending:", streamID)
            st.bodylessReq(streamID) // GET /
            // Give the handler quota to write:
            if err := st.fr.WriteWindowUpdate(streamID, size); err != nil {
                t.Fatal(err)
            }
            // Give the handler quota to write to connection-level
            // window as well
            if err := st.fr.WriteWindowUpdate(0, size); err != nil {
                t.Fatal(err)
            }
            streamID += 2
        }

        for {
            println("ReadFrame")
            f, err := st.fr.ReadFrame()
            if err != nil {
                panic(err)
            }
            println("nreqs:", nreqs)
            if es, ok := f.(streamEnder); ok && es.StreamEnded() {
                nreqs--
                if nreqs == 0 {
                    return
                }
            }
        }
    })
}

Running go test -run=TestServer_Response_LargeWrite_Concurrent -v hangs.

@bmizerany

This comment has been minimized.

Copy link
Contributor Author

@bmizerany bmizerany commented Oct 13, 2015

This is wrong. Ignore. Will file another.

@bmizerany bmizerany closed this Oct 13, 2015
@bmizerany

This comment has been minimized.

Copy link
Contributor Author

@bmizerany bmizerany commented Oct 13, 2015

I've updated the issue with a test hangs reproducibly.

@bmizerany bmizerany reopened this Oct 13, 2015
@bmizerany

This comment has been minimized.

Copy link
Contributor Author

@bmizerany bmizerany commented Oct 14, 2015

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Oct 14, 2015

The testServerResponse function is only allowed to do one write. It's even documented as such. That's where the hang is happening if you send it SIGQUIT (control-) and see the goroutines.

Have you observed this DATA-before-HEADERS behavior otherwise?

That is, is it just the test that's buggy but the issue remains?

@bradfitz

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Oct 14, 2015

I just audited the code for ways a DATA frame can go out before the HEADERS but I'm not seeing a way: from the handler's goroutine, (*responseWriterState).writeChunk looks fine: writeHeaders is called before writeDataFromHandler and both call writeFrameFromHandler which looks fine and sends on a channel. The sole receiver of that channel (in the server goroutine) also looks fine, calling into the write scheduler (writesched.go) and those add & push methods look fine too.

I'm closing this for now until I have something to go on.

@bradfitz bradfitz closed this Oct 14, 2015
@bmizerany

This comment has been minimized.

Copy link
Contributor Author

@bmizerany bmizerany commented Oct 21, 2015

I think this exposed what I was trying to: #12998

@golang golang locked and limited conversation to collaborators Oct 24, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.