Skip to content

Commit 2b28dc1

Browse files
mustafasen81msenarista
authored andcommitted
internal/transport/http2_server: properly convert ConnectionError to Unavailable status in WriteHeader
1 parent 4f03f3f commit 2b28dc1

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

internal/transport/http2_server.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,12 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error {
960960
}
961961
}
962962
if err := t.writeHeaderLocked(s); err != nil {
963-
return status.Convert(err).Err()
963+
switch e := err.(type) {
964+
case ConnectionError:
965+
return status.Error(codes.Unavailable, e.Desc)
966+
default:
967+
return status.Convert(err).Err()
968+
}
964969
}
965970
return nil
966971
}

internal/transport/transport_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
"google.golang.org/grpc/internal/grpctest"
4646
"google.golang.org/grpc/internal/leakcheck"
4747
"google.golang.org/grpc/internal/testutils"
48+
"google.golang.org/grpc/metadata"
4849
"google.golang.org/grpc/resolver"
4950
"google.golang.org/grpc/status"
5051
)
@@ -2136,6 +2137,69 @@ func (s) TestHeadersHTTPStatusGRPCStatus(t *testing.T) {
21362137
}
21372138
}
21382139

2140+
func (s) TestWriteHeaderConnectionError(t *testing.T) {
2141+
server, client, cancel := setUp(t, 0, notifyCall)
2142+
defer cancel()
2143+
defer server.stop()
2144+
2145+
waitWhileTrue(t, func() (bool, error) {
2146+
server.mu.Lock()
2147+
defer server.mu.Unlock()
2148+
2149+
if len(server.conns) == 0 {
2150+
return true, fmt.Errorf("timed-out while waiting for connection to be created on the server")
2151+
}
2152+
return false, nil
2153+
})
2154+
2155+
if len(server.conns) != 1 {
2156+
t.Fatal("Server must have an active connection for the client.")
2157+
}
2158+
2159+
// Get the server transfort for the connecton to the client
2160+
var serverTransport *http2Server
2161+
server.mu.Lock()
2162+
for k := range server.conns {
2163+
serverTransport = k.(*http2Server)
2164+
}
2165+
notifyChan := make(chan struct{})
2166+
server.h.notify = notifyChan
2167+
server.mu.Unlock()
2168+
2169+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
2170+
defer cancel()
2171+
cstream1, err := client.NewStream(ctx, &CallHdr{})
2172+
if err != nil {
2173+
t.Fatalf("Client failed to create first stream. Err: %v", err)
2174+
}
2175+
2176+
<-notifyChan // Wait server stream to be established
2177+
var sstream1 *Stream
2178+
// Access stream on the server
2179+
serverTransport.mu.Lock()
2180+
for _, v := range serverTransport.activeStreams {
2181+
if v.id == cstream1.id {
2182+
sstream1 = v
2183+
}
2184+
}
2185+
serverTransport.mu.Unlock()
2186+
if sstream1 == nil {
2187+
t.Fatalf("Didn't find stream corresponding to client cstream.id: %v on the server", cstream1.id)
2188+
}
2189+
2190+
client.Close(fmt.Errorf("closed manually by test"))
2191+
2192+
// Wait server transport to be closed
2193+
<-serverTransport.done
2194+
2195+
// Write header on a closed server transport
2196+
err = serverTransport.WriteHeader(sstream1, metadata.MD{})
2197+
st := status.Convert(err)
2198+
if st.Code() != codes.Unavailable {
2199+
t.Fatalf("Unailable status expected but got: %v", st.Code().String())
2200+
}
2201+
}
2202+
21392203
func (s) TestPingPong1B(t *testing.T) {
21402204
runPingPongTest(t, 1)
21412205
}

0 commit comments

Comments
 (0)