From 0cc7a3aba872ab278c8d0f22fb10aac3fb07c1c5 Mon Sep 17 00:00:00 2001 From: Hakase Date: Sat, 13 Jul 2019 19:14:22 +0900 Subject: [PATCH] Latest update - 7534 --- .../modules/ngx_http_gzip_filter_module.c | 124 +----- src/http/modules/perl/nginx.xs | 411 ++++++++++++------ src/http/modules/perl/ngx_http_perl_module.c | 81 +++- src/http/modules/perl/ngx_http_perl_module.h | 10 +- 4 files changed, 367 insertions(+), 259 deletions(-) diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index e4c343c..48f3dd7 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -55,44 +55,23 @@ typedef struct { unsigned redo:1; unsigned done:1; unsigned nomem:1; - unsigned gzheader:1; unsigned buffering:1; unsigned intel:1; size_t zin; size_t zout; - uint32_t crc32; z_stream zstream; ngx_http_request_t *request; } ngx_http_gzip_ctx_t; -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - -struct gztrailer { - uint32_t crc32; - uint32_t zlen; -}; - -#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ - -struct gztrailer { - u_char crc32[4]; - u_char zlen[4]; -}; - -#endif - - static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in); static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); -static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, - ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, @@ -446,12 +425,6 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return ctx->busy ? NGX_AGAIN : NGX_OK; } - if (!ctx->gzheader) { - if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) { - goto failed; - } - } - rc = ngx_http_next_body_filter(r, ctx->out); if (rc == NGX_ERROR) { @@ -643,7 +616,7 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ctx->zstream.opaque = ctx; rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED, - - ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY); + ctx->wbits + 16, ctx->memlevel, Z_DEFAULT_STRATEGY); if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, @@ -652,45 +625,12 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, } ctx->last_out = &ctx->out; - ctx->crc32 = crc32(0L, Z_NULL, 0); ctx->flush = Z_NO_FLUSH; return NGX_OK; } -static ngx_int_t -ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) -{ - ngx_buf_t *b; - ngx_chain_t *cl; - static u_char gzheader[10] = - { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = gzheader; - b->last = b->pos + 10; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = ctx->out; - ctx->out = cl; - - ctx->gzheader = 1; - - return NGX_OK; -} - - static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { @@ -743,14 +683,9 @@ ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } else if (ctx->in_buf->flush) { ctx->flush = Z_SYNC_FLUSH; - } - if (ctx->zstream.avail_in) { - - ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, - ctx->zstream.avail_in); - - } else if (ctx->flush == Z_NO_FLUSH) { + } else if (ctx->zstream.avail_in == 0) { + /* ctx->flush == Z_NO_FLUSH */ return NGX_AGAIN; } @@ -932,13 +867,11 @@ static ngx_int_t ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - int rc; - ngx_buf_t *b; - ngx_chain_t *cl; - struct gztrailer *trailer; + int rc; + ngx_chain_t *cl; ctx->zin = ctx->zstream.total_in; - ctx->zout = 10 + ctx->zstream.total_out + 8; + ctx->zout = ctx->zstream.total_out; rc = deflateEnd(&ctx->zstream); @@ -960,50 +893,7 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, *ctx->last_out = cl; ctx->last_out = &cl->next; - if (ctx->zstream.avail_out >= 8) { - trailer = (struct gztrailer *) ctx->out_buf->last; - ctx->out_buf->last += 8; - ctx->out_buf->last_buf = 1; - - } else { - b = ngx_create_temp_buf(r->pool, 8); - if (b == NULL) { - return NGX_ERROR; - } - - b->last_buf = 1; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - trailer = (struct gztrailer *) b->pos; - b->last += 8; - } - -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - - trailer->crc32 = ctx->crc32; - trailer->zlen = ctx->zin; - -#else - - trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); - trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); - trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); - trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); - - trailer->zlen[0] = (u_char) (ctx->zin & 0xff); - trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); - trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); - trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); - -#endif + ctx->out_buf->last_buf = 1; ctx->zstream.avail_in = 0; ctx->zstream.avail_out = 0; diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 848e501..309b7cb 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -15,8 +15,10 @@ #include "XSUB.h" -#define ngx_http_perl_set_request(r) \ - r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) +#define ngx_http_perl_set_request(r, ctx) \ + \ + ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \ + r = ctx->request #define ngx_http_perl_set_targ(p, len) \ @@ -64,14 +66,12 @@ ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv) static ngx_int_t -ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) +ngx_http_perl_output(ngx_http_request_t *r, ngx_http_perl_ctx_t *ctx, + ngx_buf_t *b) { - ngx_chain_t out; + ngx_chain_t out; #if (NGX_HTTP_SSI) - ngx_chain_t *cl; - ngx_http_perl_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); + ngx_chain_t *cl; if (ctx->ssi) { cl = ngx_alloc_chain_link(r->pool); @@ -105,9 +105,14 @@ void status(r, code) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("status(): cannot be used in variable handler"); + } r->headers_out.status = SvIV(ST(1)); @@ -121,10 +126,28 @@ void send_http_header(r, ...) CODE: - ngx_http_request_t *r; - SV *sv; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *sv; + ngx_int_t rc; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("send_http_header(): called after error"); + } + + if (ctx->variable) { + croak("send_http_header(): cannot be used in variable handler"); + } + + if (ctx->header_sent) { + croak("send_http_header(): header already sent"); + } + + if (ctx->redirect_uri.len) { + croak("send_http_header(): cannot be used with internal_redirect()"); + } if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; @@ -136,20 +159,30 @@ send_http_header(r, ...) if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } r->headers_out.content_type_len = r->headers_out.content_type.len; } else { if (ngx_http_set_content_type(r) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_set_content_type() failed"); } } + ctx->header_sent = 1; + r->disable_not_modified = 1; - (void) ngx_http_send_header(r); + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK) { + ctx->error = 1; + ctx->status = rc; + croak("ngx_http_send_header() failed"); + } void @@ -157,9 +190,10 @@ header_only(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); sv_upgrade(TARG, SVt_IV); sv_setiv(TARG, r->header_only); @@ -172,9 +206,10 @@ uri(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->uri.data, r->uri.len); ST(0) = TARG; @@ -185,9 +220,10 @@ args(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->args.data, r->args.len); ST(0) = TARG; @@ -198,9 +234,10 @@ request_method(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); ST(0) = TARG; @@ -211,9 +248,10 @@ remote_addr(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->connection->addr_text.data, r->connection->addr_text.len); @@ -226,6 +264,7 @@ header_in(r, key) dXSTARG; ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *key; u_char *p, *lowcase_key, *value, sep; STRLEN len; @@ -237,7 +276,7 @@ header_in(r, key) ngx_http_header_t *hh; ngx_http_core_main_conf_t *cmcf; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); key = ST(1); @@ -251,7 +290,8 @@ header_in(r, key) lowcase_key = ngx_pnalloc(r->pool, len); if (lowcase_key == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } hash = ngx_hash_strlow(lowcase_key, p, len); @@ -311,7 +351,8 @@ header_in(r, key) value = ngx_pnalloc(r->pool, size); if (value == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } p = value; @@ -373,14 +414,22 @@ has_request_body(r, next) dXSTARG; ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("has_request_body(): cannot be used in variable handler"); + } + + if (ctx->next) { + croak("has_request_body(): another handler active"); + } if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { XSRETURN_UNDEF; } - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); ctx->next = SvRV(ST(1)); r->request_body_in_single_buf = 1; @@ -391,7 +440,14 @@ has_request_body(r, next) r->request_body_file_log_level = 0; } - ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ctx->error = 1; + ctx->status = rc; + ctx->next = NULL; + croak("ngx_http_read_client_request_body() failed"); + } sv_upgrade(TARG, SVt_IV); sv_setiv(TARG, 1); @@ -404,13 +460,14 @@ request_body(r) CODE: dXSTARG; - ngx_http_request_t *r; - u_char *p, *data; - size_t len; - ngx_buf_t *buf; - ngx_chain_t *cl; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + u_char *p, *data; + size_t len; + ngx_buf_t *buf; + ngx_chain_t *cl; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->request_body == NULL || r->request_body->temp_file @@ -438,7 +495,8 @@ request_body(r) p = ngx_pnalloc(r->pool, len); if (p == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } data = p; @@ -465,9 +523,10 @@ request_body_file(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->request_body == NULL || r->request_body->temp_file == NULL) { XSRETURN_UNDEF; @@ -483,42 +542,66 @@ void discard_request_body(r) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); - ngx_http_discard_request_body(r); + if (ctx->variable) { + croak("discard_request_body(): cannot be used in variable handler"); + } + + rc = ngx_http_discard_request_body(r); + + if (rc != NGX_OK) { + ctx->error = 1; + ctx->status = rc; + croak("ngx_http_discard_request_body() failed"); + } void header_out(r, key, value) CODE: - ngx_http_request_t *r; - SV *key; - SV *value; - ngx_table_elt_t *header; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *key; + SV *value; + ngx_table_elt_t *header; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("header_out(): called after error"); + } + + if (ctx->variable) { + croak("header_out(): cannot be used in variable handler"); + } key = ST(1); value = ST(2); header = ngx_list_push(&r->headers_out.headers); if (header == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_list_push() failed"); } header->hash = 1; if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { header->hash = 0; - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) { header->hash = 0; - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } if (header->key.len == sizeof("Content-Length") - 1 @@ -542,19 +625,19 @@ filename(r) CODE: dXSTARG; - size_t root; ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + size_t root; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); if (ctx->filename.data) { goto done; } if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_map_uri_to_path() failed"); } ctx->filename.len--; @@ -571,15 +654,29 @@ void print(r, ...) CODE: - ngx_http_request_t *r; - SV *sv; - int i; - u_char *p; - size_t size; - STRLEN len; - ngx_buf_t *b; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *sv; + int i; + u_char *p; + size_t size; + STRLEN len; + ngx_int_t rc; + ngx_buf_t *b; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("print(): called after error"); + } + + if (ctx->variable) { + croak("print(): cannot be used in variable handler"); + } + + if (!ctx->header_sent) { + croak("print(): header not sent"); + } if (items == 2) { @@ -604,7 +701,8 @@ print(r, ...) b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->memory = 1; @@ -644,7 +742,8 @@ print(r, ...) b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_create_temp_buf() failed"); } for (i = 1; i < items; i++) { @@ -660,7 +759,12 @@ print(r, ...) out: - (void) ngx_http_perl_output(r, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } void @@ -668,15 +772,29 @@ sendfile(r, filename, offset = -1, bytes = 0) CODE: ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; char *filename; off_t offset; size_t bytes; + ngx_int_t rc; ngx_str_t path; ngx_buf_t *b; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("sendfile(): called after error"); + } + + if (ctx->variable) { + croak("sendfile(): cannot be used in variable handler"); + } + + if (!ctx->header_sent) { + croak("sendfile(): header not sent"); + } filename = SvPV_nolen(ST(1)); @@ -689,19 +807,22 @@ sendfile(r, filename, offset = -1, bytes = 0) b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_pcalloc() failed"); } path.len = ngx_strlen(filename); path.data = ngx_pnalloc(r->pool, path.len + 1); if (path.data == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1); @@ -718,19 +839,23 @@ sendfile(r, filename, offset = -1, bytes = 0) of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_set_disable_symlinks() failed"); } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err == 0) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_open_cached_file() failed"); } ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, filename); - XSRETURN_EMPTY; + + ctx->error = 1; + croak("ngx_open_cached_file() failed"); } if (offset == -1) { @@ -750,28 +875,53 @@ sendfile(r, filename, offset = -1, bytes = 0) b->file->log = r->connection->log; b->file->directio = of.is_directio; - (void) ngx_http_perl_output(r, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } void flush(r) CODE: - ngx_http_request_t *r; - ngx_buf_t *b; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; + ngx_buf_t *b; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("flush(): called after error"); + } + + if (ctx->variable) { + croak("flush(): cannot be used in variable handler"); + } + + if (!ctx->header_sent) { + croak("flush(): header not sent"); + } b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->flush = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); - (void) ngx_http_perl_output(r, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } XSRETURN_EMPTY; @@ -781,29 +931,25 @@ internal_redirect(r, uri) CODE: ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *uri; ngx_uint_t i; - ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("internal_redirect(): cannot be used in variable handler"); + } + + if (ctx->header_sent) { + croak("internal_redirect(): header already sent"); + } uri = ST(1); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { - XSRETURN_EMPTY; - } - - for (i = 0; i < ctx->redirect_uri.len; i++) { - if (ctx->redirect_uri.data[i] == '?') { - - ctx->redirect_args.len = ctx->redirect_uri.len - (i + 1); - ctx->redirect_args.data = &ctx->redirect_uri.data[i + 1]; - ctx->redirect_uri.len = i; - - XSRETURN_EMPTY; - } + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } @@ -811,9 +957,14 @@ void allow_ranges(r) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("allow_ranges(): cannot be used in variable handler"); + } r->allow_ranges = 1; @@ -823,13 +974,14 @@ unescape(r, text, type = 0) CODE: dXSTARG; - ngx_http_request_t *r; - SV *text; - int type; - u_char *p, *dst, *src; - STRLEN len; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *text; + int type; + u_char *p, *dst, *src; + STRLEN len; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); text = ST(1); @@ -837,7 +989,8 @@ unescape(r, text, type = 0) p = ngx_pnalloc(r->pool, len + 1); if (p == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } dst = p; @@ -858,16 +1011,16 @@ variable(r, name, value = NULL) dXSTARG; ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *name, *value; u_char *p, *lowcase; STRLEN len; ngx_str_t var, val; ngx_uint_t i, hash; ngx_http_perl_var_t *v; - ngx_http_perl_ctx_t *ctx; ngx_http_variable_value_t *vv; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); name = ST(1); @@ -886,7 +1039,8 @@ variable(r, name, value = NULL) } if (ngx_http_perl_sv2str(aTHX_ r, &val, value) != NGX_OK) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } } @@ -894,7 +1048,8 @@ variable(r, name, value = NULL) lowcase = ngx_pnalloc(r->pool, len); if (lowcase == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } hash = ngx_hash_strlow(lowcase, p, len); @@ -914,13 +1069,12 @@ variable(r, name, value = NULL) vv = ngx_http_get_variable(r, &var, hash); if (vv == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_get_variable() failed"); } if (vv->not_found) { - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - if (ctx->variables) { v = ctx->variables->elts; @@ -949,13 +1103,15 @@ variable(r, name, value = NULL) ctx->variables = ngx_array_create(r->pool, 1, sizeof(ngx_http_perl_var_t)); if (ctx->variables == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_array_create() failed"); } } v = ngx_array_push(ctx->variables); if (v == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_array_push() failed"); } v->hash = hash; @@ -991,18 +1147,24 @@ sleep(r, sleep, next) CODE: ngx_http_request_t *r; - ngx_msec_t sleep; ngx_http_perl_ctx_t *ctx; + ngx_msec_t sleep; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("sleep(): cannot be used in variable handler"); + } + + if (ctx->next) { + croak("sleep(): another handler active"); + } sleep = (ngx_msec_t) SvIV(ST(1)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl sleep: %M", sleep); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - ctx->next = SvRV(ST(2)); r->connection->write->delayed = 1; @@ -1016,13 +1178,14 @@ void log_error(r, err, msg) CODE: - ngx_http_request_t *r; - SV *err, *msg; - u_char *p; - STRLEN len; - ngx_err_t e; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *err, *msg; + u_char *p; + STRLEN len; + ngx_err_t e; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); err = ST(1); diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 6d3be91..f3fc629 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -43,7 +43,8 @@ static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf, static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log); static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, - HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); + ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args, + ngx_str_t *handler, ngx_str_t *rv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); @@ -183,6 +184,7 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) SV *sub; ngx_int_t rc; ngx_str_t uri, args, *handler; + ngx_uint_t flags; ngx_http_perl_ctx_t *ctx; ngx_http_perl_loc_conf_t *plcf; ngx_http_perl_main_conf_t *pmcf; @@ -199,6 +201,8 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); @@ -220,26 +224,20 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) ctx->next = NULL; } - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler, - NULL); + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sub, NULL, + handler, NULL); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler done: %i", rc); - if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return; - } - if (rc > 600) { rc = NGX_OK; } if (ctx->redirect_uri.len) { uri = ctx->redirect_uri; - args = ctx->redirect_args; } else { uri.len = 0; @@ -248,13 +246,32 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) ctx->filename.data = NULL; ctx->redirect_uri.len = 0; + if (rc == NGX_ERROR) { + ngx_http_finalize_request(r, rc); + return; + } + if (ctx->done || ctx->next) { ngx_http_finalize_request(r, NGX_DONE); return; } if (uri.len) { - ngx_http_internal_redirect(r, &uri, &args); + if (uri.data[0] == '@') { + ngx_http_named_location(r, &uri); + + } else { + ngx_str_null(&args); + flags = NGX_HTTP_LOG_UNSAFE; + + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_http_internal_redirect(r, &uri, &args); + } + ngx_http_finalize_request(r, NGX_DONE); return; } @@ -299,6 +316,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_int_t rc; ngx_str_t value; + ngx_uint_t saved; ngx_http_perl_ctx_t *ctx; ngx_http_perl_main_conf_t *pmcf; @@ -314,8 +332,13 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } + saved = ctx->variable; + ctx->variable = 1; + pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); value.data = NULL; @@ -326,7 +349,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, PERL_SET_CONTEXT(pmcf->perl); PERL_SET_INTERP(pmcf->perl); - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL, + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, pv->sub, NULL, &pv->handler, &value); } @@ -342,6 +365,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, v->not_found = 1; } + ctx->variable = saved; ctx->filename.data = NULL; ctx->redirect_uri.len = 0; @@ -377,11 +401,14 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); ctx->ssi = ssi_ctx; + ctx->header_sent = 1; handler = params[NGX_HTTP_PERL_SSI_SUB]; handler->data[handler->len] = '\0'; @@ -435,8 +462,8 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, asv = NULL; } - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, - NULL); + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sv, asv, + handler, NULL); SvREFCNT_dec(sv); @@ -672,8 +699,9 @@ ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log) static ngx_int_t -ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, - SV **args, ngx_str_t *handler, ngx_str_t *rv) +ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, + ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args, + ngx_str_t *handler, ngx_str_t *rv) { SV *sv; int n, status; @@ -687,12 +715,15 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, status = 0; + ctx->error = 0; + ctx->status = NGX_OK; + ENTER; SAVETMPS; PUSHMARK(sp); - sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx)); + sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(ctx))), nginx)); XPUSHs(sv); if (args) { @@ -736,6 +767,18 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, FREETMPS; LEAVE; + if (ctx->error) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "call_sv: error, %d", ctx->status); + + if (ctx->status != NGX_OK) { + return ctx->status; + } + + return NGX_ERROR; + } + /* check $@ */ if (SvTRUE(ERRSV)) { @@ -750,6 +793,12 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, return NGX_ERROR; } + ctx->redirect_uri.len = 0; + + if (ctx->header_sent) { + return NGX_ERROR; + } + return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index 5e60b03..8fa59a4 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -21,13 +21,19 @@ typedef ngx_http_request_t *nginx; typedef struct { + ngx_http_request_t *request; + ngx_str_t filename; ngx_str_t redirect_uri; - ngx_str_t redirect_args; SV *next; - ngx_uint_t done; /* unsigned done:1; */ + ngx_int_t status; + + unsigned done:1; + unsigned error:1; + unsigned variable:1; + unsigned header_sent:1; ngx_array_t *variables; /* array of ngx_http_perl_var_t */