comparison src/http/modules/ngx_http_gzip_filter.c @ 134:d57c6835225c

nginx-0.0.1-2003-09-26-09:45:21 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 26 Sep 2003 05:45:21 +0000
parents b27548f540ad
children e29909bd9b8a
comparison
equal deleted inserted replaced
133:b27548f540ad 134:d57c6835225c
5 5
6 #include <zlib.h> 6 #include <zlib.h>
7 7
8 8
9 typedef struct { 9 typedef struct {
10 int enable;
10 int hunk_size; 11 int hunk_size;
11 int max_hunks; 12 int hunks;
12 int no_buffer; 13 int no_buffer;
13 } ngx_http_gzip_conf_t; 14 } ngx_http_gzip_conf_t;
14 15
15 16
16 typedef struct { 17 typedef struct {
19 ngx_chain_t *busy; 20 ngx_chain_t *busy;
20 ngx_chain_t *out; 21 ngx_chain_t *out;
21 ngx_chain_t **last_out; 22 ngx_chain_t **last_out;
22 ngx_hunk_t *in_hunk; 23 ngx_hunk_t *in_hunk;
23 ngx_hunk_t *out_hunk; 24 ngx_hunk_t *out_hunk;
25 int hunks;
26
27 int length;
24 void *alloc; 28 void *alloc;
25 29
30 int flush;
31 u_int crc32;
26 z_stream zstream; 32 z_stream zstream;
27 } ngx_http_gzip_ctx_t; 33 } ngx_http_gzip_ctx_t;
28 34
29 35
36 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);
30 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle); 37 static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle);
38 static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
39 static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
40 void *parent, void *child);
41
42
43 static ngx_command_t ngx_http_gzip_filter_commands[] = {
44
45 {ngx_string("gzip"),
46 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
47 ngx_conf_set_flag_slot,
48 NGX_HTTP_LOC_CONF_OFFSET,
49 offsetof(ngx_http_gzip_conf_t, enable),
50 NULL},
51
52 {ngx_string("gzip_hunk_size"),
53 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
54 ngx_conf_set_size_slot,
55 NGX_HTTP_LOC_CONF_OFFSET,
56 offsetof(ngx_http_gzip_conf_t, hunk_size),
57 NULL},
58
59 {ngx_string("gzip_hunks"),
60 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
61 ngx_conf_set_num_slot,
62 NGX_HTTP_LOC_CONF_OFFSET,
63 offsetof(ngx_http_gzip_conf_t, hunks),
64 NULL},
65
66 {ngx_string("gzip_no_buffer"),
67 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
68 ngx_conf_set_flag_slot,
69 NGX_HTTP_LOC_CONF_OFFSET,
70 offsetof(ngx_http_gzip_conf_t, no_buffer),
71 NULL},
72
73 ngx_null_command
74 };
31 75
32 76
33 static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { 77 static ngx_http_module_t ngx_http_gzip_filter_module_ctx = {
34 NULL, /* create main configuration */ 78 NULL, /* create main configuration */
35 NULL, /* init main configuration */ 79 NULL, /* init main configuration */
36 80
37 NULL, /* create server configuration */ 81 NULL, /* create server configuration */
38 NULL, /* merge server configuration */ 82 NULL, /* merge server configuration */
39 83
40 NULL, /* create location configuration */ 84 ngx_http_gzip_create_conf, /* create location configuration */
41 NULL, /* merge location configuration */ 85 ngx_http_gzip_merge_conf, /* merge location configuration */
42 }; 86 };
43 87
44 88
45 ngx_module_t ngx_http_gzip_filter_module = { 89 ngx_module_t ngx_http_gzip_filter_module = {
46 NGX_MODULE, 90 NGX_MODULE,
47 &ngx_http_gzip_filter_module_ctx, /* module context */ 91 &ngx_http_gzip_filter_module_ctx, /* module context */
48 NULL, /* module directives */ 92 ngx_http_gzip_filter_commands, /* module directives */
49 NGX_HTTP_MODULE, /* module type */ 93 NGX_HTTP_MODULE, /* module type */
50 ngx_http_gzip_filter_init, /* init module */ 94 ngx_http_gzip_filter_init, /* init module */
51 NULL /* init child */ 95 NULL /* init child */
52 }; 96 };
53 97
54 98
55 static const char gzheader[10] = 99 static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
56 { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; 100
101 #if (HAVE_LITTLE_ENDIAN)
102
103 struct gztrailer {
104 u_int crc32;
105 u_int zlen;
106 };
107
108 #else /* HAVE_BIG_ENDIAN */
109
110 struct gztrailer {
111 unsigned char crc32[4];
112 unsigned char zlen[4];
113 };
114
115 #endif
116
57 117
58 118
59 static int (*next_header_filter) (ngx_http_request_t *r); 119 static int (*next_header_filter) (ngx_http_request_t *r);
60 static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch); 120 static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
61 121
62 122
63 static int ngx_http_gzip_header_filter(ngx_http_request_t *r) 123 static int ngx_http_gzip_header_filter(ngx_http_request_t *r)
64 { 124 {
125 ngx_http_gzip_ctx_t *ctx;
126 ngx_http_gzip_conf_t *conf;
127
65 if (r->headers_out.status != NGX_HTTP_OK 128 if (r->headers_out.status != NGX_HTTP_OK
66 || (ngx_strncasecmp(r->headers_out.content_type->value.data, 129 || r->header_only
130 /* || r->content_encoding */
131 /* || r->accept_encoding == NULL */
132 || r->main)
133 {
134 return next_header_filter(r);
135 }
136
137 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
138
139 if (!conf->enable
140 /* TODO: conf->version */
141 /* TODO: "text/" -> custom types */
142 || ngx_strncasecmp(r->headers_out.content_type->value.data,
67 "text/", 5) != 0) 143 "text/", 5) != 0)
68 { 144 {
69 return next_header_filter(r); 145 return next_header_filter(r);
70 } 146 }
71 147
72 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, 148 ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module,
73 sizeof(ngx_http_gzip_filter_ctx_t), NGX_ERROR); 149 sizeof(ngx_http_gzip_ctx_t), NGX_ERROR);
74 150
75 ctx->length = r->headers_out.content_length; 151 ctx->length = r->headers_out.content_length;
76 r->headers_out.content_length = -1; 152 r->headers_out.content_length = -1;
153 r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY;
77 154
78 return next_header_filter(r); 155 return next_header_filter(r);
79 } 156 }
80 157
81 158
82 static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 159 static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
83 { 160 {
161 int rc, zin, zout;
162 struct gztrailer *trailer;
163 ngx_hunk_t *h;
164 ngx_chain_t *ce;
84 ngx_http_gzip_ctx_t *ctx; 165 ngx_http_gzip_ctx_t *ctx;
85 ngx_http_gzip_conf_t *conf; 166 ngx_http_gzip_conf_t *conf;
86 167
87 ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); 168 ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
88 169
89 if (ctx == NULL) { 170 if (ctx == NULL) {
90 next_body_filter(r, in); 171 return next_body_filter(r, in);
91 } 172 }
92 173
93 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); 174 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
94 175
95 if (ctx->alloc == NULL) { 176 if (ctx->alloc == NULL) {
96 #if 0 177 #if 0
97 ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR); 178 ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR);
98 #else 179 #else
99 ctx->alloc = ~NULL; 180 ctx->alloc = (void *) ~NULL;
100 #endif 181 #endif
101 rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED, 182 rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED,
102 /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1, 183 /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1,
103 Z_DEFAULT_STRATEGY); 184 Z_DEFAULT_STRATEGY);
104 185
105 if (rc != Z_OK) { 186 if (rc != Z_OK) {
106 ngx_log_error(NGX_LOG_ALERT, r->log, 0, 187 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
107 "deflateInit2() failed: %d", rc); 188 "deflateInit2() failed: %d", rc);
108 return ngx_http_gzip_error(ctx); 189 return ngx_http_gzip_error(ctx);
109 } 190 }
110 191
111 ngx_test_null(h, ngx_calloc_hunk(r->pool), ngx_http_gzip_error(ctx)); 192 ngx_test_null(h, ngx_calloc_hunk(r->pool), ngx_http_gzip_error(ctx));
124 ctx->crc32 = crc32(0L, Z_NULL, 0); 205 ctx->crc32 = crc32(0L, Z_NULL, 0);
125 ctx->flush = Z_NO_FLUSH; 206 ctx->flush = Z_NO_FLUSH;
126 } 207 }
127 208
128 if (in) { 209 if (in) {
129 add_to_chain(ctx->in, in) 210 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
130 } 211 return ngx_http_gzip_error(ctx);
131 212 }
132 for ( ;; ) { 213 }
133 214
215 while (ctx->in || ctx->out
216 || ctx->zstream.avail_in || ctx->zstream.avail_out
217 || ctx->flush != Z_NO_FLUSH)
218 {
134 for ( ;; ) { 219 for ( ;; ) {
135 220
136 if (ctx->flush == Z_NO_FLUSH 221 if (ctx->in
137 && ctx->zstream->avail_in == 0 222 && ctx->zstream.avail_in == 0
138 && ctx->in) 223 && ctx->flush == Z_NO_FLUSH)
139 { 224 {
140 ctx->in_hunk = ctx->in->hunk; 225 ctx->in_hunk = ctx->in->hunk;
141 ctx->in = ctx->in->next; 226 ctx->in = ctx->in->next;
142 227
143 ctx->zstream->next_in = ctx->in_hunk->pos; 228 ctx->zstream.avail_in = ctx->in_hunk->last - ctx->in_hunk->pos;
144 ctx->zstream->avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; 229
230 if (ctx->zstream.avail_in == 0) {
231 continue;
232 }
233
234 ctx->zstream.next_in = ctx->in_hunk->pos;
235
236 ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
237 ctx->zstream.avail_in);
145 238
146 if (ctx->in_hunk->type & NGX_HUNK_LAST) { 239 if (ctx->in_hunk->type & NGX_HUNK_LAST) {
147 ctx->flush = Z_FINISH; 240 ctx->flush = Z_FINISH;
148 241
149 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { 242 } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) {
150 ctx->flush = Z_SYNC_FINISH; 243 ctx->flush = Z_SYNC_FLUSH;
151 } 244 }
152 } 245 }
153 246
154 if (ctx->zstream->avail_out == 0) { 247 if (ctx->zstream.avail_out == 0) {
155 if (ctx->free) { 248 if (ctx->free) {
156 ctx->out_hunk = ctx->free->hunk; 249 ctx->out_hunk = ctx->free->hunk;
157 ctx->free = ctx->free->next; 250 ctx->free = ctx->free->next;
158 251
159 } else if (ctx->max_hunks < ctx->cur_hunks) { 252 } else if (ctx->hunks < conf->hunks) {
160 ngx_test_null(ctx->out_hunk, 253 ngx_test_null(ctx->out_hunk,
161 ngx_create_temp_hunk(r->pool, conf->size, 254 ngx_create_temp_hunk(r->pool, conf->hunk_size,
162 0, 0), 255 0, 0),
163 ngx_http_gzip_error(ctx)); 256 ngx_http_gzip_error(ctx));
164 ctx->cur_hunks++; 257 ctx->hunks++;
165 258
166 } else { 259 } else {
167 break; 260 break;
168 } 261 }
169 262
170 ctx->zstream->next_out = ctx->out_hunk->pos; 263 ctx->zstream.next_out = ctx->out_hunk->pos;
171 ctx->zstream->avail_out = conf->size; 264 ctx->zstream.avail_out = conf->hunk_size;
172 } 265 }
173 266
174 rc = deflate(ctx->zstream, ctx->flush); 267 rc = deflate(&ctx->zstream, ctx->flush);
175 if (rc != Z_OK && rc != Z_STREAM_END) { 268 if (rc != Z_OK && rc != Z_STREAM_END) {
176 ngx_log_error(NGX_LOG_ALERT, r->log, 0, 269 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
177 "deflate() failed: %d, %d", ctx->flush, rc); 270 "deflate() failed: %d, %d", ctx->flush, rc);
178 return ngx_http_gzip_error(ctx); 271 return ngx_http_gzip_error(ctx);
179 } 272 }
180 273
181 ctx->in_hunk->pos = ctx->zstream->next_in; 274 ngx_log_debug(r->connection->log, "deflate(): %d %d" _ ctx->flush _ rc);
182 275
183 if (rc == Z_STREAM_END) { 276 ctx->in_hunk->pos = ctx->zstream.next_in;
184 deflateEnd(ctx->zstream); 277
185 ngx_free(); 278 if (ctx->zstream.avail_out == 0) {
186 } 279 ctx->out_hunk->last += conf->hunk_size;
187 280 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
188 if (ctx->zstream->avail_out == 0) { 281 ngx_http_gzip_error(ctx));
189 ctx->out_hunk->last += conf->size; 282 *ctx->last_out = ce;
190 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, 283 ctx->last_out = &ce->next;
191 r->pool, ngx_http_gzip_error(ctx));
192 284
193 } else { 285 } else {
194 ctx->out_hunk->last = ctx->zstream->next_out; 286 ctx->out_hunk->last = ctx->zstream.next_out;
195 287
196 if (ctx->flush == Z_SYNC_FLUSH) { 288 if (ctx->flush == Z_SYNC_FLUSH) {
197 ctx->out_hunk->type |= NGX_HUNK_FLUSH; 289 ctx->out_hunk->type |= NGX_HUNK_FLUSH;
198 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk,
199 r->pool, ngx_http_gzip_error(ctx));
200 ctx->flush = Z_NO_FLUSH; 290 ctx->flush = Z_NO_FLUSH;
291
292 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
293 ngx_http_gzip_error(ctx));
294 *ctx->last_out = ce;
295 ctx->last_out = &ce->next;
296
201 break; 297 break;
202 298
203 } else if (ctx->flush == Z_FINISH) { 299 } else if (ctx->flush == Z_FINISH) {
204 ctx->out_hunk->type |= NGX_HUNK_LAST; 300 /* rc == Z_STREAM_END */
205 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, 301
206 r->pool, ngx_http_gzip_error(ctx)); 302 zin = ctx->zstream.total_in;
303 zout = 10 + ctx->zstream.total_out + 8;
304
305 ctx->flush = Z_NO_FLUSH;
306
307 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
308 ngx_http_gzip_error(ctx));
309 *ctx->last_out = ce;
310 ctx->last_out = &ce->next;
311
312 if (ctx->zstream.avail_out >= 8) {
313 trailer = (struct gztrailer *) &ctx->zstream.avail_in;
314 ctx->out_hunk->type |= NGX_HUNK_LAST;
315 ctx->out_hunk->last += 8;
316
317 } else {
318 /* STUB */ trailer = NULL;
319 }
320
321 #if (HAVE_LITTLE_ENDIAN)
322 trailer->crc32 = ctx->crc32;
323 trailer->zlen = zin;
324 #else
325 /* STUB */
326 #endif
327
328 deflateEnd(&ctx->zstream);
329 #if 0
330 ngx_free();
331 set ctx = NULL;
332 #endif
207 break; 333 break;
208 334
209 } else if (conf->no_buffer && ctx->in == NULL) { 335 } else if (conf->no_buffer && ctx->in == NULL) {
210 ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, 336 ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool,
211 r->pool, ngx_http_gzip_error(ctx)); 337 ngx_http_gzip_error(ctx));
338 *ctx->last_out = ce;
339 ctx->last_out = &ce->next;
340
212 break; 341 break;
213 } 342 }
214 } 343 }
215 } 344 }
216 345
217 if (next_body_filter(r, ctx->out) == NGX_ERROR) { 346 rc = next_body_filter(r, ctx->out);
347 if (rc == NGX_ERROR) {
218 return ngx_http_gzip_error(ctx); 348 return ngx_http_gzip_error(ctx);
219 } 349 }
220 350
221 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); 351 ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out);
222 } 352 ctx->last_out = &ctx->out;
353 }
354
355 /* STUB */
356 return next_body_filter(r, NULL);
223 } 357 }
224 358
225 359
226 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) 360 ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx)
227 { 361 {
241 next_body_filter = ngx_http_top_body_filter; 375 next_body_filter = ngx_http_top_body_filter;
242 ngx_http_top_body_filter = ngx_http_gzip_body_filter; 376 ngx_http_top_body_filter = ngx_http_gzip_body_filter;
243 377
244 return NGX_OK; 378 return NGX_OK;
245 } 379 }
380
381
382 static void *ngx_http_gzip_create_conf(ngx_conf_t *cf)
383 {
384 ngx_http_gzip_conf_t *conf;
385
386 ngx_test_null(conf,
387 ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)),
388 NGX_CONF_ERROR);
389
390 conf->enable = NGX_CONF_UNSET;
391 conf->hunk_size = NGX_CONF_UNSET;
392 conf->hunks = NGX_CONF_UNSET;
393 conf->no_buffer = NGX_CONF_UNSET;
394
395 return conf;
396 }
397
398
399 static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
400 void *parent, void *child)
401 {
402 ngx_http_gzip_conf_t *prev = parent;
403 ngx_http_gzip_conf_t *conf = child;
404
405 ngx_conf_merge_value(conf->enable, prev->enable, 0);
406 ngx_conf_merge_size_value(conf->hunk_size, prev->hunk_size,
407 /* STUB: PAGE_SIZE */ 4096);
408 ngx_conf_merge_value(conf->hunks, prev->hunks, 4);
409 ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
410
411 return NGX_CONF_OK;
412 }