summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2018-02-13 22:38:48 +0000
committerGraham Leggett <minfrin@apache.org>2018-02-13 22:38:48 +0000
commit99c59e098103ccf13b833281ec08493e042dfee0 (patch)
treee66d0e5d2ca654fb5f14946ce780fbfe6f42774d
parent90793a4c7028f1a4a060954025dc1666b9f869d3 (diff)
downloadhttpd-99c59e098103ccf13b833281ec08493e042dfee0.tar.gz
mod_proxy_uwsgi: Add in UWSGI proxy (sub)module
trunk patch: http://svn.apache.org/r1810358 http://svn.apache.org/r1810362 http://svn.apache.org/r1810363 http://svn.apache.org/r1810365 http://svn.apache.org/r1810447 http://svn.apache.org/r1816919 http://svn.apache.org/r1816922 http://svn.apache.org/r1818013 http://svn.apache.org/r1818280 +1: jim, icing, minfrin icing: tested on ubuntu 16.04 with a simple uwsgi python app. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1824184 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES3
-rw-r--r--STATUS16
-rw-r--r--docs/manual/mod/mod_proxy_uwsgi.xml78
-rw-r--r--docs/manual/mod/mod_proxy_uwsgi.xml.meta12
-rw-r--r--modules/proxy/config.m43
-rw-r--r--modules/proxy/mod_proxy_uwsgi.c551
-rw-r--r--modules/proxy/mod_proxy_uwsgi.dsp123
7 files changed, 770 insertions, 16 deletions
diff --git a/CHANGES b/CHANGES
index 6f18acb130..20f54e70f2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.4.30
+ *) mod_proxy_uwsgi: Add in UWSGI proxy (sub)module. [Roberto De Ioris,
+ Jim Jagielski]
+
*) mod_proxy_balancer,mod_slotmem_shm: Rework SHM reuse/deletion to not
depend on the number of restarts (non-Unix systems) and preserve shared
names as much as possible on configuration changes for SHMs and persisted
diff --git a/STATUS b/STATUS
index af8f39bf9a..3c680aa078 100644
--- a/STATUS
+++ b/STATUS
@@ -119,22 +119,6 @@ RELEASE SHOWSTOPPERS:
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
[ start all new proposals below, under PATCHES PROPOSED. ]
- *) mod_proxy_uwsgi: Add in UWSGI proxy (sub)module
- trunk patch: http://svn.apache.org/r1810358
- http://svn.apache.org/r1810362
- http://svn.apache.org/r1810363
- http://svn.apache.org/r1810365
- http://svn.apache.org/r1810447
- http://svn.apache.org/r1816919
- http://svn.apache.org/r1816922
- http://svn.apache.org/r1818013
- http://svn.apache.org/r1818280
- 2.4.x patch: trunk works (modulo CHANGES)
- svn merge -c r1810358,r1810362,r1810363,r1810365,r1810447,r1816919,r1816922,r1818013,r1818280 ^/httpd/httpd/trunk .
- (or svn copy ...)
- +1: jim, icing, minfrin
- icing: tested on ubuntu 16.04 with a simple uwsgi python app.
-
PATCHES PROPOSED TO BACKPORT FROM TRUNK:
[ New proposals should be added at the end of the list ]
diff --git a/docs/manual/mod/mod_proxy_uwsgi.xml b/docs/manual/mod/mod_proxy_uwsgi.xml
new file mode 100644
index 0000000000..42c344af2e
--- /dev/null
+++ b/docs/manual/mod/mod_proxy_uwsgi.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
+<?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
+<!-- $LastChangedRevision: 1755335 $ -->
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<modulesynopsis metafile="mod_proxy_uwsgi.xml.meta">
+
+<name>mod_proxy_uwsgi</name>
+<description>UWSGI gateway module for <module>mod_proxy</module></description>
+<status>Extension</status>
+<sourcefile>mod_proxy_uwsgi.c</sourcefile>
+<identifier>proxy_uwsgi_module</identifier>
+
+<summary>
+ <p>This module <em>requires</em> the service of <module
+ >mod_proxy</module>. It provides support for the
+ <a href="http://uwsgi-docs.readthedocs.io/en/latest/index.html">UWSGI protocol</a>.</p>
+
+ <p>Thus, in order to get the ability of handling the UWSGI protocol,
+ <module>mod_proxy</module> and <module>mod_proxy_uwsgi</module> have to
+ be present in the server.</p>
+
+ <note type="warning"><title>Warning</title>
+ <p>Do not enable proxying until you have <a
+ href="mod_proxy.html#access">secured your server</a>. Open proxy
+ servers are dangerous both to your network and to the Internet at
+ large.</p>
+ </note>
+</summary>
+
+<seealso><module>mod_proxy</module></seealso>
+<seealso><module>mod_proxy_balancer</module></seealso>
+
+<section id="examples"><title>Examples</title>
+ <p>Remember, in order to make the following examples work, you have to
+ enable <module>mod_proxy</module> and <module>mod_proxy_uwsgi</module>.</p>
+
+ <example><title>Simple gateway</title>
+ <highlight language="config">
+ProxyPass "/uwsgi-bin/" "uwsgi://localhost:4000/"
+ </highlight>
+ </example>
+
+ <p>The balanced gateway needs <module>mod_proxy_balancer</module> and
+ at least one load balancer algorithm module, such as
+ <module>mod_lbmethod_byrequests</module>, in addition to the proxy
+ modules listed above. <module>mod_lbmethod_byrequests</module> is the
+ default, and will be used for this example configuration.</p>
+
+ <example><title>Balanced gateway</title>
+ <highlight language="config">
+ProxyPass "/uwsgi-bin/" "balancer://somecluster/"
+&lt;Proxy balancer://somecluster&gt;
+ BalancerMember uwsgi://localhost:4000
+ BalancerMember uwsgi://localhost:4001
+&lt;/Proxy&gt;
+ </highlight>
+ </example>
+</section>
+
+</modulesynopsis>
diff --git a/docs/manual/mod/mod_proxy_uwsgi.xml.meta b/docs/manual/mod/mod_proxy_uwsgi.xml.meta
new file mode 100644
index 0000000000..00eccc321f
--- /dev/null
+++ b/docs/manual/mod/mod_proxy_uwsgi.xml.meta
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- GENERATED FROM XML: DO NOT EDIT -->
+
+<metafile reference="mod_proxy_uwsgi.xml">
+ <basename>mod_proxy_uwsgi</basename>
+ <path>/mod/</path>
+ <relpath>..</relpath>
+
+ <variants>
+ <variant>en</variant>
+ </variants>
+</metafile>
diff --git a/modules/proxy/config.m4 b/modules/proxy/config.m4
index a0915c653f..741a9e39d9 100644
--- a/modules/proxy/config.m4
+++ b/modules/proxy/config.m4
@@ -24,6 +24,7 @@ proxy_ftp_objs="mod_proxy_ftp.lo"
proxy_http_objs="mod_proxy_http.lo"
proxy_fcgi_objs="mod_proxy_fcgi.lo"
proxy_scgi_objs="mod_proxy_scgi.lo"
+proxy_uwsgi_objs="mod_proxy_uwsgi.lo"
proxy_fdpass_objs="mod_proxy_fdpass.lo"
proxy_ajp_objs="mod_proxy_ajp.lo ajp_header.lo ajp_link.lo ajp_msg.lo ajp_utils.lo"
proxy_wstunnel_objs="mod_proxy_wstunnel.lo"
@@ -38,6 +39,7 @@ case "$host" in
proxy_http_objs="$proxy_http_objs mod_proxy.la"
proxy_fcgi_objs="$proxy_fcgi_objs mod_proxy.la"
proxy_scgi_objs="$proxy_scgi_objs mod_proxy.la"
+ proxy_uwsgi_objs="$proxy_uwsgi_objs mod_proxy.la"
proxy_fdpass_objs="$proxy_fdpass_objs mod_proxy.la"
proxy_ajp_objs="$proxy_ajp_objs mod_proxy.la"
proxy_wstunnel_objs="$proxy_wstunnel_objs mod_proxy.la"
@@ -50,6 +52,7 @@ APACHE_MODULE(proxy_ftp, Apache proxy FTP module. Requires --enable-proxy., $pr
APACHE_MODULE(proxy_http, Apache proxy HTTP module. Requires --enable-proxy., $proxy_http_objs, , most, , proxy)
APACHE_MODULE(proxy_fcgi, Apache proxy FastCGI module. Requires --enable-proxy., $proxy_fcgi_objs, , most, , proxy)
APACHE_MODULE(proxy_scgi, Apache proxy SCGI module. Requires --enable-proxy., $proxy_scgi_objs, , most, , proxy)
+APACHE_MODULE(proxy_uwsgi, Apache proxy UWSGI module. Requires --enable-proxy., $proxy_uwsgi_objs, , most, , proxy)
APACHE_MODULE(proxy_fdpass, Apache proxy to Unix Daemon Socket module. Requires --enable-proxy., $proxy_fdpass_objs, , most, [
AC_CHECK_DECL(CMSG_DATA,,, [
#include <sys/types.h>
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
new file mode 100644
index 0000000000..bc7e7f9414
--- /dev/null
+++ b/modules/proxy/mod_proxy_uwsgi.c
@@ -0,0 +1,551 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+
+*** mod_proxy_uwsgi ***
+
+Copyright 2009-2017 Unbit S.a.s. <info@unbit.it>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+#define APR_WANT_MEMFUNC
+#define APR_WANT_STRFUNC
+#include "apr_strings.h"
+#include "apr_hooks.h"
+#include "apr_optional_hooks.h"
+#include "apr_buckets.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "util_script.h"
+
+#include "mod_proxy.h"
+
+
+#define UWSGI_SCHEME "uwsgi"
+#define UWSGI_DEFAULT_PORT 3031
+
+module AP_MODULE_DECLARE_DATA proxy_uwsgi_module;
+
+
+static int uwsgi_canon(request_rec *r, char *url)
+{
+ char *host, sport[sizeof(":65535")];
+ const char *err, *path;
+ apr_port_t port = UWSGI_DEFAULT_PORT;
+
+ if (ap_cstr_casecmpn(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
+ return DECLINED;
+ }
+ url += sizeof(UWSGI_SCHEME); /* Keep slashes */
+
+ err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10097)
+ "error parsing URL %s: %s", url, err);
+ return HTTP_BAD_REQUEST;
+ }
+
+ if (port != UWSGI_DEFAULT_PORT)
+ apr_snprintf(sport, sizeof(sport), ":%u", port);
+ else
+ sport[0] = '\0';
+
+ if (ap_strchr(host, ':')) { /* if literal IPv6 address */
+ host = apr_pstrcat(r->pool, "[", host, "]", NULL);
+ }
+
+ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
+ r->proxyreq);
+ if (!path) {
+ return HTTP_BAD_REQUEST;
+ }
+
+ r->filename =
+ apr_pstrcat(r->pool, "proxy:" UWSGI_SCHEME "://", host, sport, "/",
+ path, NULL);
+
+ return OK;
+}
+
+
+static int uwsgi_send(proxy_conn_rec * conn, const char *buf,
+ apr_size_t length, request_rec *r)
+{
+ apr_status_t rv;
+ apr_size_t written;
+
+ while (length > 0) {
+ written = length;
+ if ((rv = apr_socket_send(conn->sock, buf, &written)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10098)
+ "sending data to %s:%u failed",
+ conn->hostname, conn->port);
+ return HTTP_SERVICE_UNAVAILABLE;
+ }
+
+ /* count for stats */
+ conn->worker->s->transferred += written;
+ buf += written;
+ length -= written;
+ }
+
+ return OK;
+}
+
+
+/*
+ * Send uwsgi header block
+ */
+static int uwsgi_send_headers(request_rec *r, proxy_conn_rec * conn)
+{
+ char *buf, *ptr;
+
+ const apr_array_header_t *env_table;
+ const apr_table_entry_t *env;
+
+ int j;
+
+ apr_size_t headerlen = 4;
+ apr_uint16_t pktsize, keylen, vallen;
+ const char *script_name;
+ const char *path_info;
+ const char *auth;
+
+ ap_add_common_vars(r);
+ ap_add_cgi_vars(r);
+
+ /*
+ this is not a security problem (in Linux) as uWSGI destroy the env memory area readable in /proc
+ and generally if you host untrusted apps in your server and allows them to read others uid /proc/<pid>
+ files you have higher problems...
+ */
+ auth = apr_table_get(r->headers_in, "Authorization");
+ if (auth) {
+ apr_table_setn(r->subprocess_env, "HTTP_AUTHORIZATION", auth);
+ }
+
+ script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME");
+ path_info = apr_table_get(r->subprocess_env, "PATH_INFO");
+
+ if (script_name && path_info) {
+ if (strcmp(path_info, "/")) {
+ apr_table_set(r->subprocess_env, "SCRIPT_NAME",
+ apr_pstrndup(r->pool, script_name,
+ strlen(script_name) -
+ strlen(path_info)));
+ }
+ else {
+ if (!strcmp(script_name, "/")) {
+ apr_table_setn(r->subprocess_env, "SCRIPT_NAME", "");
+ }
+ }
+ }
+
+ env_table = apr_table_elts(r->subprocess_env);
+ env = (apr_table_entry_t *) env_table->elts;
+
+ for (j = 0; j < env_table->nelts; ++j) {
+ headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val);
+ }
+
+ ptr = buf = apr_palloc(r->pool, headerlen);
+
+ ptr += 4;
+
+ for (j = 0; j < env_table->nelts; ++j) {
+ keylen = strlen(env[j].key);
+ *ptr++ = (apr_byte_t) (keylen & 0xff);
+ *ptr++ = (apr_byte_t) ((keylen >> 8) & 0xff);
+ memcpy(ptr, env[j].key, keylen);
+ ptr += keylen;
+
+ vallen = strlen(env[j].val);
+ *ptr++ = (apr_byte_t) (vallen & 0xff);
+ *ptr++ = (apr_byte_t) ((vallen >> 8) & 0xff);
+ memcpy(ptr, env[j].val, vallen);
+ ptr += vallen;
+ }
+
+ pktsize = headerlen - 4;
+
+ buf[0] = 0;
+ buf[1] = (apr_byte_t) (pktsize & 0xff);
+ buf[2] = (apr_byte_t) ((pktsize >> 8) & 0xff);
+ buf[3] = 0;
+
+ return uwsgi_send(conn, buf, headerlen, r);
+}
+
+
+static int uwsgi_send_body(request_rec *r, proxy_conn_rec * conn)
+{
+ if (ap_should_client_block(r)) {
+ char *buf = apr_palloc(r->pool, AP_IOBUFSIZE);
+ int status;
+ apr_size_t readlen;
+
+ readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
+ while (readlen > 0) {
+ status = uwsgi_send(conn, buf, readlen, r);
+ if (status != OK) {
+ return HTTP_SERVICE_UNAVAILABLE;
+ }
+ readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE);
+ }
+ if (readlen == -1) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10099)
+ "receiving request body failed");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ return OK;
+}
+
+static request_rec *make_fake_req(conn_rec *c, request_rec *r)
+{
+ apr_pool_t *pool;
+ request_rec *rp;
+
+ apr_pool_create(&pool, c->pool);
+
+ rp = apr_pcalloc(pool, sizeof(*r));
+
+ rp->pool = pool;
+ rp->status = HTTP_OK;
+
+ rp->headers_in = apr_table_make(pool, 50);
+ rp->subprocess_env = apr_table_make(pool, 50);
+ rp->headers_out = apr_table_make(pool, 12);
+ rp->err_headers_out = apr_table_make(pool, 5);
+ rp->notes = apr_table_make(pool, 5);
+
+ rp->server = r->server;
+ rp->log = r->log;
+ rp->proxyreq = r->proxyreq;
+ rp->request_time = r->request_time;
+ rp->connection = c;
+ rp->output_filters = c->output_filters;
+ rp->input_filters = c->input_filters;
+ rp->proto_output_filters = c->output_filters;
+ rp->proto_input_filters = c->input_filters;
+ rp->useragent_ip = c->client_ip;
+ rp->useragent_addr = c->client_addr;
+
+ rp->request_config = ap_create_request_config(pool);
+ proxy_run_create_req(r, rp);
+
+ return rp;
+}
+
+static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
+ proxy_server_conf * conf)
+{
+
+ char buffer[HUGE_STRING_LEN];
+ const char *buf;
+ char *value, *end;
+ char keepchar;
+ int len;
+ int backend_broke = 0;
+ int status_start;
+ int status_end;
+ int finish = 0;
+ conn_rec *c = r->connection;
+ apr_off_t readbytes;
+ apr_status_t rv;
+ apr_bucket *e;
+ apr_read_type_e mode = APR_NONBLOCK_READ;
+ apr_bucket_brigade *pass_bb;
+ apr_bucket_brigade *bb;
+ proxy_dir_conf *dconf;
+
+ request_rec *rp = make_fake_req(backend->connection, r);
+ rp->proxyreq = PROXYREQ_RESPONSE;
+
+ bb = apr_brigade_create(r->pool, c->bucket_alloc);
+ pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
+
+ len = ap_getline(buffer, sizeof(buffer), rp, 1);
+
+ if (len <= 0) {
+ /* oops */
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ backend->worker->s->read += len;
+
+ if (len >= sizeof(buffer) - 1) {
+ /* oops */
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ /* Position of http status code */
+ if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+ status_start = 9;
+ }
+ else if (apr_date_checkmask(buffer, "HTTP/# ###*")) {
+ status_start = 7;
+ }
+ else {
+ /* oops */
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ status_end = status_start + 3;
+
+ keepchar = buffer[status_end];
+ buffer[status_end] = '\0';
+ r->status = atoi(&buffer[status_start]);
+
+ if (keepchar != '\0') {
+ buffer[status_end] = keepchar;
+ }
+ else {
+ /* 2616 requires the space in Status-Line; the origin
+ * server may have sent one but ap_rgetline_core will
+ * have stripped it. */
+ buffer[status_end] = ' ';
+ buffer[status_end + 1] = '\0';
+ }
+ r->status_line = apr_pstrdup(r->pool, &buffer[status_start]);
+
+ /* start parsing headers */
+ while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
+ value = strchr(buffer, ':');
+ /* invalid header skip */
+ if (!value)
+ continue;
+ *value = '\0';
+ ++value;
+ while (apr_isspace(*value))
+ ++value;
+ for (end = &value[strlen(value) - 1];
+ end > value && apr_isspace(*end); --end)
+ *end = '\0';
+ apr_table_add(r->headers_out, buffer, value);
+ }
+
+ if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+ ap_set_content_type(r, apr_pstrdup(r->pool, buf));
+ }
+
+ /* honor ProxyErrorOverride and ErrorDocument */
+#if AP_MODULE_MAGIC_AT_LEAST(20101106,0)
+ dconf =
+ ap_get_module_config(r->per_dir_config, &proxy_module);
+ if (dconf->error_override && ap_is_HTTP_ERROR(r->status)) {
+#else
+ if (conf->error_override && ap_is_HTTP_ERROR(r->status)) {
+#endif
+ int status = r->status;
+ r->status = HTTP_OK;
+ r->status_line = NULL;
+
+ apr_brigade_cleanup(bb);
+ apr_brigade_cleanup(pass_bb);
+
+ return status;
+ }
+
+ while (!finish) {
+ rv = ap_get_brigade(rp->input_filters, bb,
+ AP_MODE_READBYTES, mode, conf->io_buffer_size);
+ if (APR_STATUS_IS_EAGAIN(rv)
+ || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) {
+ e = apr_bucket_flush_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ if (ap_pass_brigade(r->output_filters, bb) || c->aborted) {
+ break;
+ }
+ apr_brigade_cleanup(bb);
+ mode = APR_BLOCK_READ;
+ continue;
+ }
+ else if (rv == APR_EOF) {
+ break;
+ }
+ else if (rv != APR_SUCCESS) {
+ ap_proxy_backend_broke(r, bb);
+ ap_pass_brigade(r->output_filters, bb);
+ backend_broke = 1;
+ break;
+ }
+
+ mode = APR_NONBLOCK_READ;
+ apr_brigade_length(bb, 0, &readbytes);
+ backend->worker->s->read += readbytes;
+
+ if (APR_BRIGADE_EMPTY(bb)) {
+ apr_brigade_cleanup(bb);
+ break;
+ }
+
+ ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
+
+ /* found the last brigade? */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb)))
+ finish = 1;
+
+ /* do not pass chunk if it is zero_sized */
+ apr_brigade_length(pass_bb, 0, &readbytes);
+
+ if ((readbytes > 0
+ && ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS)
+ || c->aborted) {
+ finish = 1;
+ }
+
+ apr_brigade_cleanup(bb);
+ apr_brigade_cleanup(pass_bb);
+ }
+
+ e = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ ap_pass_brigade(r->output_filters, bb);
+
+ apr_brigade_cleanup(bb);
+
+ if (c->aborted || backend_broke) {
+ return DONE;
+ }
+
+ return OK;
+}
+
+static int uwsgi_handler(request_rec *r, proxy_worker * worker,
+ proxy_server_conf * conf, char *url,
+ const char *proxyname, apr_port_t proxyport)
+{
+ int status;
+ int delta = 0;
+ int decode_status;
+ proxy_conn_rec *backend = NULL;
+ apr_pool_t *p = r->pool;
+ size_t w_len;
+ char server_portstr[32];
+ char *u_path_info;
+ apr_uri_t *uri;
+
+ if (ap_cstr_casecmpn(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "declining URL %s", url);
+ return DECLINED;
+ }
+
+ uri = apr_palloc(r->pool, sizeof(*uri));
+
+ /* ADD PATH_INFO */
+#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
+ w_len = strlen(worker->s->name);
+#else
+ w_len = strlen(worker->name);
+#endif
+ u_path_info = r->filename + 6 + w_len;
+ if (u_path_info[0] != '/') {
+ delta = 1;
+ }
+ decode_status = ap_unescape_url(url + w_len - delta);
+ if (decode_status) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10100)
+ "unable to decode uri: %s", url + w_len - delta);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ apr_table_add(r->subprocess_env, "PATH_INFO", url + w_len - delta);
+
+
+ /* Create space for state information */
+ status = ap_proxy_acquire_connection(UWSGI_SCHEME, &backend, worker,
+ r->server);
+ if (status != OK) {
+ goto cleanup;
+ }
+ backend->is_ssl = 0;
+
+ /* Step One: Determine Who To Connect To */
+ status = ap_proxy_determine_connection(p, r, conf, worker, backend,
+ uri, &url, proxyname, proxyport,
+ server_portstr,
+ sizeof(server_portstr));
+ if (status != OK) {
+ goto cleanup;
+ }
+
+
+ /* Step Two: Make the Connection */
+ if (ap_proxy_connect_backend(UWSGI_SCHEME, backend, worker, r->server)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10101)
+ "failed to make connection to backend: %s:%u",
+ backend->hostname, backend->port);
+ status = HTTP_SERVICE_UNAVAILABLE;
+ goto cleanup;
+ }
+
+ /* Step Three: Create conn_rec */
+ if (!backend->connection) {
+ if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend,
+ r->connection,
+ r->server)) != OK)
+ goto cleanup;
+ }
+
+ /* Step Four: Process the Request */
+ if (((status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK)
+ || ((status = uwsgi_send_headers(r, backend)) != OK)
+ || ((status = uwsgi_send_body(r, backend)) != OK)
+ || ((status = uwsgi_response(r, backend, conf)) != OK)) {
+ goto cleanup;
+ }
+
+ cleanup:
+ if (backend) {
+ backend->close = 1; /* always close the socket */
+ ap_proxy_release_connection(UWSGI_SCHEME, backend, r->server);
+ }
+ return status;
+}
+
+
+static void register_hooks(apr_pool_t * p)
+{
+ proxy_hook_scheme_handler(uwsgi_handler, NULL, NULL, APR_HOOK_FIRST);
+ proxy_hook_canon_handler(uwsgi_canon, NULL, NULL, APR_HOOK_FIRST);
+}
+
+
+module AP_MODULE_DECLARE_DATA proxy_uwsgi_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ NULL, /* command table */
+ register_hooks /* register hooks */
+};
diff --git a/modules/proxy/mod_proxy_uwsgi.dsp b/modules/proxy/mod_proxy_uwsgi.dsp
new file mode 100644
index 0000000000..00c3034b93
--- /dev/null
+++ b/modules/proxy/mod_proxy_uwsgi.dsp
@@ -0,0 +1,123 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_uwsgi" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_uwsgi - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_uwsgi.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_uwsgi.mak" CFG="mod_proxy_uwsgi - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_proxy_uwsgi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_uwsgi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_proxy_uwsgi - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_uwsgi_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_proxy_uwsgi.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_proxy_uwsgi.so" /d LONG_NAME="proxy_uwsgi_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:".\Release\mod_proxy_uwsgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_uwsgi.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_proxy_uwsgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_uwsgi.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_proxy_uwsgi.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_proxy_uwsgi - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_uwsgi_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_proxy_uwsgi.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_proxy_uwsgi.so" /d LONG_NAME="proxy_uwsgi_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_proxy_uwsgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_uwsgi.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_proxy_uwsgi.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_uwsgi.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_proxy_uwsgi.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_proxy_uwsgi - Win32 Release"
+# Name "mod_proxy_uwsgi - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\mod_proxy_uwsgi.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project