Skip to content

Commit d9aee41

Browse files
Merge pull request #20 from FireTail-io/ignore-404
Ignore 404
2 parents 935d28b + 1d42c20 commit d9aee41

File tree

5 files changed

+105
-20
lines changed

5 files changed

+105
-20
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ To demonstrate request validation a `POST /proxy/profile/{username}/comment` ope
235235
Making a curl request to `POST /profile/alice/comment` should yield the following result, which validates successfully against the provided appspec:
236236

237237
```bash
238-
curl localhost:8080/proxy/profile/alice/comment -X POST -H "Content-Type: application/json" -d '{"comment":"Hello world!"}
238+
curl localhost:8080/proxy/profile/alice/comment -X POST -H "Content-Type: application/json" -d '{"comment":"Hello world!"}'
239239
```
240240

241241
```json

src/nginx_module/filter_response_body.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ ngx_int_t FiretailResponseBodyFilter(ngx_http_request_t *request, ngx_chain_t *c
9898

9999
validation_result = response_body_validator(
100100
(char *)main_config->FiretailUrl.data, main_config->FiretailUrl.len, (char *)main_config->FiretailApiToken.data,
101-
main_config->FiretailApiToken.len, (char *)ctx->request_body, (int)ctx->request_body_size,
101+
main_config->FiretailApiToken.len, (char *)main_config->FiretailAllowUndefinedRoutes.data,
102+
(int)main_config->FiretailAllowUndefinedRoutes.len, (char *)ctx->request_body, (int)ctx->request_body_size,
102103
(char *)ctx->request_headers_json, (int)ctx->request_headers_json_size, ctx->response_body,
103104
ctx->response_body_size, response_headers_json_string, strlen(response_headers_json_string),
104105
request->unparsed_uri.data, request->unparsed_uri.len, ctx->status_code, request->method_name.data,

src/nginx_module/firetail_module.c

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ static ngx_int_t ngx_http_firetail_handler_internal(ngx_http_request_t *request)
8888
// Update the ctx with the new updated body
8989
ctx->request_body = updated_request_body;
9090

91+
// Get the main config so we can check if we have 404s disabled from the middleware
92+
FiretailMainConfig *main_config = ngx_http_get_module_main_conf(request, ngx_firetail_module);
93+
9194
// run the validation
9295
void *validator_module = dlopen("/etc/nginx/modules/firetail-validator.so", RTLD_LAZY);
9396
if (!validator_module) {
@@ -102,10 +105,10 @@ static ngx_int_t ngx_http_firetail_handler_internal(ngx_http_request_t *request)
102105
}
103106
ngx_log_debug(NGX_LOG_DEBUG, request->connection->log, 0, "Validating request body...");
104107

105-
struct ValidateRequestBody_return validation_result =
106-
request_body_validator(ctx->request_body, ctx->request_body_size, request->unparsed_uri.data,
107-
request->unparsed_uri.len, request->method_name.data, request->method_name.len,
108-
(char *)ctx->request_headers_json, ctx->request_headers_json_size);
108+
struct ValidateRequestBody_return validation_result = request_body_validator(
109+
main_config->FiretailAllowUndefinedRoutes.data, main_config->FiretailAllowUndefinedRoutes.len, ctx->request_body,
110+
ctx->request_body_size, request->unparsed_uri.data, request->unparsed_uri.len, request->method_name.data,
111+
request->method_name.len, (char *)ctx->request_headers_json, ctx->request_headers_json_size);
109112

110113
ngx_log_debug(NGX_LOG_DEBUG, request->connection->log, 0, "Validation request result: %d", validation_result.r0);
111114
ngx_log_debug(NGX_LOG_DEBUG, request->connection->log, 0, "Validating request body: %s", validation_result.r1);
@@ -210,8 +213,8 @@ ngx_http_module_t kFiretailModuleContext = {
210213
NULL // merge location configuration
211214
};
212215

213-
char *EnableFiretailDirectiveInit(ngx_conf_t *configuration_object, ngx_command_t *command_definition,
214-
void *http_main_config) {
216+
char *FiretailApiTokenDirectiveCallback(ngx_conf_t *configuration_object, ngx_command_t *command_definition,
217+
void *http_main_config) {
215218
// TODO: validate the args given to the directive
216219

217220
// Find the firetail_api_key_field given the config pointer & offset in cmd
@@ -225,8 +228,8 @@ char *EnableFiretailDirectiveInit(ngx_conf_t *configuration_object, ngx_command_
225228
return NGX_CONF_OK;
226229
}
227230

228-
char *EnableFiretailUrlInit(ngx_conf_t *configuration_object, ngx_command_t *command_definition,
229-
void *http_main_config) {
231+
char *FiretailUrlDirectiveCallback(ngx_conf_t *configuration_object, ngx_command_t *command_definition,
232+
void *http_main_config) {
230233
// TODO: validate the args given to the directive
231234

232235
// Find the firetail_api_key_field given the config pointer & offset in cmd
@@ -240,16 +243,43 @@ char *EnableFiretailUrlInit(ngx_conf_t *configuration_object, ngx_command_t *com
240243
return NGX_CONF_OK;
241244
}
242245

243-
ngx_command_t kFiretailCommands[3] = {
246+
char *FiretailAllowUndefinedRoutesDirectiveCallback(ngx_conf_t *configuration_object, ngx_command_t *command_definition,
247+
void *http_main_config) {
248+
// Find the firetail_api_key_field given the config pointer & offset in cmd
249+
char *firetail_config = http_main_config;
250+
ngx_str_t *firetail_allow_undefined_routes_field = (ngx_str_t *)(firetail_config + command_definition->offset);
251+
252+
// Get the string value from the configuraion object
253+
ngx_str_t *value = configuration_object->args->elts;
254+
*firetail_allow_undefined_routes_field = value[1];
255+
256+
return NGX_CONF_OK;
257+
}
258+
259+
ngx_command_t kFiretailCommands[4] = {
244260
{// Name of the directive
245261
ngx_string("firetail_api_token"),
246262
// Valid in the main config and takes one arg
247263
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
248264
// A callback function to be called when the directive is found in the
249265
// configuration
250-
EnableFiretailDirectiveInit, NGX_HTTP_MAIN_CONF_OFFSET, offsetof(FiretailMainConfig, FiretailApiToken), NULL},
251-
{ngx_string("firetail_url"), NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1, EnableFiretailUrlInit, NGX_HTTP_MAIN_CONF_OFFSET,
252-
offsetof(FiretailMainConfig, FiretailUrl), NULL},
266+
FiretailApiTokenDirectiveCallback, NGX_HTTP_MAIN_CONF_OFFSET, offsetof(FiretailMainConfig, FiretailApiToken),
267+
NULL},
268+
{// Name of the directive
269+
ngx_string("firetail_url"),
270+
// Valid in the main config and takes one arg
271+
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
272+
// A callback function to be called when the directive is found in the
273+
// configuration
274+
FiretailUrlDirectiveCallback, NGX_HTTP_MAIN_CONF_OFFSET, offsetof(FiretailMainConfig, FiretailUrl), NULL},
275+
{// Name of the directive
276+
ngx_string("firetail_allow_undefined_routes"),
277+
// Valid in the main config and takes one arg
278+
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
279+
// A callback function to be called when the directive is found in the
280+
// configuration
281+
FiretailAllowUndefinedRoutesDirectiveCallback, NGX_HTTP_MAIN_CONF_OFFSET,
282+
offsetof(FiretailMainConfig, FiretailAllowUndefinedRoutes), NULL},
253283
ngx_null_command};
254284

255285
ngx_module_t ngx_firetail_module = {NGX_MODULE_V1,

src/nginx_module/firetail_module.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,21 @@ struct ValidateResponseBody_return {
1010
char* r1;
1111
};
1212
typedef struct ValidateResponseBody_return (*ValidateResponseBody)(char*, int, char*, int, char*, int, char*, int,
13-
void*, int, char*, int, void*, int, int, void*, int);
13+
char*, int, void*, int, char*, int, void*, int, int,
14+
void*, int);
1415

1516
struct ValidateRequestBody_return {
1617
int r0;
1718
char* r1;
1819
};
19-
typedef struct ValidateRequestBody_return (*ValidateRequestBody)(void*, int, void*, int, void*, int, void*, int);
20+
typedef struct ValidateRequestBody_return (*ValidateRequestBody)(void*, int, void*, int, void*, int, void*, int, void*,
21+
int);
2022

2123
// This config struct will hold our API key
2224
typedef struct {
2325
ngx_str_t FiretailApiToken; // TODO: this should probably be a *ngx_str_t
2426
ngx_str_t FiretailUrl;
27+
ngx_str_t FiretailAllowUndefinedRoutes;
2528
} FiretailMainConfig;
2629

2730
// The header and body filters of the filter that was added just before ours.

src/validator/main.go

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ import (
1616
)
1717
import (
1818
"net/http"
19+
"strconv"
1920
)
2021

2122
var firetailRequestMiddleware func(next http.Handler) http.Handler
2223
var firetailResponseMiddleware func(next http.Handler) http.Handler
2324

2425
//export ValidateRequestBody
2526
func ValidateRequestBody(
27+
allowUndefinedRoutes unsafe.Pointer, allowUndefinedRoutesLength C.int,
2628
bodyCharPtr unsafe.Pointer, bodyLength C.int,
2729
pathCharPtr unsafe.Pointer, pathLength C.int,
2830
methodCharPtr unsafe.Pointer, methodLength C.int,
2931
headersCharPtr unsafe.Pointer, headersLength C.int,
3032
) (C.int, *C.char) {
33+
log.Println("✅ Validating request body...")
3134
// Create the middleware if it hasn't already been done
3235
if firetailRequestMiddleware == nil {
3336
var err error
@@ -78,11 +81,35 @@ func ValidateRequestBody(
7881
// Serve the request to the middlware
7982
myMiddleware.ServeHTTP(localResponseWriter, mockRequest)
8083

81-
// If the body differs after being passed through the middleware then we'll just infer it doesn't match the spec
84+
// Get the response body from the middleware
8285
middlewareResponseBodyBytes, err := io.ReadAll(localResponseWriter.Body)
8386
responseCString := C.CString(string(middlewareResponseBodyBytes))
87+
if err != nil {
88+
return 1, responseCString // return 1 is error by convention
89+
}
90+
91+
// If the body differs after being passed through the middleware then we'll just infer it doesn't match the spec
92+
if string(middlewareResponseBodyBytes) != string(placeholderResponse) {
93+
// If allowing undefined routes, then we need to check if the response is a 404 from the middleware. If it is,
94+
// we return success.
95+
allowUndefinedRoutesBool, err := strconv.ParseBool(string(C.GoBytes(allowUndefinedRoutes, allowUndefinedRoutesLength)))
96+
if err != nil {
97+
return 1, responseCString // return 1 is error by convention
98+
}
99+
if allowUndefinedRoutesBool {
100+
response_json := map[string]interface{}{}
101+
if err := json.Unmarshal(middlewareResponseBodyBytes, &response_json); err != nil {
102+
return 1, responseCString // return 1 is error by convention
103+
}
104+
if code, ok := response_json["code"]; ok {
105+
if code_float, ok := code.(float64); ok {
106+
if code_float == 404 {
107+
return 0, responseCString // return 0 is success by convention
108+
}
109+
}
110+
}
84111

85-
if err != nil || string(middlewareResponseBodyBytes) != string(placeholderResponse) {
112+
}
86113
return 1, responseCString // return 1 is error by convention
87114
}
88115

@@ -94,6 +121,7 @@ func ValidateResponseBody(
94121
urlCharPtr unsafe.Pointer,
95122
urlLength C.int,
96123
tokenCharPtr unsafe.Pointer, tokenLength C.int,
124+
allowUndefinedRoutes unsafe.Pointer, allowUndefinedRoutesLength C.int,
97125
reqBodyCharPtr unsafe.Pointer, reqBodyLength C.int,
98126
reqHeadersJsonCharPtr unsafe.Pointer, reqHeadersJsonLength C.int,
99127
resBodyCharPtr unsafe.Pointer, resBodyLength C.int,
@@ -170,12 +198,35 @@ func ValidateResponseBody(
170198
// match the spec
171199
middlewareResponseBodyBytes, err := io.ReadAll(localResponseWriter.Body)
172200
responseCString := C.CString(string(middlewareResponseBodyBytes))
201+
if err != nil {
202+
return 1, responseCString // return 1 is error by convention
203+
}
173204

174-
if err != nil || localResponseWriter.Code != int(statusCode) || string(middlewareResponseBodyBytes) != string(resBodySlice) {
205+
// If the body differs after being passed through the middleware then we'll just infer it doesn't match the spec
206+
if string(middlewareResponseBodyBytes) != string(resBodySlice) || localResponseWriter.Code != int(statusCode) {
207+
// If allowing undefined routes, then we need to check if the response is a 404 from the middleware. If it is,
208+
// we return success.
209+
allowUndefinedRoutesBool, err := strconv.ParseBool(string(C.GoBytes(allowUndefinedRoutes, allowUndefinedRoutesLength)))
210+
if err != nil {
211+
return 1, responseCString // return 1 is error by convention
212+
}
213+
if allowUndefinedRoutesBool {
214+
response_json := map[string]interface{}{}
215+
if err := json.Unmarshal(middlewareResponseBodyBytes, &response_json); err != nil {
216+
return 1, responseCString // return 1 is error by convention
217+
}
218+
if code, ok := response_json["code"]; ok {
219+
if code_float, ok := code.(float64); ok {
220+
if code_float == 404 {
221+
return 0, C.CString(string(resBodySlice)) // return 0 is success by convention
222+
}
223+
}
224+
}
225+
}
175226
return 1, responseCString // return 1 is error by convention
176227
}
177228

178-
return 0, responseCString // return 0 is success by convention
229+
return 0, C.CString(string(resBodySlice)) // return 0 is success by convention
179230
}
180231

181232
func main() {}

0 commit comments

Comments
 (0)