From ada5f28b88826428c7712c173d28c4fa5b4ab133 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Tue, 17 Mar 2009 19:20:44 +0300 Subject: [PATCH 1/3] Add size of empty gif Cc: catap@catap.ru `ngx_http_empty_gif_module' is a simplpe module for send 1x1 transparent gif. Since the gif can contain any number of garbages data after the header, I added a directive `empty_gif_size' that sets the size of "size" for gif 1x1 transparent gif. --- src/http/modules/ngx_http_empty_gif_module.c | 162 ++++++++++++++++++++++---- 1 files changed, 137 insertions(+), 25 deletions(-) diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c index 20e4413c086bc9cce0c54b591edc3b5324cf591b..2abbc19ceb9991be85ebd2236d106c4800ae6508 100644 --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -8,9 +8,22 @@ #include +typedef struct { + ngx_str_t fake; +} ngx_http_empty_gif_loc_conf_t; + + static char *ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void *ngx_http_empty_gif_create_local_conf(ngx_conf_t *cf); +static char *ngx_http_empty_gif_merge_local_conf(ngx_conf_t *cf, + void *parent, void *child); + +static char *ngx_http_empty_gif_size(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + static ngx_command_t ngx_http_empty_gif_commands[] = { { ngx_string("empty_gif"), @@ -20,6 +33,13 @@ static ngx_command_t ngx_http_empty_gif_commands[] = { 0, NULL }, + { ngx_string("empty_gif_size"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_empty_gif_size, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_empty_gif_loc_conf_t, fake), + NULL }, + ngx_null_command }; @@ -75,32 +95,32 @@ static u_char ngx_empty_gif[] = { static ngx_http_module_t ngx_http_empty_gif_module_ctx = { - NULL, /* preconfiguration */ - NULL, /* postconfiguration */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ - NULL, /* create main configuration */ - NULL, /* init main configuration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ - NULL, /* create location configuration */ - NULL /* merge location configuration */ + ngx_http_empty_gif_create_local_conf, /* create location configuration */ + ngx_http_empty_gif_merge_local_conf /* merge location configuration */ }; ngx_module_t ngx_http_empty_gif_module = { NGX_MODULE_V1, - &ngx_http_empty_gif_module_ctx, /* module context */ - ngx_http_empty_gif_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_http_empty_gif_module_ctx, /* module context */ + ngx_http_empty_gif_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 }; @@ -108,9 +128,12 @@ ngx_module_t ngx_http_empty_gif_module = { static ngx_int_t ngx_http_empty_gif_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t out; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out[2]; + ngx_http_empty_gif_loc_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_empty_gif_module); if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; @@ -129,6 +152,9 @@ ngx_http_empty_gif_handler(ngx_http_request_t *r) if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = sizeof(ngx_empty_gif); + if (conf->fake.len) { + r->headers_out.content_length_n += conf->fake.len; + } r->headers_out.last_modified_time = 23349600; r->headers_out.etag_size = 40; @@ -144,18 +170,36 @@ ngx_http_empty_gif_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - out.buf = b; - out.next = NULL; + out[0].buf = b; + out[0].next = NULL; b->pos = ngx_empty_gif; b->last = ngx_empty_gif + sizeof(ngx_empty_gif); b->memory = 1; - b->last_buf = 1; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = sizeof(ngx_empty_gif); r->headers_out.last_modified_time = 23349600; + if (conf->fake.len) { + out[0].next = &out[1]; + r->headers_out.content_length_n += conf->fake.len; + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + out[1].next = NULL; + out[1].buf = b; + + b->pos = conf->fake.data; + b->last = conf->fake.data + conf->fake.len; + b->memory = 1; + } + + b->last_buf = 1; + r->headers_out.etag_size = 40; r->headers_out.etag_time = 5; r->headers_out.etag_uniq = 6535; @@ -166,7 +210,7 @@ ngx_http_empty_gif_handler(ngx_http_request_t *r) return rc; } - return ngx_http_output_filter(r, &out); + return ngx_http_output_filter(r, &out[0]); } @@ -180,3 +224,71 @@ ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } + + +static void * +ngx_http_empty_gif_create_local_conf(ngx_conf_t *cf) +{ + ngx_http_empty_gif_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_empty_gif_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + return conf; +} + +static char * +ngx_http_empty_gif_merge_local_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_empty_gif_loc_conf_t *prev = parent; + ngx_http_empty_gif_loc_conf_t *conf = child; + + if (prev->fake.len) { + conf->fake = prev->fake; + } + + return NGX_CONF_OK; +} + +static char * +ngx_http_empty_gif_size(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *field, *value; + ngx_conf_post_t *post; + + field = (ngx_str_t *) (p + cmd->offset); + + if (field->data) { + return "is duplicate"; + } + + value = cf->args->elts; + + field->len = ngx_parse_size(&value[1]); + + if (field->len == (size_t) NGX_ERROR) { + return "invalid value"; + } + + if (field->len < sizeof(ngx_empty_gif)) { + return "is shortly"; + } + + field->len -= sizeof(ngx_empty_gif); + + field->data = ngx_pcalloc(cf->pool, field->len); + if (field->data == NULL) { + return NGX_CONF_ERROR; + } + + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, field); + } + + return NGX_CONF_OK; +} -- 1.6.2 From 18f581348d9b4170d9570877b86df7e6843c66c3 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Wed, 18 Mar 2009 02:32:56 +0300 Subject: [PATCH 2/3] Optimize by memmory `empty_gif_size' Cc: catap@catap.ru Now for send of very large empty gif did not allocated a lot of memory, because I allocated buffer and used it multiple times. Size of buffer is a first optional argument of `empty_gif_size' directive. --- src/http/modules/ngx_http_empty_gif_module.c | 109 +++++++++++++++++--------- 1 files changed, 71 insertions(+), 38 deletions(-) diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c index 2abbc19ceb9991be85ebd2236d106c4800ae6508..17b46ac0efb06673232e808ca1d0b44d5994a1a2 100644 --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -9,7 +9,12 @@ typedef struct { - ngx_str_t fake; + size_t size; + ngx_str_t str; +} ngx_http_empty_gif_fake_t; + +typedef struct { + ngx_http_empty_gif_fake_t fake; } ngx_http_empty_gif_loc_conf_t; @@ -34,7 +39,7 @@ static ngx_command_t ngx_http_empty_gif_commands[] = { NULL }, { ngx_string("empty_gif_size"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_TAKE2, ngx_http_empty_gif_size, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_empty_gif_loc_conf_t, fake), @@ -129,8 +134,9 @@ static ngx_int_t ngx_http_empty_gif_handler(ngx_http_request_t *r) { ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t out[2]; + ngx_buf_t *b = NULL; + ngx_uint_t i, out_count; + ngx_chain_t *out; ngx_http_empty_gif_loc_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_empty_gif_module); @@ -152,8 +158,8 @@ ngx_http_empty_gif_handler(ngx_http_request_t *r) if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = sizeof(ngx_empty_gif); - if (conf->fake.len) { - r->headers_out.content_length_n += conf->fake.len; + if (conf->fake.size) { + r->headers_out.content_length_n += conf->fake.size; } r->headers_out.last_modified_time = 23349600; @@ -165,39 +171,50 @@ ngx_http_empty_gif_handler(ngx_http_request_t *r) return ngx_http_send_header(r); } - b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); - if (b == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + out_count = 1; + if (conf->fake.size) { + out_count += conf->fake.size / conf->fake.str.len; + if (conf->fake.size % conf->fake.str.len) { + out_count++; + } } - out[0].buf = b; - out[0].next = NULL; - - b->pos = ngx_empty_gif; - b->last = ngx_empty_gif + sizeof(ngx_empty_gif); - b->memory = 1; - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = sizeof(ngx_empty_gif); - r->headers_out.last_modified_time = 23349600; - - if (conf->fake.len) { - out[0].next = &out[1]; - r->headers_out.content_length_n += conf->fake.len; + out = ngx_palloc(r->pool, sizeof(ngx_chain_t) * out_count); + if (out == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + for (i = 0; i < out_count; i++) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - out[1].next = NULL; - out[1].buf = b; + out[i].buf = b; + + if (0 == i) { + out[i].next = NULL; + b->pos = b->start = ngx_empty_gif; + b->last = b->end = ngx_empty_gif + sizeof(ngx_empty_gif); + } else if ((conf->fake.size / conf->fake.str.len) + 1 == i) { + out[i-1].next = &out[i]; + out[i].next = NULL; + b->pos = b->start = conf->fake.str.data; + b->last = b->end = conf->fake.str.data + conf->fake.size % conf->fake.str.len; + } else { + out[i-1].next = &out[i]; + out[i].next = NULL; + b->pos = b->start = conf->fake.str.data; + b->last = b->end = conf->fake.str.data + conf->fake.str.len; + } - b->pos = conf->fake.data; - b->last = conf->fake.data + conf->fake.len; b->memory = 1; } + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = sizeof(ngx_empty_gif) + conf->fake.size; + r->headers_out.last_modified_time = 23349600; + b->last_buf = 1; r->headers_out.etag_size = 40; @@ -210,7 +227,7 @@ ngx_http_empty_gif_handler(ngx_http_request_t *r) return rc; } - return ngx_http_output_filter(r, &out[0]); + return ngx_http_output_filter(r, out); } @@ -245,7 +262,7 @@ ngx_http_empty_gif_merge_local_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_empty_gif_loc_conf_t *prev = parent; ngx_http_empty_gif_loc_conf_t *conf = child; - if (prev->fake.len) { + if (prev->fake.size) { conf->fake = prev->fake; } @@ -257,31 +274,47 @@ ngx_http_empty_gif_size(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; - ngx_str_t *field, *value; + ngx_str_t *value; + ngx_int_t i = 1; ngx_conf_post_t *post; + ngx_http_empty_gif_fake_t *field; - field = (ngx_str_t *) (p + cmd->offset); + field = (ngx_http_empty_gif_fake_t *) (p + cmd->offset); - if (field->data) { + if (field->str.data) { return "is duplicate"; } value = cf->args->elts; - field->len = ngx_parse_size(&value[1]); + if (cf->args->nelts == 3) { + field->str.len = ngx_parse_size(&value[i]); + if (field->str.len == (size_t) NGX_ERROR) { + return "invalid value"; + } + i++; + } else { + field->str.len = 1024; + } + + field->size = ngx_parse_size(&value[i]); - if (field->len == (size_t) NGX_ERROR) { + if (field->size == (size_t) NGX_ERROR) { return "invalid value"; } - if (field->len < sizeof(ngx_empty_gif)) { + if (field->size < sizeof(ngx_empty_gif)) { return "is shortly"; } - field->len -= sizeof(ngx_empty_gif); + field->size -= sizeof(ngx_empty_gif); + + if (field->str.len > field->size) { + field->str.len = field->size; + } - field->data = ngx_pcalloc(cf->pool, field->len); - if (field->data == NULL) { + field->str.data = ngx_pcalloc(cf->pool, field->str.len); + if (field->str.data == NULL) { return NGX_CONF_ERROR; } -- 1.6.2 From d988dd9645e9b6780cb582681e9cc9bef6951757 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Wed, 18 Mar 2009 02:36:16 +0300 Subject: [PATCH 3/3] Grand access to use `empty_gif_size' directive using in http, server, location and if in location Cc: catap@catap.ru --- src/http/modules/ngx_http_empty_gif_module.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c index 17b46ac0efb06673232e808ca1d0b44d5994a1a2..e1a5749f44369b092913720ab89f565f8deb3130 100644 --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -39,7 +39,8 @@ static ngx_command_t ngx_http_empty_gif_commands[] = { NULL }, { ngx_string("empty_gif_size"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_TAKE2, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE12, ngx_http_empty_gif_size, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_empty_gif_loc_conf_t, fake), -- 1.6.2