This repository has been archived by the owner on Dec 22, 2022. It is now read-only.
forked from prebid/prebid-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Queued request timeout (prebid#1217)
Co-authored-by: Veronika Solovei <veronika.solovei@xandr.com>
- Loading branch information
1 parent
a05a0ec
commit 3c0f25c
Showing
4 changed files
with
183 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package aspects | ||
|
||
import ( | ||
"github.com/julienschmidt/httprouter" | ||
"github.com/prebid/prebid-server/config" | ||
"net/http" | ||
"strconv" | ||
) | ||
|
||
func QueuedRequestTimeout(f httprouter.Handle, reqTimeoutHeaders config.RequestTimeoutHeaders) httprouter.Handle { | ||
|
||
return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) { | ||
|
||
reqTimeInQueue := r.Header.Get(reqTimeoutHeaders.RequestTimeInQueue) | ||
reqTimeout := r.Header.Get(reqTimeoutHeaders.RequestTimeoutInQueue) | ||
|
||
//If request timeout headers are not specified - process request as usual | ||
if reqTimeInQueue == "" || reqTimeout == "" { | ||
f(w, r, params) | ||
return | ||
} | ||
|
||
reqTimeFloat, reqTimeFloatErr := strconv.ParseFloat(reqTimeInQueue, 64) | ||
reqTimeoutFloat, reqTimeoutFloatErr := strconv.ParseFloat(reqTimeout, 64) | ||
|
||
//Return HTTP 500 if request timeout headers are incorrect (wrong format) | ||
if reqTimeFloatErr != nil || reqTimeoutFloatErr != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
w.Write([]byte("Request timeout headers are incorrect (wrong format)")) | ||
return | ||
} | ||
|
||
//Return HTTP 408 if requests stays too long in queue | ||
if reqTimeFloat >= reqTimeoutFloat { | ||
w.WriteHeader(http.StatusRequestTimeout) | ||
w.Write([]byte("Queued request processing time exceeded maximum")) | ||
return | ||
} | ||
|
||
f(w, r, params) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package aspects | ||
|
||
import ( | ||
"github.com/julienschmidt/httprouter" | ||
"github.com/prebid/prebid-server/config" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
const reqTimeInQueueHeaderName = "X-Ngx-Request-Time" | ||
const reqTimeoutHeaderName = "X-Request-Timeout" | ||
|
||
func TestAny(t *testing.T) { | ||
testCases := []struct { | ||
reqTimeInQueue string | ||
reqTimeOut string | ||
setHeaders bool | ||
extectedRespCode int | ||
expectedRespCodeMessage string | ||
expectedRespBody string | ||
expectedRespBodyMessage string | ||
}{ | ||
{ | ||
//TestQueuedRequestTimeoutWithTimeout | ||
reqTimeInQueue: "6", | ||
reqTimeOut: "5", | ||
setHeaders: true, | ||
extectedRespCode: http.StatusRequestTimeout, | ||
expectedRespCodeMessage: "Http response code is incorrect, should be 408", | ||
expectedRespBody: "Queued request processing time exceeded maximum", | ||
expectedRespBodyMessage: "Body should have error message", | ||
}, | ||
{ | ||
//TestQueuedRequestTimeoutNoTimeout | ||
reqTimeInQueue: "0.9", | ||
reqTimeOut: "5", | ||
setHeaders: true, | ||
extectedRespCode: http.StatusOK, | ||
expectedRespCodeMessage: "Http response code is incorrect, should be 200", | ||
expectedRespBody: "Executed", | ||
expectedRespBodyMessage: "Body should be present in response", | ||
}, | ||
{ | ||
//TestQueuedRequestNoHeaders | ||
reqTimeInQueue: "", | ||
reqTimeOut: "", | ||
setHeaders: false, | ||
extectedRespCode: http.StatusOK, | ||
expectedRespCodeMessage: "Http response code is incorrect, should be 200", | ||
expectedRespBody: "Executed", | ||
expectedRespBodyMessage: "Body should be present in response", | ||
}, | ||
{ | ||
//TestQueuedRequestSomeHeaders | ||
reqTimeInQueue: "2", | ||
reqTimeOut: "", | ||
setHeaders: true, | ||
extectedRespCode: http.StatusOK, | ||
expectedRespCodeMessage: "Http response code is incorrect, should be 200", | ||
expectedRespBody: "Executed", | ||
expectedRespBodyMessage: "Body should be present in response", | ||
}, | ||
{ | ||
//TestQueuedRequestAllHeadersIncorrect | ||
reqTimeInQueue: "test1", | ||
reqTimeOut: "test2", | ||
setHeaders: true, | ||
extectedRespCode: http.StatusInternalServerError, | ||
expectedRespCodeMessage: "Http response code is incorrect, should be 400", | ||
expectedRespBody: "Request timeout headers are incorrect (wrong format)", | ||
expectedRespBodyMessage: "Body should have error message", | ||
}, | ||
{ | ||
//TestQueuedRequestSomeHeadersIncorrect | ||
reqTimeInQueue: "test1", | ||
reqTimeOut: "123", | ||
setHeaders: true, | ||
extectedRespCode: http.StatusInternalServerError, | ||
expectedRespCodeMessage: "Http response code is incorrect, should be 400", | ||
expectedRespBody: "Request timeout headers are incorrect (wrong format)", | ||
expectedRespBodyMessage: "Body should have error message", | ||
}, | ||
} | ||
|
||
for _, test := range testCases { | ||
result := ExecuteAspectRequest(t, test.reqTimeInQueue, test.reqTimeOut, test.setHeaders) | ||
assert.Equal(t, test.extectedRespCode, result.Code, test.expectedRespCodeMessage) | ||
assert.Equal(t, test.expectedRespBody, string(result.Body.Bytes()), test.expectedRespBodyMessage) | ||
} | ||
} | ||
|
||
func MockEndpoint() httprouter.Handle { | ||
return httprouter.Handle(MockHandler) | ||
} | ||
|
||
func MockHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { | ||
w.Write([]byte("Executed")) | ||
} | ||
|
||
func ExecuteAspectRequest(t *testing.T, timeInQueue string, reqTimeout string, setHeaders bool) *httptest.ResponseRecorder { | ||
rw := httptest.NewRecorder() | ||
req, err := http.NewRequest("POST", "/test", nil) | ||
if err != nil { | ||
assert.Fail(t, "Unable create mock http request") | ||
} | ||
if setHeaders { | ||
req.Header.Set(reqTimeInQueueHeaderName, timeInQueue) | ||
req.Header.Set(reqTimeoutHeaderName, reqTimeout) | ||
} | ||
|
||
customHeaders := config.RequestTimeoutHeaders{reqTimeInQueueHeaderName, reqTimeoutHeaderName} | ||
|
||
handler := QueuedRequestTimeout(MockEndpoint(), customHeaders) | ||
|
||
r := httprouter.New() | ||
r.POST("/test", handler) | ||
|
||
r.ServeHTTP(rw, req) | ||
|
||
return rw | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters