Skip to content

Commit

Permalink
Adjusting the written etag to be wrapped in quotes and only returned …
Browse files Browse the repository at this point in the history
…for GET requests as per the standard
  • Loading branch information
joshgarnett committed Apr 26, 2024
1 parent 2dc39a3 commit 3ab49ed
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
6 changes: 3 additions & 3 deletions runtime/handler.go
Expand Up @@ -183,14 +183,14 @@ func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marsha
w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
}

// Generate an Etag for any messages larger than 100 bytes.
// Generate an Etag for any GET requests with messages larger than 100 bytes.
// Writing the Etag in the response takes 39 bytes, so it's not worth doing for smaller messages.
etag := ""
if len(buf) > 100 {
if len(buf) > 100 && req.Method == http.MethodGet {
h := md5.New()
h.Write(buf)
etag = hex.EncodeToString(h.Sum(nil))
w.Header().Set("Etag", etag)
w.Header().Set("Etag", "\""+etag+"\"")
}

// Check if the client has provided an Etag and if it matches the generated Etag.
Expand Down
43 changes: 30 additions & 13 deletions runtime/handler_test.go
Expand Up @@ -326,48 +326,65 @@ func TestOutgoingEtagIfNoneMatch(t *testing.T) {
for _, tc := range []struct {
msg *pb.SimpleMessage
requestHeaders http.Header
method string
name string
headers http.Header
expectedStatus int
}{
{
msg: &pb.SimpleMessage{Id: "foo"},
name: "small message",
msg: &pb.SimpleMessage{Id: "foo"},
method: http.MethodGet,
name: "small message",
headers: http.Header{
"Content-Length": []string{"12"},
"Content-Type": []string{"application/json"},
},
expectedStatus: http.StatusOK,
},
{
msg: &pb.SimpleMessage{Id: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rhoncus magna ante, sed malesuada nibh vehicula in nec."},
name: "large message",
msg: &pb.SimpleMessage{Id: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rhoncus magna ante, sed malesuada nibh vehicula in nec."},
method: http.MethodGet,
name: "large message",
headers: http.Header{
"Content-Length": []string{"129"},
"Content-Type": []string{"application/json"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
expectedStatus: http.StatusOK,
},
{
msg: &pb.SimpleMessage{Id: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rhoncus magna ante, sed malesuada nibh vehicula in nec."},
msg: &pb.SimpleMessage{Id: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rhoncus magna ante, sed malesuada nibh vehicula in nec."},
method: http.MethodGet,
requestHeaders: http.Header{
"If-None-Match": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
},
name: "large message with If-None-Match header",
headers: http.Header{
"Content-Length": []string{"129"},
"Content-Type": []string{"application/json"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
expectedStatus: http.StatusNotModified,
},
{
msg: &pb.SimpleMessage{Id: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rhoncus magna ante, sed malesuada nibh vehicula in nec."},
method: http.MethodPost,
requestHeaders: http.Header{
"If-None-Match": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
},
name: "large message with If-None-Match header",
headers: http.Header{
"Content-Length": []string{"129"},
"Content-Type": []string{"application/json"},
},
expectedStatus: http.StatusOK,
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

req := httptest.NewRequest("GET", "http://example.com/foo", nil)
req := httptest.NewRequest(tc.method, "http://example.com/foo", nil)
req.Header = tc.requestHeaders
resp := httptest.NewRecorder()

Expand Down Expand Up @@ -448,7 +465,7 @@ func TestOutgoingHeaderMatcher(t *testing.T) {
"Content-Type": []string{"application/json"},
"Grpc-Metadata-Foo": []string{"bar"},
"Grpc-Metadata-Baz": []string{"qux"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
},
{
Expand All @@ -464,7 +481,7 @@ func TestOutgoingHeaderMatcher(t *testing.T) {
"Content-Length": []string{"129"},
"Content-Type": []string{"application/json"},
"Custom-Foo": []string{"bar"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
matcher: func(key string) (string, bool) {
switch key {
Expand Down Expand Up @@ -591,7 +608,7 @@ func TestOutgoingTrailerMatcher(t *testing.T) {
"Transfer-Encoding": []string{"chunked"},
"Content-Type": []string{"application/json"},
"Trailer": []string{"Grpc-Trailer-Foo", "Grpc-Trailer-Baz"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
trailer: http.Header{
"Grpc-Trailer-Foo": []string{"bar"},
Expand All @@ -610,7 +627,7 @@ func TestOutgoingTrailerMatcher(t *testing.T) {
headers: http.Header{
"Content-Length": []string{"129"},
"Content-Type": []string{"application/json"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
},
{
Expand All @@ -629,7 +646,7 @@ func TestOutgoingTrailerMatcher(t *testing.T) {
"Transfer-Encoding": []string{"chunked"},
"Content-Type": []string{"application/json"},
"Trailer": []string{"Custom-Trailer-Foo"},
"Etag": []string{"41bf5d28a47f59b2a649e44f2607b0ea"},
"Etag": []string{"\"41bf5d28a47f59b2a649e44f2607b0ea\""},
},
trailer: http.Header{
"Custom-Trailer-Foo": []string{"bar"},
Expand Down

0 comments on commit 3ab49ed

Please sign in to comment.