2222
2323#include "ngx_http_modsecurity_common.h"
2424
25+ void
26+ ngx_http_modsecurity_request_read (ngx_http_request_t * r )
27+ {
28+ ngx_http_modsecurity_ctx_t * ctx ;
29+
30+ ctx = ngx_http_modsecurity_get_module_ctx (r );
31+
32+ #if defined(nginx_version ) && nginx_version >= 8011
33+ r -> main -> count -- ;
34+ #endif
35+
36+ if (ctx -> waiting_more_body )
37+ {
38+ ctx -> waiting_more_body = 0 ;
39+ r -> write_event_handler = ngx_http_core_run_phases ;
40+ ngx_http_core_run_phases (r );
41+ }
42+ }
43+
44+
2545ngx_int_t
26- ngx_http_modsecurity_rewrite_handler (ngx_http_request_t * r )
46+ ngx_http_modsecurity_access_handler (ngx_http_request_t * r )
2747{
48+
2849 ngx_pool_t * old_pool ;
2950 ngx_http_modsecurity_ctx_t * ctx ;
3051 ngx_http_modsecurity_conf_t * mcf ;
@@ -44,7 +65,7 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
4465 }
4566 */
4667
47- dd ("catching a new _rewrite_ phase handler" );
68+ dd ("catching a new _access_ phase handler" );
4869
4970 ctx = ngx_http_modsecurity_get_module_ctx (r );
5071
@@ -264,6 +285,181 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
264285 }
265286 }
266287
288+ #if 1
289+
290+ /*
291+ * FIXME:
292+ * In order to perform some tests, let's accept everything.
293+ *
294+ if (r->method != NGX_HTTP_GET &&
295+ r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
296+ dd("ModSecurity is not ready to deal with anything different from " \
297+ "POST, GET or HEAD");
298+ return NGX_DECLINED;
299+ }
300+ */
301+
302+ ctx = ngx_http_modsecurity_get_module_ctx (r );
303+
304+ dd ("recovering ctx: %p" , ctx );
267305
306+ if (ctx == NULL )
307+ {
308+ dd ("ctx is null; Nothing we can do, returning an error." );
309+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
310+ }
311+
312+ if (ctx -> request_body_processed ) {
313+ // should we use r->internal or r->filter_finalize?
314+ return NGX_DECLINED ;
315+ }
316+
317+ if (ctx -> intervention_triggered ) {
318+ return NGX_DECLINED ;
319+ }
320+
321+ if (ctx -> waiting_more_body == 1 )
322+ {
323+ dd ("waiting for more data before proceed. / count: %d" ,
324+ r -> main -> count );
325+
326+ return NGX_DONE ;
327+ }
328+
329+ if (ctx -> body_requested == 0 )
330+ {
331+ ngx_int_t rc = NGX_OK ;
332+
333+ ctx -> body_requested = 1 ;
334+
335+ dd ("asking for the request body, if any. Count: %d" ,
336+ r -> main -> count );
337+ /**
338+ * TODO: Check if there is any benefit to use request_body_in_single_buf set to 1.
339+ *
340+ * saw some module using this request_body_in_single_buf
341+ * but not sure what exactly it does, same for the others options below.
342+ *
343+ * r->request_body_in_single_buf = 1;
344+ */
345+ r -> request_body_in_single_buf = 1 ;
346+ r -> request_body_in_persistent_file = 1 ;
347+ if (!r -> request_body_in_file_only ) {
348+ // If the above condition fails, then the flag below will have been
349+ // set correctly elsewhere. We need to set the flag here for other
350+ // conditions (client_body_in_file_only not used but
351+ // client_body_buffer_size is)
352+ r -> request_body_in_clean_file = 1 ;
353+ }
354+
355+ rc = ngx_http_read_client_request_body (r ,
356+ ngx_http_modsecurity_request_read );
357+ if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE ) {
358+ #if (nginx_version < 1002006 ) || \
359+ (nginx_version >= 1003000 && nginx_version < 1003009 )
360+ r -> main -> count -- ;
361+ #endif
362+
363+ return rc ;
364+ }
365+ if (rc == NGX_AGAIN )
366+ {
367+ dd ("nginx is asking us to wait for more data." );
368+
369+ ctx -> waiting_more_body = 1 ;
370+ return NGX_DONE ;
371+ }
372+ }
373+
374+ if (ctx -> waiting_more_body == 0 )
375+ {
376+ int ret = 0 ;
377+ int already_inspected = 0 ;
378+
379+ dd ("request body is ready to be processed" );
380+
381+ r -> write_event_handler = ngx_http_core_run_phases ;
382+
383+ ngx_chain_t * chain = r -> request_body -> bufs ;
384+
385+ /**
386+ * TODO: Speed up the analysis by sending chunk while they arrive.
387+ *
388+ * Notice that we are waiting for the full request body to
389+ * start to process it, it may not be necessary. We may send
390+ * the chunks to ModSecurity while nginx keep calling this
391+ * function.
392+ */
393+
394+ if (r -> request_body -> temp_file != NULL ) {
395+ ngx_str_t file_path = r -> request_body -> temp_file -> file .name ;
396+ const char * file_name = ngx_str_to_char (file_path , r -> pool );
397+ if (file_name == (char * )-1 ) {
398+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
399+ }
400+ /*
401+ * Request body was saved to a file, probably we don't have a
402+ * copy of it in memory.
403+ */
404+ dd ("request body inspection: file -- %s" , file_name );
405+
406+ msc_request_body_from_file (ctx -> modsec_transaction , file_name );
407+
408+ already_inspected = 1 ;
409+ } else {
410+ dd ("inspection request body in memory." );
411+ }
412+
413+ while (chain && !already_inspected )
414+ {
415+ u_char * data = chain -> buf -> pos ;
416+
417+ msc_append_request_body (ctx -> modsec_transaction , data ,
418+ chain -> buf -> last - data );
419+
420+ if (chain -> buf -> last_buf ) {
421+ break ;
422+ }
423+ chain = chain -> next ;
424+
425+ /* XXX: chains are processed one-by-one, maybe worth to pass all chains and then call intervention() ? */
426+
427+ /**
428+ * ModSecurity may perform stream inspection on this buffer,
429+ * it may ask for a intervention in consequence of that.
430+ *
431+ */
432+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 0 );
433+ if (ret > 0 ) {
434+ return ret ;
435+ }
436+ }
437+
438+ /**
439+ * At this point, all the request body was sent to ModSecurity
440+ * and we want to make sure that all the request body inspection
441+ * happened; consequently we have to check if ModSecurity have
442+ * returned any kind of intervention.
443+ */
444+
445+ /* XXX: once more -- is body can be modified ? content-length need to be adjusted ? */
446+
447+ old_pool = ngx_http_modsecurity_pcre_malloc_init (r -> pool );
448+ msc_process_request_body (ctx -> modsec_transaction );
449+ ctx -> request_body_processed = 1 ;
450+ ngx_http_modsecurity_pcre_malloc_done (old_pool );
451+
452+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 0 );
453+ if (r -> error_page ) {
454+ return NGX_DECLINED ;
455+ }
456+ if (ret > 0 ) {
457+ return ret ;
458+ }
459+ }
460+
461+ dd ("Nothing to add on the body inspection, reclaiming a NGX_DECLINED" );
462+ #endif
268463 return NGX_DECLINED ;
269464}
465+
0 commit comments