Skip to content

Commit 6ce73bf

Browse files
authored
internal/transport: convert ConnectionError to Unavailable status when writing headers (#6891)
1 parent e7e400b commit 6ce73bf

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-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: 65 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,70 @@ 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+
server.mu.Lock()
2156+
2157+
if len(server.conns) != 1 {
2158+
t.Fatalf("Server has %d connections from the client, want 1", len(server.conns))
2159+
}
2160+
2161+
// Get the server transport for the connecton to the client.
2162+
var serverTransport *http2Server
2163+
for k := range server.conns {
2164+
serverTransport = k.(*http2Server)
2165+
}
2166+
notifyChan := make(chan struct{})
2167+
server.h.notify = notifyChan
2168+
server.mu.Unlock()
2169+
2170+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
2171+
defer cancel()
2172+
cstream, err := client.NewStream(ctx, &CallHdr{})
2173+
if err != nil {
2174+
t.Fatalf("Client failed to create first stream. Err: %v", err)
2175+
}
2176+
2177+
<-notifyChan // Wait for server stream to be established.
2178+
var sstream *Stream
2179+
// Access stream on the server.
2180+
serverTransport.mu.Lock()
2181+
for _, v := range serverTransport.activeStreams {
2182+
if v.id == cstream.id {
2183+
sstream = v
2184+
}
2185+
}
2186+
serverTransport.mu.Unlock()
2187+
if sstream == nil {
2188+
t.Fatalf("Didn't find stream corresponding to client cstream.id: %v on the server", cstream.id)
2189+
}
2190+
2191+
client.Close(fmt.Errorf("closed manually by test"))
2192+
2193+
// Wait for server transport to be closed.
2194+
<-serverTransport.done
2195+
2196+
// Write header on a closed server transport.
2197+
err = serverTransport.WriteHeader(sstream, metadata.MD{})
2198+
st := status.Convert(err)
2199+
if st.Code() != codes.Unavailable {
2200+
t.Fatalf("WriteHeader() failed with status code %s, want %s", st.Code(), codes.Unavailable)
2201+
}
2202+
}
2203+
21392204
func (s) TestPingPong1B(t *testing.T) {
21402205
runPingPongTest(t, 1)
21412206
}

0 commit comments

Comments
 (0)