Skip to content

Commit eeda2b4

Browse files
authored
vms/rpcchainvm: ensure response code is valid (ava-labs#1437)
1 parent ded4026 commit eeda2b4

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

vms/rpcchainvm/ghttp/gresponsewriter/writer_server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (s *Server) WriteHeader(ctx context.Context, req *responsewriterpb.WriteHea
6868
for _, header := range req.Headers {
6969
headers[header.Key] = header.Values
7070
}
71-
s.writer.WriteHeader(int(req.StatusCode))
71+
s.writer.WriteHeader(grpcutils.EnsureValidResponseCode(int(req.StatusCode)))
7272
return &emptypb.Empty{}, nil
7373
}
7474

vms/rpcchainvm/ghttp/http_client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func getHTTPSimpleRequest(r *http.Request) (*httppb.HandleSimpleHTTPRequest, err
217217
// convertWriteResponse converts a gRPC HandleSimpleHTTPResponse to an HTTP response.
218218
func convertWriteResponse(w http.ResponseWriter, resp *httppb.HandleSimpleHTTPResponse) error {
219219
grpcutils.MergeHTTPHeader(resp.Headers, w.Header())
220-
w.WriteHeader(int(resp.Code))
220+
w.WriteHeader(grpcutils.EnsureValidResponseCode(int(resp.Code)))
221221
_, err := w.Write(resp.Body)
222222
return err
223223
}

vms/rpcchainvm/ghttp/http_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package ghttp
5+
6+
import (
7+
"net/http/httptest"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
12+
httppb "github.com/ava-labs/avalanchego/proto/pb/http"
13+
)
14+
15+
func Test_convertWriteResponse(t *testing.T) {
16+
assert := assert.New(t)
17+
18+
scenerios := map[string]struct {
19+
resp *httppb.HandleSimpleHTTPResponse
20+
}{
21+
"empty response": {
22+
resp: &httppb.HandleSimpleHTTPResponse{},
23+
},
24+
"response header value empty": {
25+
resp: &httppb.HandleSimpleHTTPResponse{
26+
Code: 500,
27+
Body: []byte("foo"),
28+
Headers: []*httppb.Element{
29+
{
30+
Key: "foo",
31+
},
32+
},
33+
},
34+
},
35+
"response header key empty": {
36+
resp: &httppb.HandleSimpleHTTPResponse{
37+
Code: 200,
38+
Body: []byte("foo"),
39+
Headers: []*httppb.Element{
40+
{
41+
Values: []string{"foo"},
42+
},
43+
},
44+
},
45+
},
46+
}
47+
for testName, scenerio := range scenerios {
48+
t.Run(testName, func(t *testing.T) {
49+
w := httptest.NewRecorder()
50+
err := convertWriteResponse(w, scenerio.resp)
51+
assert.NoError(err)
52+
})
53+
}
54+
}

vms/rpcchainvm/grpcutils/util.go

+10
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,13 @@ func TimestampAsTime(ts *tspb.Timestamp) (time.Time, error) {
186186
func TimestampFromTime(time time.Time) *tspb.Timestamp {
187187
return tspb.New(time)
188188
}
189+
190+
// EnsureValidResponseCode ensures that the response code is valid otherwise it returns 500.
191+
func EnsureValidResponseCode(code int) int {
192+
// Response code outside of this range is invalid and could panic.
193+
// ref. https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
194+
if code < 100 || code > 599 {
195+
return http.StatusInternalServerError
196+
}
197+
return code
198+
}

0 commit comments

Comments
 (0)