I am trying to write a nginx module which will filter out GET requests for any resource whose size is greater than say 1000KB. I followed the tutorials, the module compiles and installs fine. However I think the module is not getting invoked on an incoming request. The module consists of header and body filters which will check the outgoing requests content size, if greater than 1000KB it will clear the response body and redirect to a different port which I will be throttling in firewall. I used some logging statements but I cannot see any thing in logs because of which I think its not getting invoked. I am attaching full source
#include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> typedef struct { ngx_str_t download_filter; } ngx_http_download_conf_t; static void *ngx_http_download_create_conf(ngx_conf_t *cf); static ngx_int_t ngx_http_download_filter_init(ngx_conf_t *cf); static ngx_int_t ngx_http_download_header_filter(ngx_http_request_t *r); static ngx_int_t ngx_http_download_body_filter(ngx_http_request_t *r, ngx_chain_t *in); //static char *ngx_http_download_module( ngx_conf_t *cf, ngx_command_t *cmd, void *conf); //static u_char ngx_download_filter_module[] = "download filter"; static ngx_command_t ngx_download_filter_module_commands[] = { { ngx_string("download_filter"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_download_conf_t, download_filter), NULL }, ngx_null_command }; static ngx_http_module_t ngx_http_download_filter_module_ctx = { NULL, /* preconfiguration */ ngx_http_download_filter_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_download_create_conf, /* create location configuration */ NULL /* merge location configuration */ }; ngx_module_t ngx_http_download_filter_module = { NGX_MODULE_V1, &ngx_http_download_filter_module_ctx, /* module context */ ngx_download_filter_module_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING }; static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t ngx_http_download_filter_init(ngx_conf_t *cf) { printf("hello world: inside init function\n"); ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_download_header_filter; ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_download_body_filter; return NGX_OK; } static ngx_int_t ngx_http_download_header_filter( ngx_http_request_t *r) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "inside the header filter"); printf("inside header filter hello world\n"); ngx_str_t new_location= ngx_string("http://localhost:5000/flake.jpg"); if ( r->headers_out.content_length_n > 1000 && r->headers_out.status == NGX_HTTP_OK ) { r->headers_out.status = NGX_HTTP_MOVED_TEMPORARILY; r->headers_out.content_type.len = 0; r->headers_out.location->value.data = new_location.data; r->headers_out.location->value.len = new_location.len; ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); } r->headers_out.status = NGX_HTTP_MOVED_TEMPORARILY; return ngx_http_next_header_filter(r); } static ngx_int_t ngx_http_download_body_filter ( ngx_http_request_t *r, ngx_chain_t *in ) { if ( r->headers_out.content_length_n > 1000 && r->headers_out.status == NGX_HTTP_OK ) { r->discard_body = 0; return ngx_http_next_body_filter(r, in); } return ngx_http_next_body_filter(r, in); } static void * ngx_http_download_create_conf(ngx_conf_t *cf) { ngx_http_download_conf_t *conf; conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_download_conf_t)); if (conf == NULL) { return NULL; } /* * set by ngx_pcalloc(): * * conf->before_body = { 0, NULL }; * conf->after_body = { 0, NULL }; * conf->types = { NULL }; * conf->types_keys = NULL; */ return conf; }
My nginx conf uses the download_filter
directive. Following is a snippet.
http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /tmp/log/access.log main; error_log /tmp/log/error.log info; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; download_filter;
The module initializes as I see "hello world, inside init function" string when I start nginx.
Anything that I am missing which is stopping my filters? I am not using a handler here as I do not need to serve anything and let nginx do its work and use filters right before it is being served. Do I need a handler? If yes how can I make a handler which just serves the content and let filters do its work.