aboutsummaryrefslogtreecommitdiff
path: root/src/http/modules/perl/nginx.xs
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2006-01-16 14:56:53 +0000
committerIgor Sysoev <igor@sysoev.ru>2006-01-16 14:56:53 +0000
commit9bf11aa19366f45bcd10a0917034acb45f89b259 (patch)
treec7231ce937ab196c89608185e59ab544224e4da8 /src/http/modules/perl/nginx.xs
parent243edbb727c49ac25355e109a097f1ca2d9e1e44 (diff)
downloadnginx-9bf11aa19366f45bcd10a0917034acb45f89b259.tar.gz
nginx-9bf11aa19366f45bcd10a0917034acb45f89b259.zip
nginx-0.3.21-RELEASE importrelease-0.3.21
*) Feature: the ngx_http_perl_module. *) Change: the "valid_referers" directive allows the referreres without URI part.
Diffstat (limited to 'src/http/modules/perl/nginx.xs')
-rw-r--r--src/http/modules/perl/nginx.xs551
1 files changed, 551 insertions, 0 deletions
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
new file mode 100644
index 000000000..21d2deb99
--- /dev/null
+++ b/src/http/modules/perl/nginx.xs
@@ -0,0 +1,551 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#define PERL_NO_GET_CONTEXT
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <ngx_http_perl_module.h>
+
+
+static ngx_int_t
+ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv)
+{
+ u_char *p;
+ STRLEN len;
+
+ if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
+ sv = SvRV(sv);
+ }
+
+ p = (u_char *) SvPV(sv, len);
+
+ s->len = len;
+
+ if (SvREADONLY(sv)) {
+ s->data = p;
+ return NGX_OK;
+ }
+
+ s->data = ngx_palloc(r->pool, len);
+ if (s->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(s->data, p, len);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b)
+{
+ ngx_chain_t *cl, out;
+ ngx_http_perl_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
+
+ if (ctx->ssi) {
+ cl = ngx_alloc_chain_link(r->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = b;
+ cl->next = NULL;
+ *ctx->ssi->last_out = cl;
+ ctx->ssi->last_out = &cl->next;
+
+ return NGX_OK;
+ }
+
+ out.buf = b;
+ out.next = NULL;
+
+ return ngx_http_output_filter(r, &out);
+}
+
+
+MODULE = nginx PACKAGE = nginx
+
+
+int
+send_http_header(r, ...)
+ nginx r
+
+ PREINIT:
+
+ SV *sv;
+
+ CODE:
+
+ if (r->headers_out.status == 0) {
+ r->headers_out.status = NGX_HTTP_OK;
+ }
+
+ if (items != 1) {
+ sv = ST(1);
+
+ if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv)
+ != NGX_OK)
+ {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ } else {
+ if (r->headers_out.content_type.len == 0) {
+ if (ngx_http_set_content_type(r) != NGX_OK) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+ }
+ }
+
+ RETVAL = ngx_http_send_header(r);
+
+ done:
+
+ OUTPUT:
+ RETVAL
+
+
+int
+header_only(r)
+ nginx r
+
+ CODE:
+ RETVAL = r->header_only;
+
+ OUTPUT:
+ RETVAL
+
+
+# The returning "char *" is more quickly than creating SV, because SV returned
+# from XS is never used as permanent storage. Even in simple case:
+# "$uri = $r->uri" the SV returned by $r->uri is copied to $uri's SV.
+
+char *
+uri(r, ...)
+ nginx r
+
+ CODE:
+
+ if (items != 1) {
+ croak("$r->uri(text) is not implemented");
+ }
+
+ RETVAL = ngx_palloc(r->pool, r->uri.len + 1);
+ if (RETVAL == NULL) {
+ XSRETURN_UNDEF;
+ }
+
+ ngx_cpystrn((u_char *) RETVAL, r->uri.data, r->uri.len + 1);
+
+ OUTPUT:
+ RETVAL
+
+
+char *
+query_string(r, ...)
+ nginx r
+
+ CODE:
+
+ if (items != 1) {
+ croak("$r->query_string(text) is not implemented");
+ }
+
+ RETVAL = ngx_palloc(r->pool, r->args.len + 1);
+ if (RETVAL == NULL) {
+ XSRETURN_UNDEF;
+ }
+
+ ngx_cpystrn((u_char *) RETVAL, r->args.data, r->args.len + 1);
+
+ OUTPUT:
+ RETVAL
+
+
+char *
+header_in(r, key)
+ nginx r
+ SV *key
+
+ PREINIT:
+
+ u_char *p;
+ STRLEN len;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
+
+ CODE:
+
+ if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) {
+ key = SvRV(key);
+ }
+
+ p = (u_char *) SvPV(key, len);
+
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ if (len != header[i].key.len
+ || ngx_strcasecmp(p, header[i].key.data) != 0)
+ {
+ continue;
+ }
+
+ RETVAL = (char *) header[i].value.data;
+
+ goto done;
+ }
+
+ XSRETURN_UNDEF;
+
+ done:
+
+ OUTPUT:
+ RETVAL
+
+
+int
+header_out(r, key, value)
+ nginx r
+ SV *key
+ SV *value
+
+ PREINIT:
+
+ ngx_table_elt_t *header;
+
+ CODE:
+
+ header = ngx_list_push(&r->headers_out.headers);
+ if (header == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ header->hash = 1;
+
+ if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ if (header->key.len == sizeof("Content-Length") - 1
+ && ngx_strncasecmp(header->key.data, "Content-Length",
+ sizeof("Content-Length") - 1) == 0
+ && SvIOK(value))
+ {
+ r->headers_out.content_length_n = (ssize_t) SvIV(value);;
+ r->headers_out.content_length = header;
+ }
+
+ RETVAL = NGX_OK;
+
+ done:
+
+ OUTPUT:
+ RETVAL
+
+
+char *
+filename(r)
+ nginx r
+
+ PREINIT:
+
+ ngx_str_t path;
+ ngx_http_perl_ctx_t *ctx;
+
+ CODE:
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
+ if (ctx->filename) {
+ goto done;
+ }
+
+ if (ngx_http_map_uri_to_path(r, &path, 0) == NULL) {
+ XSRETURN_UNDEF;
+ }
+
+ ctx->filename = (char *) path.data;
+
+ sv_setpv(PL_statname, ctx->filename);
+
+ done:
+
+ RETVAL = ctx->filename;
+
+ OUTPUT:
+ RETVAL
+
+
+int
+print(r, ...)
+ nginx r
+
+ PREINIT:
+
+ SV *sv;
+ int i;
+ u_char *p;
+ size_t size;
+ STRLEN len;
+ ngx_buf_t *b;
+
+ CODE:
+
+ RETVAL = NGX_OK;
+
+ if (items == 2) {
+
+ /*
+ * do zero copy for prolate single read-only SV:
+ * $r->print("some text\n");
+ */
+
+ sv = ST(1);
+
+ if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
+ sv = SvRV(sv);
+ }
+
+ if (SvREADONLY(sv)) {
+
+ p = (u_char *) SvPV(sv, len);
+
+ if (len == 0) {
+ goto done;
+ }
+
+ b = ngx_calloc_buf(r->pool);
+ if (b == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ b->memory = 1;
+ b->pos = p;
+ b->last = p + len;
+ b->start = p;
+ b->end = b->last;
+
+ goto out;
+ }
+ }
+
+ size = 0;
+
+ for (i = 1; i < items; i++) {
+
+ sv = ST(i);
+
+ if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
+ sv = SvRV(sv);
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "SV: %p %d %Xd",
+ sv, SvREFCNT(sv), SvREADONLY(sv));
+
+ (void) SvPV(sv, len);
+
+ size += len;
+ }
+
+ if (size == 0) {
+ goto done;
+ }
+
+ b = ngx_create_temp_buf(r->pool, size);
+ if (b == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ for (i = 1; i < items; i++) {
+ sv = ST(i);
+
+ if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) {
+ sv = SvRV(sv);
+ }
+
+ p = (u_char *) SvPV(sv, len);
+ b->last = ngx_cpymem(b->last, p, len);
+ }
+
+ out:
+
+ RETVAL = ngx_http_perl_output(r, b);
+
+ done:
+
+ OUTPUT:
+ RETVAL
+
+
+int
+sendfile(r, filename)
+ nginx r
+ char *filename
+
+ PREINIT:
+
+ ngx_fd_t fd;
+ ngx_buf_t *b;
+ ngx_file_info_t fi;
+ ngx_pool_cleanup_t *cln;
+ ngx_pool_cleanup_file_t *clnf;
+
+ CODE:
+
+ if (filename == NULL) {
+ croak("sendfile(): NULL filename");
+ }
+
+ b = ngx_calloc_buf(r->pool);
+ if (b == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
+ if (b->file == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
+ if (cln == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+
+ if (fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", filename);
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", filename);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", filename);
+ }
+
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ cln->handler = ngx_pool_cleanup_file;
+ clnf = cln->data;
+
+ clnf->fd = fd;
+ clnf->name = (u_char *) "";
+ clnf->log = r->pool->log;
+
+ b->in_file = 1;
+ b->file_pos = 0;
+ b->file_last = ngx_file_size(&fi);
+
+ b->file->fd = fd;
+ b->file->log = r->connection->log;
+
+ RETVAL = ngx_http_perl_output(r, b);
+
+ done:
+
+ OUTPUT:
+ RETVAL
+
+
+int
+rflush(r)
+ nginx r
+
+ PREINIT:
+
+ ngx_buf_t *b;
+
+ CODE:
+
+ b = ngx_calloc_buf(r->pool);
+ if (b == NULL) {
+ RETVAL = NGX_ERROR;
+ goto done;
+ }
+
+ b->flush = 1;
+
+ RETVAL = ngx_http_perl_output(r, b);
+
+ done:
+
+ OUTPUT:
+ RETVAL
+
+
+void
+internal_redirect(r, uri)
+ nginx r
+ SV *uri
+
+ PREINIT:
+
+ ngx_uint_t i;
+ ngx_http_perl_ctx_t *ctx;
+
+ CODE:
+
+ 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;
+ }
+ }