diff options
author | Graham Leggett <minfrin@apache.org> | 2018-02-13 22:38:48 +0000 |
---|---|---|
committer | Graham Leggett <minfrin@apache.org> | 2018-02-13 22:38:48 +0000 |
commit | 99c59e098103ccf13b833281ec08493e042dfee0 (patch) | |
tree | e66d0e5d2ca654fb5f14946ce780fbfe6f42774d | |
parent | 90793a4c7028f1a4a060954025dc1666b9f869d3 (diff) | |
download | httpd-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-- | CHANGES | 3 | ||||
-rw-r--r-- | STATUS | 16 | ||||
-rw-r--r-- | docs/manual/mod/mod_proxy_uwsgi.xml | 78 | ||||
-rw-r--r-- | docs/manual/mod/mod_proxy_uwsgi.xml.meta | 12 | ||||
-rw-r--r-- | modules/proxy/config.m4 | 3 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_uwsgi.c | 551 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_uwsgi.dsp | 123 |
7 files changed, 770 insertions, 16 deletions
@@ -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 @@ -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/" +<Proxy balancer://somecluster> + BalancerMember uwsgi://localhost:4000 + BalancerMember uwsgi://localhost:4001 +</Proxy> + </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 |