Skip to content

Commit ce75200

Browse files
committed
prevent body overwrite with path param
1 parent 98a6467 commit ce75200

File tree

12 files changed

+572
-62
lines changed

12 files changed

+572
-62
lines changed

Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,6 @@ test: proto
138138
go test -short -race ./...
139139
go test -race ./examples/internal/integration -args -network=unix -endpoint=test.sock
140140

141-
test/integration:
142-
go test -race ./examples/internal/integration -args -network=unix -endpoint=test.sock
143-
144141
clean:
145142
find . -type f -name '*.pb.go' -delete
146143
find . -type f -name '*.swagger.json' -delete

examples/internal/clients/echo/api/swagger.yaml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,87 @@ paths:
583583
description: "An unexpected error response."
584584
schema:
585585
$ref: "#/definitions/rpcStatus"
586+
/v1/example/echo_body2/{id}:
587+
put:
588+
tags:
589+
- "EchoService"
590+
summary: "EchoBody method receives a simple message and returns it."
591+
operationId: "EchoService_EchoBody3"
592+
parameters:
593+
- name: "id"
594+
in: "path"
595+
description: "Id represents the message identifier."
596+
required: true
597+
type: "string"
598+
x-exportParamName: "Id"
599+
- in: "body"
600+
name: "resourceId"
601+
required: true
602+
schema:
603+
type: "string"
604+
x-exportParamName: "ResourceId"
605+
- name: "num"
606+
in: "query"
607+
required: false
608+
type: "string"
609+
format: "int64"
610+
x-exportParamName: "Num"
611+
x-optionalDataType: "String"
612+
- name: "lineNum"
613+
in: "query"
614+
required: false
615+
type: "string"
616+
format: "int64"
617+
x-exportParamName: "LineNum"
618+
x-optionalDataType: "String"
619+
- name: "lang"
620+
in: "query"
621+
required: false
622+
type: "string"
623+
x-exportParamName: "Lang"
624+
x-optionalDataType: "String"
625+
- name: "status.progress"
626+
in: "query"
627+
required: false
628+
type: "string"
629+
format: "int64"
630+
x-exportParamName: "StatusProgress"
631+
x-optionalDataType: "String"
632+
- name: "status.note"
633+
in: "query"
634+
required: false
635+
type: "string"
636+
x-exportParamName: "StatusNote"
637+
x-optionalDataType: "String"
638+
- name: "en"
639+
in: "query"
640+
required: false
641+
type: "string"
642+
format: "int64"
643+
x-exportParamName: "En"
644+
x-optionalDataType: "String"
645+
- name: "no.progress"
646+
in: "query"
647+
required: false
648+
type: "string"
649+
format: "int64"
650+
x-exportParamName: "NoProgress"
651+
x-optionalDataType: "String"
652+
- name: "no.note"
653+
in: "query"
654+
required: false
655+
type: "string"
656+
x-exportParamName: "NoNote"
657+
x-optionalDataType: "String"
658+
responses:
659+
200:
660+
description: "A successful response."
661+
schema:
662+
$ref: "#/definitions/examplepbSimpleMessage"
663+
default:
664+
description: "An unexpected error response."
665+
schema:
666+
$ref: "#/definitions/rpcStatus"
586667
/v1/example/echo_delete:
587668
delete:
588669
tags:

examples/internal/clients/echo/api_echo_service.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,153 @@ func (a *EchoServiceApiService) EchoServiceEchoBody2(ctx context.Context, id str
11431143
return localVarReturnValue, localVarHttpResponse, nil
11441144
}
11451145

1146+
/*
1147+
EchoServiceApiService EchoBody method receives a simple message and returns it.
1148+
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
1149+
* @param id Id represents the message identifier.
1150+
* @param resourceId
1151+
* @param optional nil or *EchoServiceEchoBody3Opts - Optional Parameters:
1152+
* @param "Num" (optional.String) -
1153+
* @param "LineNum" (optional.String) -
1154+
* @param "Lang" (optional.String) -
1155+
* @param "StatusProgress" (optional.String) -
1156+
* @param "StatusNote" (optional.String) -
1157+
* @param "En" (optional.String) -
1158+
* @param "NoProgress" (optional.String) -
1159+
* @param "NoNote" (optional.String) -
1160+
1161+
@return ExamplepbSimpleMessage
1162+
*/
1163+
1164+
type EchoServiceEchoBody3Opts struct {
1165+
Num optional.String
1166+
LineNum optional.String
1167+
Lang optional.String
1168+
StatusProgress optional.String
1169+
StatusNote optional.String
1170+
En optional.String
1171+
NoProgress optional.String
1172+
NoNote optional.String
1173+
}
1174+
1175+
func (a *EchoServiceApiService) EchoServiceEchoBody3(ctx context.Context, id string, resourceId string, localVarOptionals *EchoServiceEchoBody3Opts) (ExamplepbSimpleMessage, *http.Response, error) {
1176+
var (
1177+
localVarHttpMethod = strings.ToUpper("Put")
1178+
localVarPostBody interface{}
1179+
localVarFileName string
1180+
localVarFileBytes []byte
1181+
localVarReturnValue ExamplepbSimpleMessage
1182+
)
1183+
1184+
// create path and map variables
1185+
localVarPath := a.client.cfg.BasePath + "/v1/example/echo_body2/{id}"
1186+
localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", fmt.Sprintf("%v", id), -1)
1187+
1188+
localVarHeaderParams := make(map[string]string)
1189+
localVarQueryParams := url.Values{}
1190+
localVarFormParams := url.Values{}
1191+
1192+
if localVarOptionals != nil && localVarOptionals.Num.IsSet() {
1193+
localVarQueryParams.Add("num", parameterToString(localVarOptionals.Num.Value(), ""))
1194+
}
1195+
if localVarOptionals != nil && localVarOptionals.LineNum.IsSet() {
1196+
localVarQueryParams.Add("lineNum", parameterToString(localVarOptionals.LineNum.Value(), ""))
1197+
}
1198+
if localVarOptionals != nil && localVarOptionals.Lang.IsSet() {
1199+
localVarQueryParams.Add("lang", parameterToString(localVarOptionals.Lang.Value(), ""))
1200+
}
1201+
if localVarOptionals != nil && localVarOptionals.StatusProgress.IsSet() {
1202+
localVarQueryParams.Add("status.progress", parameterToString(localVarOptionals.StatusProgress.Value(), ""))
1203+
}
1204+
if localVarOptionals != nil && localVarOptionals.StatusNote.IsSet() {
1205+
localVarQueryParams.Add("status.note", parameterToString(localVarOptionals.StatusNote.Value(), ""))
1206+
}
1207+
if localVarOptionals != nil && localVarOptionals.En.IsSet() {
1208+
localVarQueryParams.Add("en", parameterToString(localVarOptionals.En.Value(), ""))
1209+
}
1210+
if localVarOptionals != nil && localVarOptionals.NoProgress.IsSet() {
1211+
localVarQueryParams.Add("no.progress", parameterToString(localVarOptionals.NoProgress.Value(), ""))
1212+
}
1213+
if localVarOptionals != nil && localVarOptionals.NoNote.IsSet() {
1214+
localVarQueryParams.Add("no.note", parameterToString(localVarOptionals.NoNote.Value(), ""))
1215+
}
1216+
// to determine the Content-Type header
1217+
localVarHttpContentTypes := []string{"application/json"}
1218+
1219+
// set Content-Type header
1220+
localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes)
1221+
if localVarHttpContentType != "" {
1222+
localVarHeaderParams["Content-Type"] = localVarHttpContentType
1223+
}
1224+
1225+
// to determine the Accept header
1226+
localVarHttpHeaderAccepts := []string{"application/json"}
1227+
1228+
// set Accept header
1229+
localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts)
1230+
if localVarHttpHeaderAccept != "" {
1231+
localVarHeaderParams["Accept"] = localVarHttpHeaderAccept
1232+
}
1233+
// body params
1234+
localVarPostBody = &resourceId
1235+
r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes)
1236+
if err != nil {
1237+
return localVarReturnValue, nil, err
1238+
}
1239+
1240+
localVarHttpResponse, err := a.client.callAPI(r)
1241+
if err != nil || localVarHttpResponse == nil {
1242+
return localVarReturnValue, localVarHttpResponse, err
1243+
}
1244+
1245+
localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body)
1246+
localVarHttpResponse.Body.Close()
1247+
if err != nil {
1248+
return localVarReturnValue, localVarHttpResponse, err
1249+
}
1250+
1251+
if localVarHttpResponse.StatusCode < 300 {
1252+
// If we succeed, return the data, otherwise pass on to decode error.
1253+
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type"));
1254+
if err == nil {
1255+
return localVarReturnValue, localVarHttpResponse, err
1256+
}
1257+
}
1258+
1259+
if localVarHttpResponse.StatusCode >= 300 {
1260+
newErr := GenericSwaggerError{
1261+
body: localVarBody,
1262+
error: localVarHttpResponse.Status,
1263+
}
1264+
1265+
if localVarHttpResponse.StatusCode == 200 {
1266+
var v ExamplepbSimpleMessage
1267+
err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type"));
1268+
if err != nil {
1269+
newErr.error = err.Error()
1270+
return localVarReturnValue, localVarHttpResponse, newErr
1271+
}
1272+
newErr.model = v
1273+
return localVarReturnValue, localVarHttpResponse, newErr
1274+
}
1275+
1276+
if localVarHttpResponse.StatusCode == 0 {
1277+
var v RpcStatus
1278+
err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type"));
1279+
if err != nil {
1280+
newErr.error = err.Error()
1281+
return localVarReturnValue, localVarHttpResponse, newErr
1282+
}
1283+
newErr.model = v
1284+
return localVarReturnValue, localVarHttpResponse, newErr
1285+
}
1286+
1287+
return localVarReturnValue, localVarHttpResponse, newErr
1288+
}
1289+
1290+
return localVarReturnValue, localVarHttpResponse, nil
1291+
}
1292+
11461293
/*
11471294
EchoServiceApiService EchoDelete method receives a simple message and returns it.
11481295
* @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().

examples/internal/integration/integration_test.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,13 @@ func TestEcho(t *testing.T) {
4646
testEchoOneof(t, 8088, apiPrefix, "application/json")
4747
testEchoOneof1(t, 8088, apiPrefix, "application/json")
4848
testEchoOneof2(t, 8088, apiPrefix, "application/json")
49-
testEchoResource(t, 8088)
49+
testEchoPathParamOverwrite(t, 8088)
5050
testEchoBody(t, 8088, apiPrefix, true)
5151
testEchoBody(t, 8088, apiPrefix, false)
5252
// Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645
5353
testEchoBody(t, 8089, apiPrefix, true)
5454
testEchoBody(t, 8089, apiPrefix, false)
55+
testEchoBodyParamOverwrite(t, 8088)
5556
})
5657
}
5758
}
@@ -348,7 +349,7 @@ func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string
348349
}
349350
}
350351

351-
func testEchoResource(t *testing.T, port int) {
352+
func testEchoPathParamOverwrite(t *testing.T, port int) {
352353
apiURL := fmt.Sprintf("http://localhost:%d/v1/example/echo/resource/my_resource_id?resourceId=bad_resource_id", port)
353354
resp, err := http.Get(apiURL)
354355
if err != nil {
@@ -378,7 +379,7 @@ func testEchoResource(t *testing.T, port int) {
378379
}
379380

380381
func testEchoBody(t *testing.T, port int, apiPrefix string, useTrailers bool) {
381-
sent := examplepb.UnannotatedSimpleMessage{Id: "example"}
382+
sent := examplepb.UnannotatedSimpleMessage{Id: "example", ResourceId: "my_resource_id"}
382383
payload, err := marshaler.Marshal(&sent)
383384
if err != nil {
384385
t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err)
@@ -443,6 +444,48 @@ func testEchoBody(t *testing.T, port int, apiPrefix string, useTrailers bool) {
443444
}
444445
}
445446

447+
func testEchoBodyParamOverwrite(t *testing.T, port int) {
448+
sent := "my_resource_id"
449+
payload, err := marshaler.Marshal(&sent)
450+
if err != nil {
451+
t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err)
452+
}
453+
454+
apiURL := fmt.Sprintf("http://localhost:%d/v1/example/echo_body2/%s?resourceId=bad_resource_id", port, "my_id")
455+
456+
req, err := http.NewRequest("PUT", apiURL, bytes.NewReader(payload))
457+
if err != nil {
458+
t.Errorf("http.NewRequest() failed with %v; want success", err)
459+
return
460+
}
461+
462+
resp, err := http.DefaultClient.Do(req)
463+
if err != nil {
464+
t.Errorf("client.Do(%v) failed with %v; want success", req, err)
465+
return
466+
}
467+
defer resp.Body.Close()
468+
buf, err := io.ReadAll(resp.Body)
469+
if err != nil {
470+
t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err)
471+
return
472+
}
473+
474+
if got, want := resp.StatusCode, http.StatusOK; got != want {
475+
t.Errorf("resp.StatusCode = %d; want %d", got, want)
476+
t.Logf("%s", buf)
477+
}
478+
479+
var received examplepb.UnannotatedSimpleMessage
480+
if err := marshaler.Unmarshal(buf, &received); err != nil {
481+
t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err)
482+
return
483+
}
484+
if diff := cmp.Diff(&received.ResourceId, &sent, protocmp.Transform()); diff != "" {
485+
t.Errorf(diff)
486+
}
487+
}
488+
446489
func TestABE(t *testing.T) {
447490
if testing.Short() {
448491
t.Skip()

examples/internal/proto/examplepb/a_bit_of_everything.pb.gw.go

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)