diff --git a/cmd/collector/app/zipkin/http_handler.go b/cmd/collector/app/zipkin/http_handler.go index 4b7bb2f584d..0d15e4b7c11 100644 --- a/cmd/collector/app/zipkin/http_handler.go +++ b/cmd/collector/app/zipkin/http_handler.go @@ -119,6 +119,12 @@ func (aH *APIHandler) saveSpansV2(w http.ResponseWriter, r *http.Request) { return } + contentType := r.Header.Get("Content-Type") + if contentType != "application/json" { + http.Error(w, "Unsupported Content-Type", http.StatusBadRequest) + return + } + var spans models.ListOfSpans if err = swag.ReadJSON(bodyBytes, &spans); err != nil { http.Error(w, fmt.Sprintf(app.UnableToReadBodyErrFormat, err), http.StatusBadRequest) diff --git a/cmd/collector/app/zipkin/http_handler_test.go b/cmd/collector/app/zipkin/http_handler_test.go index c2de3fed706..62fd1a23107 100644 --- a/cmd/collector/app/zipkin/http_handler_test.go +++ b/cmd/collector/app/zipkin/http_handler_test.go @@ -103,20 +103,13 @@ func waitForSpans(t *testing.T, handler *mockZipkinHandler, expecting int) { } func TestThriftFormat(t *testing.T) { - server, handler := initializeTestServer(nil) + server, _ := initializeTestServer(nil) defer server.Close() - bodyBytes := zipkinSerialize([]*zipkincore.Span{{}}) statusCode, resBodyStr, err := postBytes(server.URL+`/api/v1/spans`, bodyBytes, createHeader("application/x-thrift")) assert.NoError(t, err) assert.EqualValues(t, http.StatusAccepted, statusCode) assert.EqualValues(t, "", resBodyStr) - - handler.zipkinSpansHandler.(*mockZipkinHandler).err = fmt.Errorf("Bad times ahead") - statusCode, resBodyStr, err = postBytes(server.URL+`/api/v1/spans`, bodyBytes, createHeader("application/x-thrift")) - assert.NoError(t, err) - assert.EqualValues(t, http.StatusInternalServerError, statusCode) - assert.EqualValues(t, "Cannot submit Zipkin batch: Bad times ahead\n", resBodyStr) } func TestJsonFormat(t *testing.T) { @@ -229,9 +222,52 @@ func TestCannotReadBodyFromRequest(t *testing.T) { req, err := http.NewRequest(http.MethodPost, "whatever", &errReader{}) assert.NoError(t, err) rw := dummyResponseWriter{} - handler.saveSpans(&rw, req) - assert.EqualValues(t, http.StatusInternalServerError, rw.myStatusCode) - assert.EqualValues(t, "Unable to process request body: Simulated error reading body\n", rw.myBody) + + tests := []struct { + handler func(w http.ResponseWriter, r *http.Request) + }{ + {handler: handler.saveSpans}, + {handler: handler.saveSpansV2}, + } + for _, test := range tests { + test.handler(&rw, req) + assert.EqualValues(t, http.StatusInternalServerError, rw.myStatusCode) + assert.EqualValues(t, "Unable to process request body: Simulated error reading body\n", rw.myBody) + } +} + +func TestSaveSpansV2(t *testing.T) { + server, handler := initializeTestServer(nil) + defer server.Close() + tests := []struct { + body []byte + resBody string + code int + headers map[string]string + }{ + {body: []byte("[]"), code: http.StatusAccepted}, + {body: gzipEncode([]byte("[]")), code: http.StatusAccepted, headers: map[string]string{"Content-Encoding": "gzip"}}, + {body: []byte("[]"), code: http.StatusBadRequest, headers: map[string]string{"Content-Type": "text/html"}, resBody: "Unsupported Content-Type\n"}, + {body: []byte("[]"), code: http.StatusBadRequest, headers: map[string]string{"Content-Encoding": "gzip"}, resBody: "Unable to process request body: unexpected EOF\n"}, + {body: []byte("not good"), code: http.StatusBadRequest, resBody: "Unable to process request body: invalid character 'o' in literal null (expecting 'u')\n"}, + {body: []byte("[{}]"), code: http.StatusBadRequest, resBody: "Unable to process request body: validation failure list:\nid in body is required\ntraceId in body is required\n"}, + {body: []byte(`[{"id":"1111111111111111", "traceId":"1111111111111111", "localEndpoint": {"ipv4": "A"}}]`), code: http.StatusBadRequest, resBody: "Unable to process request body: wrong ipv4\n"}, + } + for _, test := range tests { + h := createHeader("application/json") + for k, v := range test.headers { + h.Set(k, v) + } + statusCode, resBody, err := postBytes(server.URL+`/api/v2/spans`, test.body, h) + require.NoError(t, err) + assert.EqualValues(t, test.code, statusCode) + assert.EqualValues(t, test.resBody, resBody) + } + handler.zipkinSpansHandler.(*mockZipkinHandler).err = fmt.Errorf("Bad times ahead") + statusCode, resBody, err := postBytes(server.URL+`/api/v2/spans`, []byte(`[{"id":"1111111111111111", "traceId":"1111111111111111"}]`), createHeader("application/json")) + require.NoError(t, err) + assert.EqualValues(t, http.StatusInternalServerError, statusCode) + assert.EqualValues(t, "Cannot submit Zipkin batch: Bad times ahead\n", resBody) } type errReader struct{} diff --git a/cmd/collector/app/zipkin/jsonv2_test.go b/cmd/collector/app/zipkin/jsonv2_test.go index 29605692118..1f94d2e6b37 100644 --- a/cmd/collector/app/zipkin/jsonv2_test.go +++ b/cmd/collector/app/zipkin/jsonv2_test.go @@ -36,16 +36,16 @@ func TestFixtures(t *testing.T) { var pid int64 = 1 var ts int64 = 1 var d int64 = 10 - localE := &zipkincore.Endpoint{ServiceName:"foo", Ipv4: 170594602} - remoteE := &zipkincore.Endpoint{ServiceName:"bar", Ipv4: 170594603} - tSpan := &zipkincore.Span{ID: 2, TraceID: 1, ParentID: &pid, Name:"foo", Debug: true, Duration: &d, Timestamp: &ts, - Annotations:[]*zipkincore.Annotation{ - {Value:"foo", Timestamp:1, Host:localE}, - {Value: zipkincore.CLIENT_SEND, Timestamp: ts, Host:localE}, - {Value: zipkincore.CLIENT_RECV, Timestamp: ts+d, Host: localE}}, - BinaryAnnotations:[]*zipkincore.BinaryAnnotation{ - {Key:"foo", Value:[]byte("bar"), Host:localE, AnnotationType:zipkincore.AnnotationType_STRING}, - {Key:zipkincore.SERVER_ADDR, Host:remoteE, AnnotationType:zipkincore.AnnotationType_BOOL}}} + localE := &zipkincore.Endpoint{ServiceName: "foo", Ipv4: 170594602} + remoteE := &zipkincore.Endpoint{ServiceName: "bar", Ipv4: 170594603} + tSpan := &zipkincore.Span{ID: 2, TraceID: 1, ParentID: &pid, Name: "foo", Debug: true, Duration: &d, Timestamp: &ts, + Annotations: []*zipkincore.Annotation{ + {Value: "foo", Timestamp: 1, Host: localE}, + {Value: zipkincore.CLIENT_SEND, Timestamp: ts, Host: localE}, + {Value: zipkincore.CLIENT_RECV, Timestamp: ts + d, Host: localE}}, + BinaryAnnotations: []*zipkincore.BinaryAnnotation{ + {Key: "foo", Value: []byte("bar"), Host: localE, AnnotationType: zipkincore.AnnotationType_STRING}, + {Key: zipkincore.SERVER_ADDR, Host: remoteE, AnnotationType: zipkincore.AnnotationType_BOOL}}} assert.Equal(t, tSpans[0], tSpan) }