Skip to content

Commit 822c016

Browse files
fredmaggiowskiDaniele Cinà
authored and
Daniele Cinà
committed
fix(): application/json content type for error responses
1 parent 1c3c59c commit 822c016

10 files changed

+92
-59
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1111

1212
- [JAF-278](https://makeitapp.atlassian.net/browse/JAF-278): optimized query evaluation with precomputed evaluators
1313

14+
### Fixed
15+
16+
- provide `application/json` Content-Type header when sending error responses
17+
1418
## 0.5.0 - 07/02/2022
1519

1620
### Added

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [2021] [Mia-Platform]
189+
Copyright 2021 Mia-Platform
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

handler.go

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func EvaluateRequest(req *http.Request, env config.EnvironmentVariables, w http.
8888
if err != nil {
8989
if errors.Is(err, opatranslator.ErrEmptyQuery) && hasApplicationJSONContentType(req.Header) {
9090
w.WriteHeader(http.StatusOK)
91+
w.Header().Set(ContentTypeHeaderKey, JSONContentTypeHeader)
9192
w.Write([]byte("[]"))
9293
return err
9394
}

handler_test.go

+8-7
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func TestDirectProxyHandler(t *testing.T) {
164164

165165
r, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com:8080/api", body)
166166
assert.Equal(t, err, nil, "Unexpected error")
167-
r.Header.Set("Content-Type", "text/plain")
167+
r.Header.Set(ContentTypeHeaderKey, "text/plain")
168168
w := httptest.NewRecorder()
169169

170170
rbacHandler(w, r)
@@ -211,7 +211,7 @@ func TestDirectProxyHandler(t *testing.T) {
211211
)
212212

213213
r, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://www.example.com:8080/api", body)
214-
r.Header.Set("content-type", "application/json")
214+
r.Header.Set(ContentTypeHeaderKey, "application/json")
215215
assert.Equal(t, err, nil, "Unexpected error")
216216
w := httptest.NewRecorder()
217217

@@ -294,7 +294,7 @@ allow {
294294
assert.Equal(t, err, nil, "Unexpected error")
295295
r.Header.Set("miauserproperties", `{"name":"gianni"}`)
296296
r.Header.Set("examplekey", "value")
297-
r.Header.Set("Content-Type", "text/plain")
297+
r.Header.Set(ContentTypeHeaderKey, "text/plain")
298298
w := httptest.NewRecorder()
299299

300300
rbacHandler(w, r)
@@ -372,7 +372,7 @@ allow {
372372
assert.Equal(t, err, nil, "Unexpected error")
373373
r.Header.Set("miauserproperties", `{"name":"gianni"}`)
374374
r.Header.Set("examplekey", "value")
375-
r.Header.Set("Content-Type", "text/plain")
375+
r.Header.Set(ContentTypeHeaderKey, "text/plain")
376376
w := httptest.NewRecorder()
377377

378378
rbacHandler(w, r)
@@ -427,12 +427,13 @@ allow {
427427

428428
r, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com:8080/api", body)
429429
assert.Equal(t, err, nil, "Unexpected error")
430-
r.Header.Set("Content-Type", "application/json")
430+
r.Header.Set(ContentTypeHeaderKey, "application/json")
431431
w := httptest.NewRecorder()
432432

433433
rbacHandler(w, r)
434434

435435
assert.Equal(t, w.Code, http.StatusOK, "Unexpected status code.")
436+
assert.Equal(t, w.Header().Get(ContentTypeHeaderKey), JSONContentTypeHeader, "Unexpected content type header")
436437
buf, err := ioutil.ReadAll(w.Body)
437438
assert.Equal(t, err, nil, "Unexpected error to read body response")
438439
assert.Equal(t, string(buf), "[]", "Unexpected body response")
@@ -482,7 +483,7 @@ allow {
482483

483484
r, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com:8080/api", body)
484485
assert.Equal(t, err, nil, "Unexpected error")
485-
r.Header.Set("Content-Type", "text/plain")
486+
r.Header.Set(ContentTypeHeaderKey, "text/plain")
486487
w := httptest.NewRecorder()
487488

488489
rbacHandler(w, r)
@@ -561,7 +562,7 @@ allow {
561562
assert.Equal(t, err, nil, "Unexpected error")
562563
r.Header.Set("miauserproperties", `{"name":"gianni"}`)
563564
r.Header.Set("examplekey", "value")
564-
r.Header.Set("Content-Type", "text/plain")
565+
r.Header.Set(ContentTypeHeaderKey, "text/plain")
565566
w := httptest.NewRecorder()
566567

567568
rbacHandler(w, r)

main_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ func TestEntryPoint(t *testing.T) {
571571
req, err := http.NewRequest("GET", "http://localhost:3003/users/", nil)
572572
req.Header.Set("miauserid", "user1")
573573
req.Header.Set("miausergroups", "user1,user2")
574-
req.Header.Set("Content-type", "application/json")
574+
req.Header.Set(ContentTypeHeaderKey, "application/json")
575575
client := &http.Client{}
576576
resp, err := client.Do(req)
577577
require.Equal(t, "user1", resp.Header.Get("someuserheader"))
@@ -615,7 +615,7 @@ func TestEntryPoint(t *testing.T) {
615615
req, err := http.NewRequest("GET", "http://localhost:3003/with-mongo-find-one/some-project", nil)
616616
req.Header.Set("miauserid", "user1")
617617
req.Header.Set("miausergroups", "user1,user2")
618-
req.Header.Set("Content-type", "application/json")
618+
req.Header.Set(ContentTypeHeaderKey, "application/json")
619619
client := &http.Client{}
620620
resp, err := client.Do(req)
621621

@@ -650,7 +650,7 @@ func TestEntryPoint(t *testing.T) {
650650
req, err := http.NewRequest("GET", "http://localhost:3003/with-mongo-find-many/some-project", nil)
651651
req.Header.Set("miauserid", "user1")
652652
req.Header.Set("miausergroups", "user1,user2")
653-
req.Header.Set("Content-type", "application/json")
653+
req.Header.Set(ContentTypeHeaderKey, "application/json")
654654
client := &http.Client{}
655655
resp, err := client.Do(req)
656656

opa_transport.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (t *OPATransport) RoundTrip(req *http.Request) (resp *http.Response, err er
4545
}
4646

4747
if !hasApplicationJSONContentType(resp.Header) {
48-
t.logger.WithField("foundContentType", resp.Header.Get("content-type")).Debug("found content type")
48+
t.logger.WithField("foundContentType", resp.Header.Get(ContentTypeHeaderKey)).Debug("found content type")
4949
t.responseWithError(resp, fmt.Errorf("Content-type is not application/json"), http.StatusInternalServerError)
5050
return resp, nil
5151
}

opaevaluator_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func TestCreateRegoInput(t *testing.T) {
5858

5959
t.Run("ignore nil body on method POST", func(t *testing.T) {
6060
req := httptest.NewRequest(http.MethodPost, "/", nil)
61-
req.Header.Set("Content-Type", "application/json")
61+
req.Header.Set(ContentTypeHeaderKey, "application/json")
6262

6363
inputBytes, err := createRegoQueryInput(req, env, user, nil)
6464
require.Nil(t, err, "Unexpected error")
@@ -70,7 +70,7 @@ func TestCreateRegoInput(t *testing.T) {
7070

7171
for _, method := range acceptedMethods {
7272
req := httptest.NewRequest(method, "/", bytes.NewReader(reqBodyBytes))
73-
req.Header.Set("Content-Type", "application/json")
73+
req.Header.Set(ContentTypeHeaderKey, "application/json")
7474
inputBytes, err := createRegoQueryInput(req, env, user, nil)
7575
require.Nil(t, err, "Unexpected error")
7676

@@ -80,7 +80,7 @@ func TestCreateRegoInput(t *testing.T) {
8080

8181
t.Run("added with content-type specifying charset", func(t *testing.T) {
8282
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(reqBodyBytes))
83-
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
83+
req.Header.Set(ContentTypeHeaderKey, "application/json;charset=UTF-8")
8484
inputBytes, err := createRegoQueryInput(req, env, user, nil)
8585
require.Nil(t, err, "Unexpected error")
8686

@@ -89,14 +89,14 @@ func TestCreateRegoInput(t *testing.T) {
8989

9090
t.Run("reject on method POST but with invalid body", func(t *testing.T) {
9191
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader([]byte("{notajson}")))
92-
req.Header.Set("Content-Type", "application/json")
92+
req.Header.Set(ContentTypeHeaderKey, "application/json")
9393
_, err := createRegoQueryInput(req, env, user, nil)
9494
require.True(t, err != nil)
9595
})
9696

9797
t.Run("ignore body on method POST but with another content type", func(t *testing.T) {
9898
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader([]byte("{notajson}")))
99-
req.Header.Set("Content-Type", "multipart/form-data")
99+
req.Header.Set(ContentTypeHeaderKey, "multipart/form-data")
100100

101101
inputBytes, err := createRegoQueryInput(req, env, user, nil)
102102
require.Nil(t, err, "Unexpected error")

statusroutes.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type StatusResponse struct {
3131
}
3232

3333
func handleStatusRoutes(w http.ResponseWriter, serviceName, serviceVersion string) (*StatusResponse, []byte) {
34-
w.Header().Add("Content-Type", "application/json")
34+
w.Header().Add(ContentTypeHeaderKey, "application/json")
3535
status := StatusResponse{
3636
Status: "OK",
3737
Name: serviceName,

utilities.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import (
88
"git.tools.mia-platform.eu/platform/core/rbac-service/internal/types"
99
)
1010

11+
const ContentTypeHeaderKey = "content-type"
1112
const JSONContentTypeHeader = "application/json"
1213

1314
func hasApplicationJSONContentType(headers http.Header) bool {
14-
return strings.HasPrefix(headers.Get("content-type"), JSONContentTypeHeader)
15+
return strings.HasPrefix(headers.Get(ContentTypeHeaderKey), JSONContentTypeHeader)
1516
}
1617

1718
func failResponse(w http.ResponseWriter, technicalError, businessError string) {
@@ -28,6 +29,8 @@ func failResponseWithCode(w http.ResponseWriter, statusCode int, technicalError,
2829
if err != nil {
2930
return
3031
}
32+
33+
w.Header().Set(ContentTypeHeaderKey, JSONContentTypeHeader)
3134
w.Write(content)
3235
}
3336

utilities_test.go

+64-40
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,75 @@ package main
22

33
import (
44
"encoding/json"
5+
"io/ioutil"
56
"net/http"
7+
"net/http/httptest"
68
"testing"
79

10+
"git.tools.mia-platform.eu/platform/core/rbac-service/internal/types"
11+
812
"gotest.tools/v3/assert"
913
)
1014

11-
func TestUtilities(t *testing.T) {
12-
t.Run("TestUnmarshalHeader", func(t *testing.T) {
13-
userPropertiesHeaderKey := "miauserproperties"
14-
mockedUserProperties := map[string]interface{}{
15-
"my": "other",
16-
"key": []string{"is", "not"},
17-
}
18-
mockedUserPropertiesStringified, err := json.Marshal(mockedUserProperties)
19-
assert.NilError(t, err)
20-
21-
t.Run("header not exists", func(t *testing.T) {
22-
headers := http.Header{}
23-
var userProperties map[string]interface{}
24-
25-
ok, err := unmarshalHeader(headers, userPropertiesHeaderKey, &userProperties)
26-
27-
assert.Assert(t, !ok, "Unmarshal not existing header")
28-
assert.NilError(t, err, "Unexpected error if doesn't exist header")
29-
})
30-
31-
t.Run("header exists but the unmarshalling fails", func(t *testing.T) {
32-
headers := http.Header{}
33-
headers.Set(userPropertiesHeaderKey, string(mockedUserPropertiesStringified))
34-
var userProperties string
35-
36-
ok, err := unmarshalHeader(headers, userPropertiesHeaderKey, &userProperties)
37-
38-
assert.Assert(t, !ok, "Unexpected success during unmarshalling")
39-
assert.ErrorType(t, err, &json.UnmarshalTypeError{}, "Unexpected error on unmarshalling")
40-
})
41-
42-
t.Run("header exists and unmarshalling finishes correctly", func(t *testing.T) {
43-
headers := http.Header{}
44-
headers.Set(userPropertiesHeaderKey, string(mockedUserPropertiesStringified))
45-
var userProperties map[string]interface{}
46-
47-
ok, err := unmarshalHeader(headers, userPropertiesHeaderKey, &userProperties)
48-
assert.Assert(t, ok, "Unexpected failure")
49-
assert.NilError(t, err, "Unexpected error")
50-
})
15+
func TestUnmarshalHeader(t *testing.T) {
16+
userPropertiesHeaderKey := "miauserproperties"
17+
mockedUserProperties := map[string]interface{}{
18+
"my": "other",
19+
"key": []string{"is", "not"},
20+
}
21+
mockedUserPropertiesStringified, err := json.Marshal(mockedUserProperties)
22+
assert.NilError(t, err)
23+
24+
t.Run("header not exists", func(t *testing.T) {
25+
headers := http.Header{}
26+
var userProperties map[string]interface{}
27+
28+
ok, err := unmarshalHeader(headers, userPropertiesHeaderKey, &userProperties)
29+
30+
assert.Assert(t, !ok, "Unmarshal not existing header")
31+
assert.NilError(t, err, "Unexpected error if doesn't exist header")
32+
})
33+
34+
t.Run("header exists but the unmarshalling fails", func(t *testing.T) {
35+
headers := http.Header{}
36+
headers.Set(userPropertiesHeaderKey, string(mockedUserPropertiesStringified))
37+
var userProperties string
38+
39+
ok, err := unmarshalHeader(headers, userPropertiesHeaderKey, &userProperties)
40+
41+
assert.Assert(t, !ok, "Unexpected success during unmarshalling")
42+
assert.ErrorType(t, err, &json.UnmarshalTypeError{}, "Unexpected error on unmarshalling")
43+
})
44+
45+
t.Run("header exists and unmarshalling finishes correctly", func(t *testing.T) {
46+
headers := http.Header{}
47+
headers.Set(userPropertiesHeaderKey, string(mockedUserPropertiesStringified))
48+
var userProperties map[string]interface{}
49+
50+
ok, err := unmarshalHeader(headers, userPropertiesHeaderKey, &userProperties)
51+
assert.Assert(t, ok, "Unexpected failure")
52+
assert.NilError(t, err, "Unexpected error")
53+
})
54+
}
55+
56+
func TestFailResponseWithCode(t *testing.T) {
57+
w := httptest.NewRecorder()
58+
59+
failResponseWithCode(w, http.StatusInternalServerError, "The Error", "The Message")
60+
assert.Equal(t, w.Code, http.StatusInternalServerError)
61+
62+
assert.Equal(t, w.Header().Get(ContentTypeHeaderKey), "application/json")
63+
64+
bodyBytes, err := ioutil.ReadAll(w.Body)
65+
assert.NilError(t, err)
66+
67+
var response types.RequestError
68+
err = json.Unmarshal(bodyBytes, &response)
69+
assert.NilError(t, err)
70+
71+
assert.DeepEqual(t, response, types.RequestError{
72+
StatusCode: http.StatusInternalServerError,
73+
Error: "The Error",
74+
Message: "The Message",
5175
})
5276
}

0 commit comments

Comments
 (0)