Skip to content

Commit

Permalink
evaluate accepted content type
Browse files Browse the repository at this point in the history
  • Loading branch information
hgiasac committed Dec 13, 2024
1 parent 66499a3 commit 21daf45
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 6 deletions.
6 changes: 3 additions & 3 deletions connector/connector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func TestHTTPConnector_authentication(t *testing.T) {
assertHTTPResponse(t, res, http.StatusOK, schema.ExplainResponse{
Details: schema.ExplainResponseDetails{
"url": server.URL + "/pet",
"headers": `{"Api_key":["ran*******(14)"],"Content-Type":["application/json"]}`,
"headers": `{"Accept":["application/json"],"Api_key":["ran*******(14)"],"Content-Type":["application/json"]}`,
},
})
})
Expand Down Expand Up @@ -201,7 +201,7 @@ func TestHTTPConnector_authentication(t *testing.T) {
assertHTTPResponse(t, res, http.StatusOK, schema.ExplainResponse{
Details: schema.ExplainResponseDetails{
"url": server.URL + "/pet",
"headers": `{"Api_key":["ran*******(14)"],"Content-Type":["application/json"]}`,
"headers": `{"Accept":["application/json"],"Api_key":["ran*******(14)"],"Content-Type":["application/json"]}`,
"body": `{"name":"pet"}`,
},
})
Expand Down Expand Up @@ -253,7 +253,7 @@ func TestHTTPConnector_authentication(t *testing.T) {
assertHTTPResponse(t, res, http.StatusOK, schema.ExplainResponse{
Details: schema.ExplainResponseDetails{
"url": server.URL + "/pet/findByStatus?status=available",
"headers": `{"Authorization":["Bearer ran*******(19)"],"Content-Type":["application/json"],"X-Custom-Header":["This is a test"]}`,
"headers": `{"Accept":["application/json"],"Authorization":["Bearer ran*******(19)"],"Content-Type":["application/json"],"X-Custom-Header":["This is a test"]}`,
},
})
})
Expand Down
2 changes: 1 addition & 1 deletion connector/internal/request_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (c *RequestBuilder) Build() (*RetryableRequest, error) {
}

if rawRequest.Response.ContentType != "" && request.Headers.Get(acceptHeader) == "" {
request.Headers.Set(acceptHeader, rawRequest.Response.ContentType)
request.Headers.Set(acceptHeader, evalAcceptContentType(rawRequest.Response.ContentType))
}

if rawRequest.RuntimeSettings != nil {
Expand Down
60 changes: 60 additions & 0 deletions connector/internal/request_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,57 @@ func TestEvalURLAndHeaderParameters(t *testing.T) {
}
}

func TestEvalURLAndHeaderParametersOAS2(t *testing.T) {
testCases := []struct {
name string
rawArguments string
expectedURL string
errorMsg string
headers map[string]string
}{
{
name: "get_subject",
rawArguments: `{
"identifier": "thesauri/material/AAT.11914"
}`,
expectedURL: "/id/thesauri/material/AAT.11914",
},
}

ndcSchema := createMockSchemaOAS2(t)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var info *rest.OperationInfo
for key, f := range ndcSchema.Functions {
if key == tc.name {
info = &f
break
}
}
var arguments map[string]any
assert.NilError(t, json.Unmarshal([]byte(tc.rawArguments), &arguments))

builder := RequestBuilder{
Schema: ndcSchema,
Operation: info,
Arguments: arguments,
}
result, headers, err := builder.evalURLAndHeaderParameters()
if tc.errorMsg != "" {
assert.ErrorContains(t, err, tc.errorMsg)
} else {
assert.NilError(t, err)
decodedValue, err := url.QueryUnescape(result.String())
assert.NilError(t, err)
assert.Equal(t, tc.expectedURL, decodedValue)
for k, v := range tc.headers {
assert.Equal(t, v, headers.Get(k))
}
}
})
}
}

func createMockSchema(t *testing.T) *rest.NDCHttpSchema {
var ndcSchema rest.NDCHttpSchema
rawSchemaBytes, err := os.ReadFile("../../ndc-http-schema/openapi/testdata/petstore3/expected.json")
Expand All @@ -85,3 +136,12 @@ func createMockSchema(t *testing.T) *rest.NDCHttpSchema {

return &ndcSchema
}

func createMockSchemaOAS2(t *testing.T) *rest.NDCHttpSchema {
var ndcSchema rest.NDCHttpSchema
rawSchemaBytes, err := os.ReadFile("../../ndc-http-schema/openapi/testdata/petstore2/expected.json")
assert.NilError(t, err)
assert.NilError(t, json.Unmarshal(rawSchemaBytes, &ndcSchema))

return &ndcSchema
}
1 change: 0 additions & 1 deletion connector/internal/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ type HTTPOptions struct {
Servers []string `json:"serverIds" yaml:"serverIds"`
Parallel bool `json:"parallel" yaml:"parallel"`

Explain bool `json:"-" yaml:"-"`
Distributed bool `json:"-" yaml:"-"`
Concurrency uint `json:"-" yaml:"-"`
}
Expand Down
18 changes: 17 additions & 1 deletion connector/internal/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,29 @@ import (
"go.opentelemetry.io/otel/trace"
)

// IsSensitiveHeader checks if the header name is sensitive.
func IsSensitiveHeader(name string) bool {
return sensitiveHeaderRegex.MatchString(strings.ToLower(name))
}

func evalAcceptContentType(contentType string) string {
switch {
case strings.HasPrefix(contentType, "image/"):
return "image/*"
case strings.HasPrefix(contentType, "video/"):
return "video/*"
default:
return contentType
}
}

func setHeaderAttributes(span trace.Span, prefix string, httpHeaders http.Header) {
for key, headers := range httpHeaders {
if len(headers) == 0 {
continue
}
values := headers
if sensitiveHeaderRegex.MatchString(strings.ToLower(key)) {
if IsSensitiveHeader(key) {
values = make([]string, len(headers))
for i, header := range headers {
values[i] = utils.MaskString(header)
Expand Down
13 changes: 13 additions & 0 deletions connector/internal/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package internal

import (
"testing"

"gotest.tools/v3/assert"
)

func TestEvalAcceptContentType(t *testing.T) {
assert.Equal(t, "image/*", evalAcceptContentType("image/jpeg"))
assert.Equal(t, "video/*", evalAcceptContentType("video/mp4"))
assert.Equal(t, "application/json", evalAcceptContentType("application/json"))
}
8 changes: 8 additions & 0 deletions connector/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/hasura/ndc-http/connector/internal"
"github.com/hasura/ndc-http/ndc-http-schema/configuration"
restUtils "github.com/hasura/ndc-http/ndc-http-schema/utils"
"github.com/hasura/ndc-sdk-go/schema"
"github.com/hasura/ndc-sdk-go/utils"
"go.opentelemetry.io/otel/codes"
Expand Down Expand Up @@ -175,6 +176,13 @@ func (c *HTTPConnector) serializeExplainResponse(ctx context.Context, requests *
}
defer cancel()

// mask sensitive forwarded headers if exists
for key := range req.Header {
if internal.IsSensitiveHeader(key) {
req.Header.Set(key, restUtils.MaskString(req.Header.Get(key)))
}
}

c.upstreams.InjectMockRequestSettings(req, requests.Schema.Name, httpRequest.RawRequest.Security)

explainResp.Details["url"] = req.URL.String()
Expand Down
32 changes: 32 additions & 0 deletions ndc-http-schema/openapi/testdata/petstore2/expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,38 @@
"type": "named"
}
},
"get_subject": {
"request": {
"url": "/id/{identifier}",
"method": "get",
"response": {
"contentType": "application/json"
}
},
"arguments": {
"identifier": {
"description": "The identifier path of the `subject` you're looking for",
"type": {
"name": "String",
"type": "named"
},
"http": {
"name": "identifier",
"in": "path",
"schema": {
"type": [
"string"
]
}
}
}
},
"description": "Explore details about a given subject node",
"result_type": {
"name": "JSON",
"type": "named"
}
},
"listOAuth2Clients": {
"request": {
"url": "/clients",
Expand Down
17 changes: 17 additions & 0 deletions ndc-http-schema/openapi/testdata/petstore2/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,23 @@
"type": "named"
}
},
{
"arguments": {
"identifier": {
"description": "The identifier path of the `subject` you're looking for",
"type": {
"name": "String",
"type": "named"
}
}
},
"description": "Explore details about a given subject node",
"name": "get_subject",
"result_type": {
"name": "JSON",
"type": "named"
}
},
{
"arguments": {
"client_name": {
Expand Down
24 changes: 24 additions & 0 deletions ndc-http-schema/openapi/testdata/petstore2/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,30 @@
}
]
}
},
"/id/{identifier}": {
"get": {
"operationId": "get subject",
"parameters": [
{
"description": "The identifier path of the `subject` you're looking for\n",
"in": "path",
"name": "identifier",
"required": true,
"type": "string"
}
],
"produces": ["text/html", "application/ld+json", "application/json"],
"responses": {
"200": {
"description": "`subject` found\n"
},
"404": {
"description": "`subject` not found\n"
}
},
"summary": "Explore details about a given subject node"
}
}
},
"securityDefinitions": {
Expand Down

0 comments on commit 21daf45

Please sign in to comment.