summaryrefslogtreecommitdiff
path: root/src/mod_proxy_backend_scgi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_proxy_backend_scgi.c')
-rw-r--r--src/mod_proxy_backend_scgi.c475
1 files changed, 0 insertions, 475 deletions
diff --git a/src/mod_proxy_backend_scgi.c b/src/mod_proxy_backend_scgi.c
deleted file mode 100644
index 60e1de83..00000000
--- a/src/mod_proxy_backend_scgi.c
+++ /dev/null
@@ -1,475 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-#include "sys-strings.h"
-#include "inet_ntop_cache.h"
-#include "mod_proxy_core.h"
-#include "mod_proxy_core_protocol.h"
-#include "buffer.h"
-#include "log.h"
-#include "array.h"
-
-#define CORE_PLUGIN "mod_proxy_core"
-
-typedef struct {
- PLUGIN_DATA;
-
- proxy_protocol *protocol;
-} protocol_plugin_data;
-
-/*
-PROXY_CONNECTION_FUNC(proxy_scgi_init) {
- return 1;
-}
-*/
-
-/*
-PROXY_CONNECTION_FUNC(proxy_scgi_cleanup) {
- return 1;
-}
-*/
-
-/**
- * add a key-value pair to the scgi-buffer
- */
-static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
- size_t len;
-
- if (!key || !val) return -1;
-
- len = key_len + val_len + 2;
-
- buffer_prepare_append(env, len);
-
- buffer_append_memory(env, key, key_len);
- env->ptr[env->used++] = '\0';
- buffer_append_memory(env, val, val_len);
- env->ptr[env->used++] = '\0';
-
- return 0;
-}
-
-static int proxy_scgi_get_env_scgi(server *srv, proxy_session *sess, buffer *env_headers) {
- connection *con = sess->remote_con;
- server_socket *srv_sock = con->srv_socket;
- plugin_data *p = sess->p;
- socklen_t our_addr_len;
- sock_addr our_addr;
- const char *s;
- char buf[32];
- int len;
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-#endif
-
- /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
-
- /* request.content_length < SSIZE_MAX, see request.c */
- if(con->request.content_length > 0) {
- len = LI_ltostr(buf, con->request.content_length);
- } else {
- buf[0] = '0';
- buf[1] = '\0';
- len = 1;
- }
- scgi_env_add(env_headers, CONST_STR_LEN("CONTENT_LENGTH"), buf, len);
- scgi_env_add(env_headers, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
-
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
-
- if (con->server_name->used) {
- size_t _len = con->server_name->used - 1;
- char *colon = strchr(con->server_name->ptr, ':');
- if (colon) _len = colon - con->server_name->ptr;
-
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, _len);
- } else {
-#ifdef HAVE_IPV6
- s = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1);
-#else
- s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
-#endif
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
- }
-
- scgi_env_add(env_headers, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
-
- len = LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
-#else
- ntohs(srv_sock->addr.ipv4.sin_port)
-#endif
- );
-
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_PORT"), buf, len);
-
- /* get the server-side of the connection to the client */
- our_addr_len = sizeof(our_addr);
-
- if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
- s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
- } else {
- s = inet_ntop_cache_get_ip(srv, &(our_addr));
- }
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
-
- len = LI_ltostr(buf,
-#ifdef HAVE_IPV6
- ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
-#else
- ntohs(con->dst_addr.ipv4.sin_port)
-#endif
- );
-
- scgi_env_add(env_headers, CONST_STR_LEN("REMOTE_PORT"), buf, len);
-
- s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- scgi_env_add(env_headers, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
-
- if (!buffer_is_empty(con->authed_user)) {
- scgi_env_add(env_headers, CONST_STR_LEN("REMOTE_USER"),
- CONST_BUF_LEN(con->authed_user));
- }
-
- /*
- * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
- * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
- * (6.1.14, 6.1.6, 6.1.7)
- * For AUTHORIZER mode these headers should be omitted.
- */
-
- scgi_env_add(env_headers, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
-
- if (!buffer_is_empty(con->request.pathinfo)) {
- scgi_env_add(env_headers, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
-
- /* PATH_TRANSLATED is only defined if PATH_INFO is set */
-
- buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
- buffer_append_string_buffer(p->tmp_buf, con->request.pathinfo);
- scgi_env_add(env_headers, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->tmp_buf));
- } else {
- scgi_env_add(env_headers, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
- }
-
- /*
- * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
- * http://www.php.net/manual/en/reserved.variables.php
- * treatment of PATH_TRANSLATED is different from the one of CGI specs.
- * TODO: this code should be checked against cgi.fix_pathinfo php
- * parameter.
- */
-
- if (1) {
- scgi_env_add(env_headers, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
- scgi_env_add(env_headers, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
- }
-
- scgi_env_add(env_headers, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
-
- if (!buffer_is_equal(sess->request_uri, con->request.orig_uri)) {
- scgi_env_add(env_headers, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(sess->request_uri));
- }
- if (!buffer_is_empty(con->uri.query)) {
- scgi_env_add(env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
- } else {
- scgi_env_add(env_headers, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
- }
-
- s = get_http_method_name(con->request.http_method);
- scgi_env_add(env_headers, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
- scgi_env_add(env_headers, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
- s = get_http_version_name(con->request.http_version);
- scgi_env_add(env_headers, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
-
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- scgi_env_add(env_headers, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
- }
-#endif
-
- return 0;
-}
-
-/**
- * transform the HTTP-Request headers into CGI notation
- */
-static int proxy_scgi_get_env_request(server *srv, proxy_session *sess, buffer *env_headers) {
- connection *con = sess->remote_con;
- plugin_data *p = sess->p;
- size_t i;
-
- UNUSED(srv);
-
- /* the request header got already copied into the sess->request_headers for us
- * no extra filter is needed
- *
- * prepend a HTTP_ and uppercase the keys
- */
- for (i = 0; i < sess->request_headers->used; i++) {
- data_string *ds;
- size_t j;
-
- ds = (data_string *)sess->request_headers->data[i];
- if (ds->value->used == 0 || ds->key->used == 0) continue;
-
- buffer_reset(p->tmp_buf);
-
- if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_"));
- p->tmp_buf->used--;
- }
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = ds->key->ptr[j];
- if (light_isalpha(c)) {
- /* upper-case */
- c = toupper(c);
- } else if (light_isdigit(c)) {
- /* copy */
- c = c;
- } else {
- c = '_';
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = c;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- scgi_env_add(env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
-
- for (i = 0; i < con->environment->used; i++) {
- data_string *ds;
- size_t j;
-
- ds = (data_string *)con->environment->data[i];
- if (ds->value->used == 0 || ds->key->used == 0) continue;
-
- buffer_reset(p->tmp_buf);
-
- buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
- for (j = 0; j < ds->key->used - 1; j++) {
- char c = ds->key->ptr[j];
- if (light_isalpha(c)) {
- /* upper-case */
- c = toupper(c);
- } else {
- c = '_';
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = c;
- }
- p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- scgi_env_add(env_headers, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
- }
-
- return 0;
-}
-
-PROXY_STREAM_ENCODER_FUNC(proxy_scgi_encode_request_headers) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- size_t headers_len = 0;
- buffer *len_buf;
- buffer *env_headers;
-
- UNUSED(in);
-
- /* get buffer to write headers length into */
- len_buf = chunkqueue_get_append_buffer(out);
-
- /* write SCGI request headers */
- env_headers = chunkqueue_get_append_buffer(out);
- buffer_prepare_copy(env_headers, 1024);
- proxy_scgi_get_env_scgi(srv, sess, env_headers);
- proxy_scgi_get_env_request(srv, sess, env_headers);
- headers_len = env_headers->used;
- out->bytes_in += headers_len;
-
- /* append "," after headers */
- buffer_append_memory(env_headers, CONST_STR_LEN(","));
- env_headers->used++; /* this is needed because the network will only write "used - 1" bytes */
- out->bytes_in++;
-
- /* prepend [headers_len]: */
- buffer_append_long(len_buf, headers_len);
- buffer_append_string_len(len_buf, CONST_STR_LEN(":"));
- out->bytes_in += len_buf->used - 1;
-
- return HANDLER_FINISHED;
-}
-
-/**
- * parse the HTTP response header
- */
-static handler_t proxy_scgi_parse_response_headers(proxy_session *sess, chunkqueue *in) {
- http_response_reset(sess->resp);
-
- /* http response parser. */
- switch(http_response_parse_cq(in, sess->resp)) {
- case PARSE_ERROR:
- /* bad gateway */
- http_response_reset(sess->resp);
- sess->have_response_headers = 1;
- sess->resp->status = 502;
- return HANDLER_ERROR;
- case PARSE_NEED_MORE:
- return HANDLER_GO_ON;
- case PARSE_SUCCESS:
- default:
- /* finished parsing response headers. */
- sess->have_response_headers = 1;
- return HANDLER_FINISHED;
- }
-}
-
-PROXY_STREAM_DECODER_FUNC(proxy_scgi_stream_decoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *in = proxy_con->recv;
- chunk *c;
-
- UNUSED(srv);
-
- if (in->first == NULL) {
- if ((sess->content_length >= 0 && sess->bytes_read == sess->content_length) || in->is_closed) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
- }
-
- /* parse response headers. */
- if (!sess->have_response_headers) {
- handler_t rc = proxy_scgi_parse_response_headers(sess, in);
- if (rc != HANDLER_FINISHED) return rc;
- }
-
- /* no chunked encoding, ok, perhaps a content-length ? */
-
- chunkqueue_remove_finished_chunks(in);
- for (c = in->first; c; c = c->next) {
- buffer *b;
-
- if (c->mem->used == 0) continue;
-
- out->bytes_in += c->mem->used - c->offset - 1;
- in->bytes_out += c->mem->used - c->offset - 1;
-
- sess->bytes_read += c->mem->used - c->offset - 1;
-
- if (c->offset == 0) {
- /* we are copying the whole buffer, just steal it */
-
- chunkqueue_steal_chunk(out, c);
- } else {
- b = chunkqueue_get_append_buffer(out);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1; /* marks is read */
- }
-
- if (sess->bytes_read == sess->content_length) {
- break;
- }
- }
-
- if (in->is_closed || sess->bytes_read == sess->content_length) {
- sess->is_request_finished = 1;
- return HANDLER_FINISHED; /* finished */
- }
-
- return HANDLER_GO_ON;
-}
-
-/**
- * transform the content-stream into a valid HTTP-content-stream
- *
- * as we don't apply chunked-encoding here, pass it on AS IS
- */
-PROXY_STREAM_ENCODER_FUNC(proxy_scgi_stream_encoder) {
- proxy_connection *proxy_con = sess->proxy_con;
- chunkqueue *out = proxy_con->send;
- int we_have = 0;
-
- UNUSED(srv);
-
- /* output queue closed, can't encode any more data. */
- if(out->is_closed) return HANDLER_FINISHED;
-
- /* encode all request content data into output queue. */
- we_have = chunkqueue_steal_all_chunks(out, in);
- in->bytes_out += we_have;
- out->bytes_in += we_have;
-
- if (in->bytes_in == in->bytes_out && in->is_closed) {
- out->is_closed = 1;
- return HANDLER_FINISHED;
- }
-
- return HANDLER_GO_ON;
-}
-
-INIT_FUNC(mod_proxy_backend_scgi_init) {
- mod_proxy_core_plugin_data *core_data;
- protocol_plugin_data *p;
-
- /* get the plugin_data of the core-plugin */
- core_data = plugin_get_config(srv, CORE_PLUGIN);
- if(!core_data) return NULL;
-
- p = calloc(1, sizeof(*p));
-
- /* define protocol handler callbacks */
- p->protocol = core_data->proxy_register_protocol("scgi");
-
- /*
- p->protocol->proxy_stream_init = proxy_scgi_init;
- p->protocol->proxy_stream_cleanup = proxy_scgi_cleanup;
- */
- p->protocol->proxy_stream_decoder = proxy_scgi_stream_decoder;
- p->protocol->proxy_stream_encoder = proxy_scgi_stream_encoder;
- p->protocol->proxy_encode_request_headers = proxy_scgi_encode_request_headers;
-
- return p;
-}
-
-FREE_FUNC(mod_proxy_backend_scgi_free) {
- protocol_plugin_data *p = p_d;
-
- UNUSED(srv);
-
- if (!p) return HANDLER_GO_ON;
-
- free(p);
-
- return HANDLER_GO_ON;
-}
-
-LI_EXPORT int mod_proxy_backend_scgi_plugin_init(plugin *p);
-LI_EXPORT int mod_proxy_backend_scgi_plugin_init(plugin *p) {
- data_string *ds;
-
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mod_proxy_backend_scgi");
-
- p->init = mod_proxy_backend_scgi_init;
- p->cleanup = mod_proxy_backend_scgi_free;
-
- p->data = NULL;
-
- ds = data_string_init();
- buffer_copy_string_len(ds->value, CONST_STR_LEN(CORE_PLUGIN));
- array_insert_unique(p->required_plugins, (data_unset *)ds);
-
- return 0;
-}
-
-