~ubuntu-branches/ubuntu/quantal/nginx/quantal-updates

« back to all changes in this revision

Viewing changes to debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.c

  • Committer: Package Import Robot
  • Author(s): Kartik Mistry, Kartik Mistry
  • Date: 2011-09-26 10:17:04 UTC
  • mfrom: (4.2.38 sid)
  • Revision ID: package-import@ubuntu.com-20110926101704-x8pxngiujrmkxnn3
Tags: 1.1.4-2
[Kartik Mistry]
* debian/modules:
  + Updated nginx-upload-progress module, Thanks to upstream for fixing issue
    that FTBFS nginx on kFreeBSD-* archs.
  + Updated nginx-lua module to latest upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) agentzh */
 
2
 
 
3
#define DDEBUG 0
 
4
 
 
5
#include "ddebug.h"
 
6
 
 
7
#include "ngx_http_headers_more_headers_out.h"
 
8
#include "ngx_http_headers_more_util.h"
 
9
#include <ctype.h>
 
10
 
 
11
/* config time */
 
12
 
 
13
static char *
 
14
ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd,
 
15
        void *conf, ngx_http_headers_more_opcode_t opcode);
 
16
 
 
17
/* request time */
 
18
 
 
19
static ngx_flag_t ngx_http_headers_more_check_type(ngx_http_request_t *r,
 
20
        ngx_array_t *types);
 
21
 
 
22
static ngx_flag_t ngx_http_headers_more_check_status(ngx_http_request_t *r,
 
23
        ngx_array_t *statuses);
 
24
 
 
25
static ngx_int_t ngx_http_set_header(ngx_http_request_t *r,
 
26
    ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
27
 
 
28
static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r,
 
29
    ngx_http_headers_more_header_val_t *hv, ngx_str_t *value,
 
30
    ngx_table_elt_t **output_header, ngx_flag_t no_create);
 
31
 
 
32
static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r,
 
33
    ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
34
 
 
35
static ngx_int_t ngx_http_set_accept_ranges_header(ngx_http_request_t *r,
 
36
    ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
37
 
 
38
static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r,
 
39
    ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
40
 
 
41
static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r,
 
42
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
43
 
 
44
static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r,
 
45
    ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
46
 
 
47
static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r,
 
48
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value);
 
49
 
 
50
 
 
51
static ngx_http_headers_more_set_header_t ngx_http_headers_more_set_handlers[]
 
52
    = {
 
53
 
 
54
    { ngx_string("Server"),
 
55
                 offsetof(ngx_http_headers_out_t, server),
 
56
                 ngx_http_set_builtin_header },
 
57
 
 
58
    { ngx_string("Date"),
 
59
                 offsetof(ngx_http_headers_out_t, date),
 
60
                 ngx_http_set_builtin_header },
 
61
 
 
62
    { ngx_string("Content-Encoding"),
 
63
                 offsetof(ngx_http_headers_out_t, content_encoding),
 
64
                 ngx_http_set_builtin_header },
 
65
 
 
66
    { ngx_string("Location"),
 
67
                 offsetof(ngx_http_headers_out_t, location),
 
68
                 ngx_http_set_builtin_header },
 
69
 
 
70
    { ngx_string("Refresh"),
 
71
                 offsetof(ngx_http_headers_out_t, refresh),
 
72
                 ngx_http_set_builtin_header },
 
73
 
 
74
    { ngx_string("Last-Modified"),
 
75
                 offsetof(ngx_http_headers_out_t, last_modified),
 
76
                 ngx_http_set_builtin_header },
 
77
 
 
78
    { ngx_string("Content-Range"),
 
79
                 offsetof(ngx_http_headers_out_t, content_range),
 
80
                 ngx_http_set_builtin_header },
 
81
 
 
82
    { ngx_string("Accept-Ranges"),
 
83
                 offsetof(ngx_http_headers_out_t, accept_ranges),
 
84
                 ngx_http_set_accept_ranges_header },
 
85
 
 
86
    { ngx_string("WWW-Authenticate"),
 
87
                 offsetof(ngx_http_headers_out_t, www_authenticate),
 
88
                 ngx_http_set_builtin_header },
 
89
 
 
90
    { ngx_string("Expires"),
 
91
                 offsetof(ngx_http_headers_out_t, expires),
 
92
                 ngx_http_set_builtin_header },
 
93
 
 
94
    { ngx_string("E-Tag"),
 
95
                 offsetof(ngx_http_headers_out_t, etag),
 
96
                 ngx_http_set_builtin_header },
 
97
 
 
98
    { ngx_string("Content-Length"),
 
99
                 offsetof(ngx_http_headers_out_t, content_length),
 
100
                 ngx_http_set_content_length_header },
 
101
 
 
102
    { ngx_string("Content-Type"),
 
103
                 0,
 
104
                 ngx_http_set_content_type_header },
 
105
 
 
106
    { ngx_null_string, 0, ngx_http_set_header }
 
107
};
 
108
 
 
109
 
 
110
/* request time implementation */
 
111
 
 
112
ngx_int_t
 
113
ngx_http_headers_more_exec_cmd(ngx_http_request_t *r,
 
114
        ngx_http_headers_more_cmd_t *cmd)
 
115
{
 
116
    ngx_str_t                                   value;
 
117
    ngx_http_headers_more_header_val_t         *h;
 
118
    ngx_uint_t                                  i;
 
119
 
 
120
    if (!cmd->headers) {
 
121
        return NGX_OK;
 
122
    }
 
123
 
 
124
    if (cmd->types) {
 
125
        if ( ! ngx_http_headers_more_check_type(r, cmd->types) ) {
 
126
            return NGX_OK;
 
127
        }
 
128
    }
 
129
 
 
130
    if (cmd->statuses) {
 
131
        if ( ! ngx_http_headers_more_check_status(r, cmd->statuses) ) {
 
132
            return NGX_OK;
 
133
        }
 
134
        dd("status check is passed");
 
135
    }
 
136
 
 
137
    h = cmd->headers->elts;
 
138
    for (i = 0; i < cmd->headers->nelts; i++) {
 
139
 
 
140
        if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {
 
141
            return NGX_ERROR;
 
142
        }
 
143
 
 
144
        if (h[i].handler(r, &h[i], &value) != NGX_OK) {
 
145
            return NGX_ERROR;
 
146
        }
 
147
    }
 
148
 
 
149
    return NGX_OK;
 
150
}
 
151
 
 
152
 
 
153
static ngx_int_t
 
154
ngx_http_set_header(ngx_http_request_t *r,
 
155
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
156
{
 
157
    return ngx_http_set_header_helper(r, hv, value, NULL, 0);
 
158
}
 
159
 
 
160
 
 
161
static ngx_int_t
 
162
ngx_http_set_header_helper(ngx_http_request_t *r,
 
163
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value,
 
164
        ngx_table_elt_t **output_header, ngx_flag_t no_create)
 
165
{
 
166
    ngx_table_elt_t             *h;
 
167
    ngx_list_part_t             *part;
 
168
    ngx_uint_t                   i;
 
169
    ngx_flag_t                   matched = 0;
 
170
 
 
171
    dd_enter();
 
172
 
 
173
    part = &r->headers_out.headers.part;
 
174
    h = part->elts;
 
175
 
 
176
    for (i = 0; /* void */; i++) {
 
177
        if (i >= part->nelts) {
 
178
            if (part->next == NULL) {
 
179
                break;
 
180
            }
 
181
            part = part->next;
 
182
            h = part->elts;
 
183
            i = 0;
 
184
        }
 
185
 
 
186
        if (
 
187
            (!hv->wildcard && (h[i].key.len == hv->key.len
 
188
                && ngx_strncasecmp(h[i].key.data,
 
189
                    hv->key.data,
 
190
                                   h[i].key.len) == 0))
 
191
            ||
 
192
            (hv->wildcard && (h[i].key.len >= hv->key.len-1
 
193
                && ngx_strncasecmp(h[i].key.data,
 
194
                    hv->key.data,
 
195
                                   hv->key.len-1) == 0))
 
196
            )
 
197
        {
 
198
            if (value->len == 0 || matched) {
 
199
                dd("clearing normal header for %.*s", (int) hv->key.len,
 
200
                        hv->key.data);
 
201
 
 
202
                h[i].value.len = 0;
 
203
                h[i].hash = 0;
 
204
 
 
205
            } else {
 
206
                h[i].value = *value;
 
207
                h[i].hash = 1;
 
208
            }
 
209
 
 
210
            if (output_header) {
 
211
                *output_header = &h[i];
 
212
            }
 
213
 
 
214
            matched = 1;
 
215
        }
 
216
    }
 
217
 
 
218
    if (matched){
 
219
      return NGX_OK;
 
220
    }
 
221
 
 
222
    if ((hv->wildcard || no_create) && value->len == 0) {
 
223
        return NGX_OK;
 
224
    }
 
225
 
 
226
    /* XXX we still need to create header slot even if the value
 
227
     * is empty because some builtin headers like Last-Modified
 
228
     * relies on this to get cleared */
 
229
 
 
230
    h = ngx_list_push(&r->headers_out.headers);
 
231
 
 
232
    if (h == NULL) {
 
233
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
234
    }
 
235
 
 
236
    if (value->len == 0) {
 
237
        h->hash = 0;
 
238
 
 
239
    } else {
 
240
        h->hash = hv->hash;
 
241
    }
 
242
 
 
243
    h->key = hv->key;
 
244
    h->value = *value;
 
245
 
 
246
    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
 
247
    if (h->lowcase_key == NULL) {
 
248
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
249
    }
 
250
 
 
251
    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
 
252
 
 
253
    if (output_header) {
 
254
        *output_header = h;
 
255
    }
 
256
 
 
257
    return NGX_OK;
 
258
}
 
259
 
 
260
 
 
261
static ngx_int_t
 
262
ngx_http_set_builtin_header(ngx_http_request_t *r,
 
263
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
264
{
 
265
    ngx_table_elt_t  *h, **old;
 
266
 
 
267
    dd_enter();
 
268
 
 
269
    if (hv->offset) {
 
270
        old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
 
271
 
 
272
    } else {
 
273
        old = NULL;
 
274
    }
 
275
 
 
276
    if (old == NULL || *old == NULL) {
 
277
        return ngx_http_set_header_helper(r, hv, value, old, 0);
 
278
    }
 
279
 
 
280
    h = *old;
 
281
 
 
282
    if (value->len == 0) {
 
283
        dd("clearing the builtin header");
 
284
 
 
285
        h->hash = 0;
 
286
        h->value = *value;
 
287
 
 
288
        return NGX_OK;
 
289
    }
 
290
 
 
291
    h->hash = hv->hash;
 
292
    h->key = hv->key;
 
293
    h->value = *value;
 
294
 
 
295
    return NGX_OK;
 
296
}
 
297
 
 
298
 
 
299
static ngx_int_t
 
300
ngx_http_set_content_type_header(ngx_http_request_t *r,
 
301
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
302
{
 
303
    u_char          *p, *last, *end;
 
304
 
 
305
    r->headers_out.content_type_len = value->len;
 
306
    r->headers_out.content_type = *value;
 
307
    r->headers_out.content_type_hash = hv->hash;
 
308
    r->headers_out.content_type_lowcase = NULL;
 
309
 
 
310
    p = value->data;
 
311
    end = p + value->len;
 
312
 
 
313
    for (; p != end; p++) {
 
314
 
 
315
        if (*p != ';') {
 
316
            continue;
 
317
        }
 
318
 
 
319
        last = p;
 
320
 
 
321
        while (*++p == ' ') { /* void */ }
 
322
 
 
323
        if (p == end) {
 
324
            break;
 
325
        }
 
326
 
 
327
        if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
 
328
            continue;
 
329
        }
 
330
 
 
331
        p += 8;
 
332
 
 
333
        r->headers_out.content_type_len = last - value->data;
 
334
 
 
335
        if (*p == '"') {
 
336
            p++;
 
337
        }
 
338
 
 
339
        last = end;
 
340
 
 
341
        if (*(last - 1) == '"') {
 
342
            last--;
 
343
        }
 
344
 
 
345
        r->headers_out.charset.len = last - p;
 
346
        r->headers_out.charset.data = p;
 
347
 
 
348
        break;
 
349
    }
 
350
 
 
351
    value->len = 0;
 
352
 
 
353
    return ngx_http_set_header_helper(r, hv, value, NULL, 1);
 
354
}
 
355
 
 
356
 
 
357
static ngx_int_t
 
358
ngx_http_set_content_length_header(ngx_http_request_t *r,
 
359
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
360
{
 
361
    off_t           len;
 
362
 
 
363
    if (value->len == 0) {
 
364
        return ngx_http_clear_content_length_header(r, hv, value);
 
365
    }
 
366
 
 
367
    len = ngx_atosz(value->data, value->len);
 
368
    if (len == NGX_ERROR) {
 
369
        return NGX_ERROR;
 
370
    }
 
371
 
 
372
    r->headers_out.content_length_n = len;
 
373
 
 
374
    return ngx_http_set_builtin_header(r, hv, value);
 
375
}
 
376
 
 
377
 
 
378
static ngx_int_t
 
379
ngx_http_set_accept_ranges_header(ngx_http_request_t *r,
 
380
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
381
{
 
382
    if (value->len == 0) {
 
383
        r->allow_ranges = 0;
 
384
    }
 
385
 
 
386
    return ngx_http_set_builtin_header(r, hv, value);
 
387
}
 
388
 
 
389
 
 
390
static ngx_int_t
 
391
ngx_http_clear_content_length_header(ngx_http_request_t *r,
 
392
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
393
{
 
394
    r->headers_out.content_length_n = -1;
 
395
 
 
396
    return ngx_http_clear_builtin_header(r, hv, value);
 
397
}
 
398
 
 
399
 
 
400
static ngx_int_t
 
401
ngx_http_clear_builtin_header(ngx_http_request_t *r,
 
402
        ngx_http_headers_more_header_val_t *hv, ngx_str_t *value)
 
403
{
 
404
    dd_enter();
 
405
 
 
406
    value->len = 0;
 
407
 
 
408
    return ngx_http_set_builtin_header(r, hv, value);
 
409
}
 
410
 
 
411
 
 
412
char *
 
413
ngx_http_headers_more_set_headers(ngx_conf_t *cf,
 
414
        ngx_command_t *cmd, void *conf)
 
415
{
 
416
    return ngx_http_headers_more_parse_directive(cf, cmd, conf,
 
417
            ngx_http_headers_more_opcode_set);
 
418
}
 
419
 
 
420
 
 
421
char *
 
422
ngx_http_headers_more_clear_headers(ngx_conf_t *cf,
 
423
        ngx_command_t *cmd, void *conf)
 
424
{
 
425
    return ngx_http_headers_more_parse_directive(cf, cmd, conf,
 
426
            ngx_http_headers_more_opcode_clear);
 
427
}
 
428
 
 
429
 
 
430
static ngx_flag_t
 
431
ngx_http_headers_more_check_type(ngx_http_request_t *r, ngx_array_t *types)
 
432
{
 
433
    ngx_uint_t          i;
 
434
    ngx_str_t           *t;
 
435
 
 
436
    dd("headers_out->content_type: %.*s (len %d)",
 
437
            (int) r->headers_out.content_type.len,
 
438
            r->headers_out.content_type.data,
 
439
            (int) r->headers_out.content_type.len);
 
440
 
 
441
    t = types->elts;
 
442
 
 
443
    for (i = 0; i < types->nelts; i++) {
 
444
        dd("...comparing with type [%.*s]", (int) t[i].len, t[i].data);
 
445
 
 
446
        if (r->headers_out.content_type.len == t[i].len
 
447
                && ngx_strncmp(r->headers_out.content_type.data,
 
448
                    t[i].data, t[i].len) == 0)
 
449
        {
 
450
            return 1;
 
451
        }
 
452
    }
 
453
 
 
454
    return 0;
 
455
}
 
456
 
 
457
 
 
458
static ngx_flag_t
 
459
ngx_http_headers_more_check_status(ngx_http_request_t *r, ngx_array_t *statuses)
 
460
{
 
461
    ngx_uint_t          i;
 
462
    ngx_uint_t          *status;
 
463
 
 
464
    dd("headers_out.status = %d", (int) r->headers_out.status);
 
465
 
 
466
    status = statuses->elts;
 
467
    for (i = 0; i < statuses->nelts; i++) {
 
468
        dd("...comparing with specified status %d", (int) status[i]);
 
469
 
 
470
        if (r->headers_out.status == status[i]) {
 
471
            return 1;
 
472
        }
 
473
    }
 
474
 
 
475
    return 0;
 
476
}
 
477
 
 
478
 
 
479
/* config time implementation */
 
480
 
 
481
static char *
 
482
ngx_http_headers_more_parse_directive(ngx_conf_t *cf, ngx_command_t *ngx_cmd,
 
483
        void *conf, ngx_http_headers_more_opcode_t opcode)
 
484
{
 
485
    ngx_http_headers_more_loc_conf_t  *hcf = conf;
 
486
 
 
487
    ngx_uint_t                         i;
 
488
    ngx_http_headers_more_cmd_t       *cmd;
 
489
    ngx_str_t                         *arg;
 
490
    ngx_flag_t                         ignore_next_arg;
 
491
    ngx_str_t                         *cmd_name;
 
492
    ngx_int_t                          rc;
 
493
 
 
494
    if (hcf->cmds == NULL) {
 
495
        hcf->cmds = ngx_array_create(cf->pool, 1,
 
496
                            sizeof(ngx_http_headers_more_cmd_t));
 
497
 
 
498
        if (hcf->cmds == NULL) {
 
499
            return NGX_CONF_ERROR;
 
500
        }
 
501
    }
 
502
 
 
503
    cmd = ngx_array_push(hcf->cmds);
 
504
 
 
505
    if (cmd == NULL) {
 
506
        return NGX_CONF_ERROR;
 
507
    }
 
508
 
 
509
    cmd->headers = ngx_array_create(cf->pool, 1,
 
510
                            sizeof(ngx_http_headers_more_header_val_t));
 
511
    if (cmd->headers == NULL) {
 
512
        return NGX_CONF_ERROR;
 
513
    }
 
514
 
 
515
    cmd->types = ngx_array_create(cf->pool, 1,
 
516
                            sizeof(ngx_str_t));
 
517
    if (cmd->types == NULL) {
 
518
        return NGX_CONF_ERROR;
 
519
    }
 
520
 
 
521
    cmd->statuses = ngx_array_create(cf->pool, 1,
 
522
                            sizeof(ngx_uint_t));
 
523
    if (cmd->statuses == NULL) {
 
524
        return NGX_CONF_ERROR;
 
525
    }
 
526
 
 
527
    arg = cf->args->elts;
 
528
 
 
529
    cmd_name = &arg[0];
 
530
 
 
531
    ignore_next_arg = 0;
 
532
 
 
533
    for (i = 1; i < cf->args->nelts; i++) {
 
534
        if (ignore_next_arg) {
 
535
            ignore_next_arg = 0;
 
536
            continue;
 
537
        }
 
538
 
 
539
        if (arg[i].len == 0) {
 
540
            continue;
 
541
        }
 
542
 
 
543
        if (arg[i].data[0] != '-') {
 
544
            rc = ngx_http_headers_more_parse_header(cf, cmd_name,
 
545
                    &arg[i], cmd->headers, opcode,
 
546
                    ngx_http_headers_more_set_handlers);
 
547
 
 
548
            if (rc != NGX_OK) {
 
549
                return NGX_CONF_ERROR;
 
550
            }
 
551
 
 
552
            continue;
 
553
        }
 
554
 
 
555
        if (arg[i].len == 2) {
 
556
            if (arg[i].data[1] == 't') {
 
557
                if (i == cf->args->nelts - 1) {
 
558
                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
 
559
                          "%V: option -t takes an argument.",
 
560
                          cmd_name);
 
561
 
 
562
                    return NGX_CONF_ERROR;
 
563
                }
 
564
 
 
565
                rc = ngx_http_headers_more_parse_types(cf->log, cmd_name,
 
566
                        &arg[i + 1], cmd->types);
 
567
 
 
568
                if (rc != NGX_OK) {
 
569
                    return NGX_CONF_ERROR;
 
570
                }
 
571
 
 
572
                ignore_next_arg = 1;
 
573
 
 
574
                continue;
 
575
 
 
576
            } else if (arg[i].data[1] == 's') {
 
577
                if (i == cf->args->nelts - 1) {
 
578
                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
 
579
                          "%V: option -s takes an argument.",
 
580
                          cmd_name
 
581
                          );
 
582
 
 
583
                    return NGX_CONF_ERROR;
 
584
                }
 
585
 
 
586
                rc = ngx_http_headers_more_parse_statuses(cf->log, cmd_name,
 
587
                        &arg[i + 1], cmd->statuses);
 
588
 
 
589
                if (rc != NGX_OK) {
 
590
                    return NGX_CONF_ERROR;
 
591
                }
 
592
 
 
593
                ignore_next_arg = 1;
 
594
 
 
595
                continue;
 
596
            }
 
597
        }
 
598
 
 
599
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
 
600
              "%V: invalid option name: \"%V\"",
 
601
              cmd_name, &arg[i]);
 
602
 
 
603
        return NGX_CONF_ERROR;
 
604
    }
 
605
 
 
606
    dd("Found %d statuses, %d types, and %d headers",
 
607
            (int) cmd->statuses->nelts, (int) cmd->types->nelts,
 
608
            (int) cmd->headers->nelts);
 
609
 
 
610
    if (cmd->headers->nelts == 0) {
 
611
        cmd->headers = NULL;
 
612
    }
 
613
 
 
614
    if (cmd->types->nelts == 0) {
 
615
        cmd->types = NULL;
 
616
    }
 
617
 
 
618
    if (cmd->statuses->nelts == 0) {
 
619
        cmd->statuses = NULL;
 
620
    }
 
621
 
 
622
    cmd->is_input = 0;
 
623
 
 
624
    ngx_http_headers_more_filter_used = 1;
 
625
 
 
626
    return NGX_CONF_OK;
 
627
}
 
628