nginx.xs revision e18a033b
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#define PERL_NO_GET_CONTEXT
9
10#include <ngx_config.h>
11#include <ngx_core.h>
12#include <ngx_http.h>
13#include <ngx_http_perl_module.h>
14
15#include "XSUB.h"
16
17
18#define ngx_http_perl_set_request(r)                                          \
19    r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0))))
20
21
22#define ngx_http_perl_set_targ(p, len)                                        \
23                                                                              \
24    SvUPGRADE(TARG, SVt_PV);                                                  \
25    SvPOK_on(TARG);                                                           \
26    sv_setpvn(TARG, (char *) p, len)
27
28
29static ngx_int_t
30ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv)
31{
32    u_char  *p;
33    STRLEN   len;
34
35    if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
36        sv = SvRV(sv);
37    }
38
39    p = (u_char *) SvPV(sv, len);
40
41    s->len = len;
42
43    if (SvREADONLY(sv) && SvPOK(sv)) {
44        s->data = p;
45
46        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
47                       "perl sv2str: %08XD \"%V\"", sv->sv_flags, s);
48
49        return NGX_OK;
50    }
51
52    s->data = ngx_pnalloc(r->pool, len);
53    if (s->data == NULL) {
54        return NGX_ERROR;
55    }
56
57    ngx_memcpy(s->data, p, len);
58
59    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
60                   "perl sv2str: %08XD \"%V\"", sv->sv_flags, s);
61
62    return NGX_OK;
63}
64
65
66static ngx_int_t
67ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b)
68{
69    ngx_chain_t           out;
70#if (NGX_HTTP_SSI)
71    ngx_chain_t          *cl;
72    ngx_http_perl_ctx_t  *ctx;
73
74    ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
75
76    if (ctx->ssi) {
77        cl = ngx_alloc_chain_link(r->pool);
78        if (cl == NULL) {
79            return NGX_ERROR;
80        }
81
82        cl->buf = b;
83        cl->next = NULL;
84        *ctx->ssi->last_out = cl;
85        ctx->ssi->last_out = &cl->next;
86
87        return NGX_OK;
88    }
89#endif
90
91    out.buf = b;
92    out.next = NULL;
93
94    return ngx_http_output_filter(r, &out);
95}
96
97
98MODULE = nginx    PACKAGE = nginx
99
100
101PROTOTYPES: DISABLE
102
103
104void
105status(r, code)
106    CODE:
107
108    ngx_http_request_t  *r;
109
110    ngx_http_perl_set_request(r);
111
112    r->headers_out.status = SvIV(ST(1));
113
114    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
115                   "perl status: %d", r->headers_out.status);
116
117    XSRETURN_UNDEF;
118
119
120void
121send_http_header(r, ...)
122    CODE:
123
124    ngx_http_request_t  *r;
125    SV                  *sv;
126
127    ngx_http_perl_set_request(r);
128
129    if (r->headers_out.status == 0) {
130        r->headers_out.status = NGX_HTTP_OK;
131    }
132
133    if (items != 1) {
134        sv = ST(1);
135
136        if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv)
137            != NGX_OK)
138        {
139            XSRETURN_EMPTY;
140        }
141
142        r->headers_out.content_type_len = r->headers_out.content_type.len;
143
144    } else {
145        if (ngx_http_set_content_type(r) != NGX_OK) {
146            XSRETURN_EMPTY;
147        }
148    }
149
150    (void) ngx_http_send_header(r);
151
152
153void
154header_only(r)
155    CODE:
156
157    dXSTARG;
158    ngx_http_request_t  *r;
159
160    ngx_http_perl_set_request(r);
161
162    sv_upgrade(TARG, SVt_IV);
163    sv_setiv(TARG, r->header_only);
164
165    ST(0) = TARG;
166
167
168void
169uri(r)
170    CODE:
171
172    dXSTARG;
173    ngx_http_request_t  *r;
174
175    ngx_http_perl_set_request(r);
176    ngx_http_perl_set_targ(r->uri.data, r->uri.len);
177
178    ST(0) = TARG;
179
180
181void
182args(r)
183    CODE:
184
185    dXSTARG;
186    ngx_http_request_t  *r;
187
188    ngx_http_perl_set_request(r);
189    ngx_http_perl_set_targ(r->args.data, r->args.len);
190
191    ST(0) = TARG;
192
193
194void
195request_method(r)
196    CODE:
197
198    dXSTARG;
199    ngx_http_request_t  *r;
200
201    ngx_http_perl_set_request(r);
202    ngx_http_perl_set_targ(r->method_name.data, r->method_name.len);
203
204    ST(0) = TARG;
205
206
207void
208remote_addr(r)
209    CODE:
210
211    dXSTARG;
212    ngx_http_request_t  *r;
213
214    ngx_http_perl_set_request(r);
215    ngx_http_perl_set_targ(r->connection->addr_text.data,
216                           r->connection->addr_text.len);
217
218    ST(0) = TARG;
219
220
221void
222header_in(r, key)
223    CODE:
224
225    dXSTARG;
226    ngx_http_request_t         *r;
227    SV                         *key;
228    u_char                     *p, *lowcase_key, *value, sep;
229    STRLEN                      len;
230    ssize_t                     size;
231    ngx_uint_t                  i, n, hash;
232    ngx_array_t                *a;
233    ngx_list_part_t            *part;
234    ngx_table_elt_t            *h, **ph;
235    ngx_http_header_t          *hh;
236    ngx_http_core_main_conf_t  *cmcf;
237
238    ngx_http_perl_set_request(r);
239
240    key = ST(1);
241
242    if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) {
243        key = SvRV(key);
244    }
245
246    p = (u_char *) SvPV(key, len);
247
248    /* look up hashed headers */
249
250    lowcase_key = ngx_pnalloc(r->pool, len);
251    if (lowcase_key == NULL) {
252        XSRETURN_UNDEF;
253    }
254
255    hash = ngx_hash_strlow(lowcase_key, p, len);
256
257    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
258
259    hh = ngx_hash_find(&cmcf->headers_in_hash, hash, lowcase_key, len);
260
261    if (hh) {
262
263        if (hh->offset == offsetof(ngx_http_headers_in_t, cookies)) {
264            sep = ';';
265            goto multi;
266        }
267#if (NGX_HTTP_X_FORWARDED_FOR)
268        if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) {
269            sep = ',';
270            goto multi;
271        }
272#endif
273
274        ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset);
275
276        if (*ph) {
277            ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
278
279            goto done;
280        }
281
282        XSRETURN_UNDEF;
283
284    multi:
285
286        /* Cookie, X-Forwarded-For */
287
288        a = (ngx_array_t *) ((char *) &r->headers_in + hh->offset);
289
290        n = a->nelts;
291
292        if (n == 0) {
293            XSRETURN_UNDEF;
294        }
295
296        ph = a->elts;
297
298        if (n == 1) {
299            ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
300
301            goto done;
302        }
303
304        size = - (ssize_t) (sizeof("; ") - 1);
305
306        for (i = 0; i < n; i++) {
307            size += ph[i]->value.len + sizeof("; ") - 1;
308        }
309
310        value = ngx_pnalloc(r->pool, size);
311        if (value == NULL) {
312            XSRETURN_UNDEF;
313        }
314
315        p = value;
316
317        for (i = 0; /* void */ ; i++) {
318            p = ngx_copy(p, ph[i]->value.data, ph[i]->value.len);
319
320            if (i == n - 1) {
321                break;
322            }
323
324            *p++ = sep; *p++ = ' ';
325        }
326
327        ngx_http_perl_set_targ(value, size);
328
329        goto done;
330    }
331
332    /* iterate over all headers */
333
334    part = &r->headers_in.headers.part;
335    h = part->elts;
336
337    for (i = 0; /* void */ ; i++) {
338
339        if (i >= part->nelts) {
340            if (part->next == NULL) {
341                break;
342            }
343
344            part = part->next;
345            h = part->elts;
346            i = 0;
347        }
348
349        if (len != h[i].key.len
350            || ngx_strcasecmp(p, h[i].key.data) != 0)
351        {
352            continue;
353        }
354
355        ngx_http_perl_set_targ(h[i].value.data, h[i].value.len);
356
357        goto done;
358    }
359
360    XSRETURN_UNDEF;
361
362    done:
363
364    ST(0) = TARG;
365
366
367void
368has_request_body(r, next)
369    CODE:
370
371    dXSTARG;
372    ngx_http_request_t   *r;
373    ngx_http_perl_ctx_t  *ctx;
374
375    ngx_http_perl_set_request(r);
376
377    if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
378        XSRETURN_UNDEF;
379    }
380
381    ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
382    ctx->next = SvRV(ST(1));
383
384    r->request_body_in_single_buf = 1;
385    r->request_body_in_persistent_file = 1;
386    r->request_body_in_clean_file = 1;
387
388    if (r->request_body_in_file_only) {
389        r->request_body_file_log_level = 0;
390    }
391
392    ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
393
394    sv_upgrade(TARG, SVt_IV);
395    sv_setiv(TARG, 1);
396
397    ST(0) = TARG;
398
399
400void
401request_body(r)
402    CODE:
403
404    dXSTARG;
405    ngx_http_request_t  *r;
406    u_char              *p, *data;
407    size_t               len;
408    ngx_buf_t           *buf;
409    ngx_chain_t         *cl;
410
411    ngx_http_perl_set_request(r);
412
413    if (r->request_body == NULL
414        || r->request_body->temp_file
415        || r->request_body->bufs == NULL)
416    {
417        XSRETURN_UNDEF;
418    }
419
420    cl = r->request_body->bufs;
421    buf = cl->buf;
422
423    if (cl->next == NULL) {
424        len = buf->last - buf->pos;
425        data = buf->pos;
426        goto done;
427    }
428
429    len = buf->last - buf->pos;
430    cl = cl->next;
431
432    for ( /* void */ ; cl; cl = cl->next) {
433        buf = cl->buf;
434        len += buf->last - buf->pos;
435    }
436
437    p = ngx_pnalloc(r->pool, len);
438    if (p == NULL) {
439        XSRETURN_UNDEF;
440    }
441
442    data = p;
443    cl = r->request_body->bufs;
444
445    for ( /* void */ ; cl; cl = cl->next) {
446        buf = cl->buf;
447        p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
448    }
449
450    done:
451
452    if (len == 0) {
453        XSRETURN_UNDEF;
454    }
455
456    ngx_http_perl_set_targ(data, len);
457
458    ST(0) = TARG;
459
460
461void
462request_body_file(r)
463    CODE:
464
465    dXSTARG;
466    ngx_http_request_t  *r;
467
468    ngx_http_perl_set_request(r);
469
470    if (r->request_body == NULL || r->request_body->temp_file == NULL) {
471        XSRETURN_UNDEF;
472    }
473
474    ngx_http_perl_set_targ(r->request_body->temp_file->file.name.data,
475                           r->request_body->temp_file->file.name.len);
476
477    ST(0) = TARG;
478
479
480void
481discard_request_body(r)
482    CODE:
483
484    ngx_http_request_t  *r;
485
486    ngx_http_perl_set_request(r);
487
488    ngx_http_discard_request_body(r);
489
490
491void
492header_out(r, key, value)
493    CODE:
494
495    ngx_http_request_t  *r;
496    SV                  *key;
497    SV                  *value;
498    ngx_table_elt_t     *header;
499
500    ngx_http_perl_set_request(r);
501
502    key = ST(1);
503    value = ST(2);
504
505    header = ngx_list_push(&r->headers_out.headers);
506    if (header == NULL) {
507        XSRETURN_EMPTY;
508    }
509
510    header->hash = 1;
511
512    if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
513        XSRETURN_EMPTY;
514    }
515
516    if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) {
517        XSRETURN_EMPTY;
518    }
519
520    if (header->key.len == sizeof("Content-Length") - 1
521        && ngx_strncasecmp(header->key.data, (u_char *) "Content-Length",
522                           sizeof("Content-Length") - 1) == 0)
523    {
524        r->headers_out.content_length_n = (off_t) SvIV(value);
525        r->headers_out.content_length = header;
526    }
527
528    if (header->key.len == sizeof("Content-Encoding") - 1
529        && ngx_strncasecmp(header->key.data, (u_char *) "Content-Encoding",
530                           sizeof("Content-Encoding") - 1) == 0)
531    {
532        r->headers_out.content_encoding = header;
533    }
534
535
536void
537filename(r)
538    CODE:
539
540    dXSTARG;
541    size_t                root;
542    ngx_http_request_t   *r;
543    ngx_http_perl_ctx_t  *ctx;
544
545    ngx_http_perl_set_request(r);
546
547    ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
548    if (ctx->filename.data) {
549        goto done;
550    }
551
552    if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) {
553        XSRETURN_UNDEF;
554    }
555
556    ctx->filename.len--;
557    sv_setpv(PL_statname, (char *) ctx->filename.data);
558
559    done:
560
561    ngx_http_perl_set_targ(ctx->filename.data, ctx->filename.len);
562
563    ST(0) = TARG;
564
565
566void
567print(r, ...)
568    CODE:
569
570    ngx_http_request_t  *r;
571    SV                  *sv;
572    int                  i;
573    u_char              *p;
574    size_t               size;
575    STRLEN               len;
576    ngx_buf_t           *b;
577
578    ngx_http_perl_set_request(r);
579
580    if (items == 2) {
581
582        /*
583         * do zero copy for prolate single read-only SV:
584         *     $r->print("some text\n");
585         */
586
587        sv = ST(1);
588
589        if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
590            sv = SvRV(sv);
591        }
592
593        if (SvREADONLY(sv) && SvPOK(sv)) {
594
595            p = (u_char *) SvPV(sv, len);
596
597            if (len == 0) {
598                XSRETURN_EMPTY;
599            }
600
601            b = ngx_calloc_buf(r->pool);
602            if (b == NULL) {
603                XSRETURN_EMPTY;
604            }
605
606            b->memory = 1;
607            b->pos = p;
608            b->last = p + len;
609            b->start = p;
610            b->end = b->last;
611
612            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
613                           "$r->print: read-only SV: %z", len);
614
615            goto out;
616        }
617    }
618
619    size = 0;
620
621    for (i = 1; i < items; i++) {
622
623        sv = ST(i);
624
625        if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
626            sv = SvRV(sv);
627        }
628
629        (void) SvPV(sv, len);
630
631        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
632                       "$r->print: copy SV: %z", len);
633
634        size += len;
635    }
636
637    if (size == 0) {
638        XSRETURN_EMPTY;
639    }
640
641    b = ngx_create_temp_buf(r->pool, size);
642    if (b == NULL) {
643        XSRETURN_EMPTY;
644    }
645
646    for (i = 1; i < items; i++) {
647        sv = ST(i);
648
649        if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
650            sv = SvRV(sv);
651        }
652
653        p = (u_char *) SvPV(sv, len);
654        b->last = ngx_cpymem(b->last, p, len);
655    }
656
657    out:
658
659    (void) ngx_http_perl_output(r, b);
660
661
662void
663sendfile(r, filename, offset = -1, bytes = 0)
664    CODE:
665
666    ngx_http_request_t        *r;
667    char                      *filename;
668    off_t                      offset;
669    size_t                     bytes;
670    ngx_str_t                  path;
671    ngx_buf_t                 *b;
672    ngx_open_file_info_t       of;
673    ngx_http_core_loc_conf_t  *clcf;
674
675    ngx_http_perl_set_request(r);
676
677    filename = SvPV_nolen(ST(1));
678
679    if (filename == NULL) {
680        croak("sendfile(): NULL filename");
681    }
682
683    offset = items < 3 ? -1 : SvIV(ST(2));
684    bytes = items < 4 ? 0 : SvIV(ST(3));
685
686    b = ngx_calloc_buf(r->pool);
687    if (b == NULL) {
688        XSRETURN_EMPTY;
689    }
690
691    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
692    if (b->file == NULL) {
693        XSRETURN_EMPTY;
694    }
695
696    path.len = ngx_strlen(filename);
697
698    path.data = ngx_pnalloc(r->pool, path.len + 1);
699    if (path.data == NULL) {
700        XSRETURN_EMPTY;
701    }
702
703    (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1);
704
705    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
706
707    ngx_memzero(&of, sizeof(ngx_open_file_info_t));
708
709    of.read_ahead = clcf->read_ahead;
710    of.directio = clcf->directio;
711    of.valid = clcf->open_file_cache_valid;
712    of.min_uses = clcf->open_file_cache_min_uses;
713    of.errors = clcf->open_file_cache_errors;
714    of.events = clcf->open_file_cache_events;
715
716    if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
717        XSRETURN_EMPTY;
718    }
719
720    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
721        != NGX_OK)
722    {
723        if (of.err == 0) {
724            XSRETURN_EMPTY;
725        }
726
727        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
728                      "%s \"%s\" failed", of.failed, filename);
729        XSRETURN_EMPTY;
730    }
731
732    if (offset == -1) {
733        offset = 0;
734    }
735
736    if (bytes == 0) {
737        bytes = of.size - offset;
738    }
739
740    b->in_file = 1;
741
742    b->file_pos = offset;
743    b->file_last = offset + bytes;
744
745    b->file->fd = of.fd;
746    b->file->log = r->connection->log;
747    b->file->directio = of.is_directio;
748
749    (void) ngx_http_perl_output(r, b);
750
751
752void
753flush(r)
754    CODE:
755
756    ngx_http_request_t  *r;
757    ngx_buf_t           *b;
758
759    ngx_http_perl_set_request(r);
760
761    b = ngx_calloc_buf(r->pool);
762    if (b == NULL) {
763        XSRETURN_EMPTY;
764    }
765
766    b->flush = 1;
767
768    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush");
769
770    (void) ngx_http_perl_output(r, b);
771
772    XSRETURN_EMPTY;
773
774
775void
776internal_redirect(r, uri)
777    CODE:
778
779    ngx_http_request_t   *r;
780    SV                   *uri;
781    ngx_uint_t            i;
782    ngx_http_perl_ctx_t  *ctx;
783
784    ngx_http_perl_set_request(r);
785
786    uri = ST(1);
787
788    ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
789
790    if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) {
791        XSRETURN_EMPTY;
792    }
793
794    for (i = 0; i < ctx->redirect_uri.len; i++) {
795        if (ctx->redirect_uri.data[i] == '?') {
796
797            ctx->redirect_args.len = ctx->redirect_uri.len - (i + 1);
798            ctx->redirect_args.data = &ctx->redirect_uri.data[i + 1];
799            ctx->redirect_uri.len = i;
800
801            XSRETURN_EMPTY;
802        }
803    }
804
805
806void
807allow_ranges(r)
808    CODE:
809
810    ngx_http_request_t  *r;
811
812    ngx_http_perl_set_request(r);
813
814    r->allow_ranges = 1;
815
816
817void
818unescape(r, text, type = 0)
819    CODE:
820
821    dXSTARG;
822    ngx_http_request_t  *r;
823    SV                  *text;
824    int                  type;
825    u_char              *p, *dst, *src;
826    STRLEN               len;
827
828    ngx_http_perl_set_request(r);
829
830    text = ST(1);
831
832    src = (u_char *) SvPV(text, len);
833
834    p = ngx_pnalloc(r->pool, len + 1);
835    if (p == NULL) {
836        XSRETURN_UNDEF;
837    }
838
839    dst = p;
840
841    type = items < 3 ? 0 : SvIV(ST(2));
842
843    ngx_unescape_uri(&dst, &src, len, (ngx_uint_t) type);
844    *dst = '\0';
845
846    ngx_http_perl_set_targ(p, dst - p);
847
848    ST(0) = TARG;
849
850
851void
852variable(r, name, value = NULL)
853    CODE:
854
855    dXSTARG;
856    ngx_http_request_t         *r;
857    SV                         *name, *value;
858    u_char                     *p, *lowcase;
859    STRLEN                      len;
860    ngx_str_t                   var, val;
861    ngx_uint_t                  i, hash;
862    ngx_http_perl_var_t        *v;
863    ngx_http_perl_ctx_t        *ctx;
864    ngx_http_variable_value_t  *vv;
865
866    ngx_http_perl_set_request(r);
867
868    name = ST(1);
869
870    if (SvROK(name) && SvTYPE(SvRV(name)) == SVt_PV) {
871        name = SvRV(name);
872    }
873
874    if (items == 2) {
875        value = NULL;
876
877    } else {
878        value = ST(2);
879
880        if (SvROK(value) && SvTYPE(SvRV(value)) == SVt_PV) {
881            value = SvRV(value);
882        }
883
884        if (ngx_http_perl_sv2str(aTHX_ r, &val, value) != NGX_OK) {
885            XSRETURN_UNDEF;
886        }
887    }
888
889    p = (u_char *) SvPV(name, len);
890
891    lowcase = ngx_pnalloc(r->pool, len);
892    if (lowcase == NULL) {
893        XSRETURN_UNDEF;
894    }
895
896    hash = ngx_hash_strlow(lowcase, p, len);
897
898    var.len = len;
899    var.data = lowcase;
900#if (NGX_DEBUG)
901
902    if (value) {
903        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
904                       "perl variable: \"%V\"=\"%V\"", &var, &val);
905    } else {
906        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
907                       "perl variable: \"%V\"", &var);
908    }
909#endif
910
911    vv = ngx_http_get_variable(r, &var, hash);
912    if (vv == NULL) {
913        XSRETURN_UNDEF;
914    }
915
916    if (vv->not_found) {
917
918        ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
919
920        if (ctx->variables) {
921
922            v = ctx->variables->elts;
923            for (i = 0; i < ctx->variables->nelts; i++) {
924
925                if (hash != v[i].hash
926                    || len != v[i].name.len
927                    || ngx_strncmp(lowcase, v[i].name.data, len) != 0)
928                {
929                    continue;
930                }
931
932                if (value) {
933                    v[i].value = val;
934                    XSRETURN_UNDEF;
935                }
936
937                ngx_http_perl_set_targ(v[i].value.data, v[i].value.len);
938
939                goto done;
940            }
941        }
942
943        if (value) {
944            if (ctx->variables == NULL) {
945                ctx->variables = ngx_array_create(r->pool, 1,
946                                                  sizeof(ngx_http_perl_var_t));
947                if (ctx->variables == NULL) {
948                    XSRETURN_UNDEF;
949                }
950            }
951
952            v = ngx_array_push(ctx->variables);
953            if (v == NULL) {
954                XSRETURN_UNDEF;
955            }
956
957            v->hash = hash;
958            v->name.len = len;
959            v->name.data = lowcase;
960            v->value = val;
961
962            XSRETURN_UNDEF;
963        }
964
965        XSRETURN_UNDEF;
966    }
967
968    if (value) {
969        vv->len = val.len;
970        vv->valid = 1;
971        vv->no_cacheable = 0;
972        vv->not_found = 0;
973        vv->data = val.data;
974
975        XSRETURN_UNDEF;
976    }
977
978    ngx_http_perl_set_targ(vv->data, vv->len);
979
980    done:
981
982    ST(0) = TARG;
983
984
985void
986sleep(r, sleep, next)
987    CODE:
988
989    ngx_http_request_t   *r;
990    ngx_msec_t            sleep;
991    ngx_http_perl_ctx_t  *ctx;
992
993    ngx_http_perl_set_request(r);
994
995    sleep = (ngx_msec_t) SvIV(ST(1));
996
997    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
998                   "perl sleep: %M", sleep);
999
1000    ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
1001
1002    ctx->next = SvRV(ST(2));
1003
1004    r->connection->write->delayed = 1;
1005    ngx_add_timer(r->connection->write, sleep);
1006
1007    r->write_event_handler = ngx_http_perl_sleep_handler;
1008    r->main->count++;
1009
1010
1011void
1012log_error(r, err, msg)
1013    CODE:
1014
1015    ngx_http_request_t  *r;
1016    SV                  *err, *msg;
1017    u_char              *p;
1018    STRLEN               len;
1019    ngx_err_t            e;
1020
1021    ngx_http_perl_set_request(r);
1022
1023    err = ST(1);
1024
1025    if (SvROK(err) && SvTYPE(SvRV(err)) == SVt_PV) {
1026        err = SvRV(err);
1027    }
1028
1029    e = SvIV(err);
1030
1031    msg = ST(2);
1032
1033    if (SvROK(msg) && SvTYPE(SvRV(msg)) == SVt_PV) {
1034        msg = SvRV(msg);
1035    }
1036
1037    p = (u_char *) SvPV(msg, len);
1038
1039    ngx_log_error(NGX_LOG_ERR, r->connection->log, e, "perl: %s", p);
1040