version 1.1, 2013/10/14 10:32:48
|
version 1.1.1.3, 2016/11/02 10:35:00
|
Line 1
|
Line 1
|
|
#include "first.h" |
|
|
#include "buffer.h" |
#include "buffer.h" |
#include "server.h" |
#include "server.h" |
#include "keyvalue.h" |
#include "keyvalue.h" |
Line 26
|
Line 28
|
|
|
#include <stdio.h> |
#include <stdio.h> |
|
|
#ifdef HAVE_SYS_FILIO_H |
|
# include <sys/filio.h> |
|
#endif |
|
|
|
#include "sys-socket.h" |
#include "sys-socket.h" |
|
|
#define data_proxy data_fastcgi |
#define data_proxy data_fastcgi |
Line 84 typedef enum {
|
Line 82 typedef enum {
|
PROXY_STATE_CONNECT, |
PROXY_STATE_CONNECT, |
PROXY_STATE_PREPARE_WRITE, |
PROXY_STATE_PREPARE_WRITE, |
PROXY_STATE_WRITE, |
PROXY_STATE_WRITE, |
PROXY_STATE_READ, | PROXY_STATE_READ |
PROXY_STATE_ERROR | |
} proxy_connection_state_t; |
} proxy_connection_state_t; |
|
|
enum { PROXY_STDOUT, PROXY_END_REQUEST }; |
enum { PROXY_STDOUT, PROXY_END_REQUEST }; |
Line 100 typedef struct {
|
Line 97 typedef struct {
|
buffer *response_header; |
buffer *response_header; |
|
|
chunkqueue *wb; |
chunkqueue *wb; |
|
off_t wb_reqlen; |
|
|
int fd; /* fd to the proxy process */ |
int fd; /* fd to the proxy process */ |
int fde_ndx; /* index into the fd-event buffer */ |
int fde_ndx; /* index into the fd-event buffer */ |
Line 127 static handler_ctx * handler_ctx_init(void) {
|
Line 125 static handler_ctx * handler_ctx_init(void) {
|
hctx->response_header = buffer_init(); |
hctx->response_header = buffer_init(); |
|
|
hctx->wb = chunkqueue_init(); |
hctx->wb = chunkqueue_init(); |
|
hctx->wb_reqlen = 0; |
|
|
hctx->fd = -1; |
hctx->fd = -1; |
hctx->fde_ndx = -1; |
hctx->fde_ndx = -1; |
Line 167 FREE_FUNC(mod_proxy_free) {
|
Line 166 FREE_FUNC(mod_proxy_free) {
|
for (i = 0; i < srv->config_context->used; i++) { |
for (i = 0; i < srv->config_context->used; i++) { |
plugin_config *s = p->config_storage[i]; |
plugin_config *s = p->config_storage[i]; |
|
|
if (s) { | if (NULL == s) continue; |
|
|
array_free(s->extensions); | array_free(s->extensions); |
|
|
free(s); | free(s); |
} | |
} |
} |
free(p->config_storage); |
free(p->config_storage); |
} |
} |
Line 194 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 192 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } |
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } |
}; |
}; |
|
|
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); | p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); |
|
|
for (i = 0; i < srv->config_context->used; i++) { |
for (i = 0; i < srv->config_context->used; i++) { |
|
data_config const* config = (data_config const*)srv->config_context->data[i]; |
plugin_config *s; |
plugin_config *s; |
array *ca; |
|
|
|
s = malloc(sizeof(plugin_config)); |
s = malloc(sizeof(plugin_config)); |
s->extensions = array_init(); |
s->extensions = array_init(); |
Line 211 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 209 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
buffer_reset(p->balance_buf); |
buffer_reset(p->balance_buf); |
|
|
p->config_storage[i] = s; |
p->config_storage[i] = s; |
ca = ((data_config *)srv->config_context->data[i])->value; |
|
|
|
if (0 != config_insert_values_global(srv, ca, cv)) { | if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
if (buffer_is_empty(p->balance_buf)) { | if (buffer_string_is_empty(p->balance_buf)) { |
s->balance = PROXY_BALANCE_FAIR; |
s->balance = PROXY_BALANCE_FAIR; |
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) { |
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) { |
s->balance = PROXY_BALANCE_FAIR; |
s->balance = PROXY_BALANCE_FAIR; |
Line 231 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 228 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
if (NULL != (du = array_get_element(ca, "proxy.server"))) { | if (NULL != (du = array_get_element(config->value, "proxy.server"))) { |
size_t j; |
size_t j; |
data_array *da = (data_array *)du; |
data_array *da = (data_array *)du; |
|
|
if (du->type != TYPE_ARRAY) { |
if (du->type != TYPE_ARRAY) { |
log_error_write(srv, __FILE__, __LINE__, "sss", |
log_error_write(srv, __FILE__, __LINE__, "sss", |
"unexpected type for key: ", "proxy.server", "array of strings"); | "unexpected type for key: ", "proxy.server", "expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); |
|
|
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
Line 254 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 251 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
if (da_ext->type != TYPE_ARRAY) { |
if (da_ext->type != TYPE_ARRAY) { |
log_error_write(srv, __FILE__, __LINE__, "sssbs", |
log_error_write(srv, __FILE__, __LINE__, "sssbs", |
"unexpected type for key: ", "proxy.server", |
"unexpected type for key: ", "proxy.server", |
"[", da->value->data[j]->key, "](string)"); | "[", da->value->data[j]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); |
|
|
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
Line 283 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 280 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
log_error_write(srv, __FILE__, __LINE__, "ssSBS", |
log_error_write(srv, __FILE__, __LINE__, "ssSBS", |
"unexpected type for key:", |
"unexpected type for key:", |
"proxy.server", |
"proxy.server", |
"[", da_ext->value->data[n]->key, "](string)"); | "[", da_ext->value->data[n]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))"); |
|
|
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
Line 292 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 289 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
|
|
df->port = 80; |
df->port = 80; |
|
|
buffer_copy_string_buffer(df->key, da_host->key); | buffer_copy_buffer(df->key, da_host->key); |
|
|
pcv[0].destination = df->host; |
pcv[0].destination = df->host; |
pcv[1].destination = &(df->port); |
pcv[1].destination = &(df->port); |
|
|
if (0 != config_insert_values_internal(srv, da_host->value, pcv)) { | if (0 != config_insert_values_internal(srv, da_host->value, pcv, T_CONFIG_SCOPE_CONNECTION)) { |
| df->free((data_unset*) df); |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
if (buffer_is_empty(df->host)) { | if (buffer_string_is_empty(df->host)) { |
log_error_write(srv, __FILE__, __LINE__, "sbbbs", |
log_error_write(srv, __FILE__, __LINE__, "sbbbs", |
"missing key (string):", |
"missing key (string):", |
da->key, |
da->key, |
Line 309 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 307 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
da_host->key, |
da_host->key, |
"host"); |
"host"); |
|
|
|
df->free((data_unset*) df); |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
Line 317 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
Line 316 SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
|
if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) { |
if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) { |
dfa = data_array_init(); |
dfa = data_array_init(); |
|
|
buffer_copy_string_buffer(dfa->key, da_ext->key); | buffer_copy_buffer(dfa->key, da_ext->key); |
|
|
array_insert_unique(dfa->value, (data_unset *)df); |
array_insert_unique(dfa->value, (data_unset *)df); |
array_insert_unique(s->extensions, (data_unset *)dfa); |
array_insert_unique(s->extensions, (data_unset *)dfa); |
Line 336 static void proxy_connection_close(server *srv, handle
|
Line 335 static void proxy_connection_close(server *srv, handle
|
plugin_data *p; |
plugin_data *p; |
connection *con; |
connection *con; |
|
|
if (NULL == hctx) return; |
|
|
|
p = hctx->plugin_data; |
p = hctx->plugin_data; |
con = hctx->remote_conn; |
con = hctx->remote_conn; |
|
|
Line 355 static void proxy_connection_close(server *srv, handle
|
Line 352 static void proxy_connection_close(server *srv, handle
|
|
|
handler_ctx_free(hctx); |
handler_ctx_free(hctx); |
con->plugin_ctx[p->id] = NULL; |
con->plugin_ctx[p->id] = NULL; |
|
|
|
/* finish response (if not already con->file_started, con->file_finished) */ |
|
if (con->mode == p->id) { |
|
http_response_backend_done(srv, con); |
|
} |
} |
} |
|
|
static int proxy_establish_connection(server *srv, handler_ctx *hctx) { |
static int proxy_establish_connection(server *srv, handler_ctx *hctx) { |
struct sockaddr *proxy_addr; |
struct sockaddr *proxy_addr; |
struct sockaddr_in proxy_addr_in; |
struct sockaddr_in proxy_addr_in; |
|
#if defined(HAVE_SYS_UN_H) |
|
struct sockaddr_un proxy_addr_un; |
|
#endif |
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
struct sockaddr_in6 proxy_addr_in6; |
struct sockaddr_in6 proxy_addr_in6; |
#endif |
#endif |
Line 370 static int proxy_establish_connection(server *srv, han
|
Line 375 static int proxy_establish_connection(server *srv, han
|
int proxy_fd = hctx->fd; |
int proxy_fd = hctx->fd; |
|
|
|
|
|
#if defined(HAVE_SYS_UN_H) |
|
if (strstr(host->host->ptr, "/")) { |
|
if (buffer_string_length(host->host) + 1 > sizeof(proxy_addr_un.sun_path)) { |
|
log_error_write(srv, __FILE__, __LINE__, "sB", |
|
"ERROR: Unix Domain socket filename too long:", |
|
host->host); |
|
return -1; |
|
} |
|
|
|
memset(&proxy_addr_un, 0, sizeof(proxy_addr_un)); |
|
proxy_addr_un.sun_family = AF_UNIX; |
|
memcpy(proxy_addr_un.sun_path, host->host->ptr, buffer_string_length(host->host) + 1); |
|
servlen = sizeof(proxy_addr_un); |
|
proxy_addr = (struct sockaddr *) &proxy_addr_un; |
|
} else |
|
#endif |
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
if (strstr(host->host->ptr, ":")) { |
if (strstr(host->host->ptr, ":")) { |
memset(&proxy_addr_in6, 0, sizeof(proxy_addr_in6)); |
memset(&proxy_addr_in6, 0, sizeof(proxy_addr_in6)); |
Line 415 static int proxy_establish_connection(server *srv, han
|
Line 436 static int proxy_establish_connection(server *srv, han
|
} |
} |
|
|
static void proxy_set_header(connection *con, const char *key, const char *value) { |
static void proxy_set_header(connection *con, const char *key, const char *value) { |
data_string *ds_dst; | data_string *ds_dst; |
|
|
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { | if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { |
ds_dst = data_string_init(); | ds_dst = data_string_init(); |
} | } |
|
|
buffer_copy_string(ds_dst->key, key); | buffer_copy_string(ds_dst->key, key); |
buffer_copy_string(ds_dst->value, value); | buffer_copy_string(ds_dst->value, value); |
array_insert_unique(con->request.headers, (data_unset *)ds_dst); | array_insert_unique(con->request.headers, (data_unset *)ds_dst); |
} |
} |
|
|
static void proxy_append_header(connection *con, const char *key, const char *value) { |
static void proxy_append_header(connection *con, const char *key, const char *value) { |
data_string *ds_dst; | data_string *ds_dst; |
|
|
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { | if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { |
ds_dst = data_string_init(); | ds_dst = data_string_init(); |
} | } |
|
|
buffer_copy_string(ds_dst->key, key); | buffer_copy_string(ds_dst->key, key); |
buffer_append_string(ds_dst->value, value); | buffer_append_string(ds_dst->value, value); |
array_insert_unique(con->request.headers, (data_unset *)ds_dst); | array_insert_unique(con->request.headers, (data_unset *)ds_dst); |
} |
} |
|
|
|
|
Line 447 static int proxy_create_env(server *srv, handler_ctx *
|
Line 468 static int proxy_create_env(server *srv, handler_ctx *
|
|
|
/* build header */ |
/* build header */ |
|
|
b = chunkqueue_get_append_buffer(hctx->wb); | b = buffer_init(); |
|
|
/* request line */ |
/* request line */ |
buffer_copy_string(b, get_http_method_name(con->request.http_method)); |
buffer_copy_string(b, get_http_method_name(con->request.http_method)); |
Line 459 static int proxy_create_env(server *srv, handler_ctx *
|
Line 480 static int proxy_create_env(server *srv, handler_ctx *
|
proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr))); |
proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr))); |
/* http_host is NOT is just a pointer to a buffer |
/* http_host is NOT is just a pointer to a buffer |
* which is NULL if it is not set */ |
* which is NULL if it is not set */ |
if (con->request.http_host && | if (!buffer_string_is_empty(con->request.http_host)) { |
!buffer_is_empty(con->request.http_host)) { | |
proxy_set_header(con, "X-Host", con->request.http_host->ptr); |
proxy_set_header(con, "X-Host", con->request.http_host->ptr); |
} |
} |
proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr); |
proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr); |
Line 471 static int proxy_create_env(server *srv, handler_ctx *
|
Line 491 static int proxy_create_env(server *srv, handler_ctx *
|
|
|
ds = (data_string *)con->request.headers->data[i]; |
ds = (data_string *)con->request.headers->data[i]; |
|
|
if (ds->value->used && ds->key->used) { | if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) { |
if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue; | if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Connection"))) continue; |
if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue; | if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue; |
| /* Do not emit HTTP_PROXY in environment. |
| * Some executables use HTTP_PROXY to configure |
| * outgoing proxy. See also https://httpoxy.org/ */ |
| if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) continue; |
|
|
buffer_append_string_buffer(b, ds->key); |
buffer_append_string_buffer(b, ds->key); |
buffer_append_string_len(b, CONST_STR_LEN(": ")); |
buffer_append_string_len(b, CONST_STR_LEN(": ")); |
Line 482 static int proxy_create_env(server *srv, handler_ctx *
|
Line 506 static int proxy_create_env(server *srv, handler_ctx *
|
} |
} |
} |
} |
|
|
buffer_append_string_len(b, CONST_STR_LEN("\r\n")); | buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n")); |
|
|
hctx->wb->bytes_in += b->used - 1; | hctx->wb_reqlen = buffer_string_length(b); |
| chunkqueue_append_buffer(hctx->wb, b); |
| buffer_free(b); |
| |
/* body */ |
/* body */ |
|
|
if (con->request.content_length) { |
if (con->request.content_length) { |
chunkqueue *req_cq = con->request_content_queue; | chunkqueue_append_chunkqueue(hctx->wb, con->request_content_queue); |
chunk *req_c; | hctx->wb_reqlen += con->request.content_length;/* (eventual) total request size */ |
off_t offset; | |
| |
/* something to send ? */ | |
for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) { | |
off_t weWant = req_cq->bytes_in - offset; | |
off_t weHave = 0; | |
| |
/* we announce toWrite octects | |
* now take all the request_content chunk that we need to fill this request | |
* */ | |
| |
switch (req_c->type) { | |
case FILE_CHUNK: | |
weHave = req_c->file.length - req_c->offset; | |
| |
if (weHave > weWant) weHave = weWant; | |
| |
chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave); | |
| |
req_c->offset += weHave; | |
req_cq->bytes_out += weHave; | |
| |
hctx->wb->bytes_in += weHave; | |
| |
break; | |
case MEM_CHUNK: | |
/* append to the buffer */ | |
weHave = req_c->mem->used - 1 - req_c->offset; | |
| |
if (weHave > weWant) weHave = weWant; | |
| |
b = chunkqueue_get_append_buffer(hctx->wb); | |
buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave); | |
b->used++; /* add virtual \0 */ | |
| |
req_c->offset += weHave; | |
req_cq->bytes_out += weHave; | |
| |
hctx->wb->bytes_in += weHave; | |
| |
break; | |
default: | |
break; | |
} | |
| |
offset += weHave; | |
} | |
| |
} |
} |
|
|
return 0; |
return 0; |
Line 557 static int proxy_response_parse(server *srv, connectio
|
Line 536 static int proxy_response_parse(server *srv, connectio
|
|
|
UNUSED(srv); |
UNUSED(srv); |
|
|
/* \r\n -> \0\0 */ | /* [\r]\n -> [\0]\0 */ |
|
|
buffer_copy_string_buffer(p->parse_response, in); | buffer_copy_buffer(p->parse_response, in); |
|
|
for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) { | for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) { |
char *key, *value; |
char *key, *value; |
int key_len; |
int key_len; |
data_string *ds; |
data_string *ds; |
int copy_header; |
int copy_header; |
|
|
ns[0] = '\0'; |
ns[0] = '\0'; |
ns[1] = '\0'; | if (s != ns && ns[-1] == '\r') ns[-1] = '\0'; |
|
|
if (-1 == http_response_status) { |
if (-1 == http_response_status) { |
/* The first line of a Response message is the Status-Line */ |
/* The first line of a Response message is the Status-Line */ |
Line 577 static int proxy_response_parse(server *srv, connectio
|
Line 556 static int proxy_response_parse(server *srv, connectio
|
|
|
if (*key) { |
if (*key) { |
http_response_status = (int) strtol(key, NULL, 10); |
http_response_status = (int) strtol(key, NULL, 10); |
if (http_response_status <= 0) http_response_status = 502; | if (http_response_status < 100 || http_response_status >= 1000) http_response_status = 502; |
} else { |
} else { |
http_response_status = 502; |
http_response_status = 502; |
} |
} |
Line 620 static int proxy_response_parse(server *srv, connectio
|
Line 599 static int proxy_response_parse(server *srv, connectio
|
break; |
break; |
case 14: |
case 14: |
if (0 == strncasecmp(key, "Content-Length", key_len)) { |
if (0 == strncasecmp(key, "Content-Length", key_len)) { |
con->response.content_length = strtol(value, NULL, 10); | con->response.content_length = strtoul(value, NULL, 10); |
con->parsed_response |= HTTP_CONTENT_LENGTH; |
con->parsed_response |= HTTP_CONTENT_LENGTH; |
} |
} |
break; |
break; |
Line 653 static int proxy_demux_response(server *srv, handler_c
|
Line 632 static int proxy_demux_response(server *srv, handler_c
|
int proxy_fd = hctx->fd; |
int proxy_fd = hctx->fd; |
|
|
/* check how much we have to read */ |
/* check how much we have to read */ |
|
#if !defined(_WIN32) && !defined(__CYGWIN__) |
if (ioctl(hctx->fd, FIONREAD, &b)) { |
if (ioctl(hctx->fd, FIONREAD, &b)) { |
|
if (errno == EAGAIN) { |
|
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
|
return 0; |
|
} |
log_error_write(srv, __FILE__, __LINE__, "sd", |
log_error_write(srv, __FILE__, __LINE__, "sd", |
"ioctl failed: ", |
"ioctl failed: ", |
proxy_fd); |
proxy_fd); |
return -1; |
return -1; |
} |
} |
|
#else |
|
b = 4096; |
|
#endif |
|
|
|
|
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "sd", |
log_error_write(srv, __FILE__, __LINE__, "sd", |
"proxy - have to read:", b); | "proxy - have to read:", b); |
} |
} |
|
|
if (b > 0) { |
if (b > 0) { |
if (hctx->response->used == 0) { | if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)) { |
/* avoid too small buffer */ | off_t cqlen = chunkqueue_length(con->write_queue); |
buffer_prepare_append(hctx->response, b + 1); | if (cqlen + b > 65536 - 4096) { |
hctx->response->used = 1; | if (!con->is_writable) { |
} else { | /*(defer removal of FDEVENT_IN interest since |
buffer_prepare_append(hctx->response, b); | * connection_state_machine() might be able to send data |
| * immediately, unless !con->is_writable, where |
| * connection_state_machine() might not loop back to call |
| * mod_proxy_handle_subrequest())*/ |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
| } |
| if (cqlen >= 65536-1) return 0; |
| b = 65536 - 1 - (int)cqlen; |
| } |
} |
} |
|
|
if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) { | buffer_string_prepare_append(hctx->response, b); |
if (errno == EAGAIN) return 0; | |
| if (-1 == (r = read(hctx->fd, hctx->response->ptr + buffer_string_length(hctx->response), buffer_string_space(hctx->response)))) { |
| if (errno == EAGAIN) { |
| fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
| return 0; |
| } |
log_error_write(srv, __FILE__, __LINE__, "sds", |
log_error_write(srv, __FILE__, __LINE__, "sds", |
"unexpected end-of-file (perhaps the proxy process died):", |
"unexpected end-of-file (perhaps the proxy process died):", |
proxy_fd, strerror(errno)); |
proxy_fd, strerror(errno)); |
return -1; |
return -1; |
} |
} |
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) |
|
if (0 == r) return 1; /* fin */ |
|
#endif |
|
|
/* this should be catched by the b > 0 above */ |
/* this should be catched by the b > 0 above */ |
assert(r); | force_assert(r); |
|
|
hctx->response->used += r; | buffer_commit(hctx->response, r); |
hctx->response->ptr[hctx->response->used - 1] = '\0'; | |
|
|
#if 0 |
#if 0 |
log_error_write(srv, __FILE__, __LINE__, "sdsbs", |
log_error_write(srv, __FILE__, __LINE__, "sdsbs", |
Line 696 static int proxy_demux_response(server *srv, handler_c
|
Line 699 static int proxy_demux_response(server *srv, handler_c
|
|
|
if (0 == con->got_response) { |
if (0 == con->got_response) { |
con->got_response = 1; |
con->got_response = 1; |
buffer_prepare_copy(hctx->response_header, 128); | buffer_string_prepare_copy(hctx->response_header, 1023); |
} |
} |
|
|
if (0 == con->file_started) { |
if (0 == con->file_started) { |
char *c; |
char *c; |
|
|
/* search for the \r\n\r\n in the string */ |
/* search for the \r\n\r\n in the string */ |
if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) { | if (NULL != (c = buffer_search_string_len(hctx->response, CONST_STR_LEN("\r\n\r\n")))) { |
size_t hlen = c - hctx->response->ptr + 4; |
size_t hlen = c - hctx->response->ptr + 4; |
size_t blen = hctx->response->used - hlen - 1; | size_t blen = buffer_string_length(hctx->response) - hlen; |
/* found */ |
/* found */ |
|
|
buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4); | buffer_append_string_len(hctx->response_header, hctx->response->ptr, hlen); |
#if 0 |
#if 0 |
log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header); |
log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header); |
#endif |
#endif |
/* parse the response header */ |
/* parse the response header */ |
proxy_response_parse(srv, con, p, hctx->response_header); |
proxy_response_parse(srv, con, p, hctx->response_header); |
|
|
/* enable chunked-transfer-encoding */ |
|
if (con->request.http_version == HTTP_VERSION_1_1 && |
|
!(con->parsed_response & HTTP_CONTENT_LENGTH)) { |
|
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; |
|
} |
|
|
|
con->file_started = 1; |
con->file_started = 1; |
if (blen) { | if (blen > 0) { |
http_chunk_append_mem(srv, con, c + 4, blen + 1); | if (0 != http_chunk_append_mem(srv, con, c + 4, blen)) { |
| /* error writing to tempfile; |
| * truncate response or send 500 if nothing sent yet */ |
| fin = 1; |
| con->file_started = 0; |
| } |
} |
} |
hctx->response->used = 0; | buffer_reset(hctx->response); |
joblist_append(srv, con); | } else { |
| /* no luck, no header found */ |
| /*(reuse MAX_HTTP_REQUEST_HEADER as max size for response headers from backends)*/ |
| if (buffer_string_length(hctx->response) > MAX_HTTP_REQUEST_HEADER) { |
| log_error_write(srv, __FILE__, __LINE__, "sb", "response headers too large for", con->uri.path); |
| con->http_status = 502; /* Bad Gateway */ |
| con->mode = DIRECT; |
| fin = 1; |
| } |
} |
} |
} else { |
} else { |
http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used); | if (0 != http_chunk_append_buffer(srv, con, hctx->response)) { |
joblist_append(srv, con); | /* error writing to tempfile; |
hctx->response->used = 0; | * truncate response or send 500 if nothing sent yet */ |
| fin = 1; |
| } |
| buffer_reset(hctx->response); |
} |
} |
|
|
} else { |
} else { |
/* reading from upstream done */ |
/* reading from upstream done */ |
con->file_finished = 1; |
|
|
|
http_chunk_append_mem(srv, con, NULL, 0); |
|
joblist_append(srv, con); |
|
|
|
fin = 1; |
fin = 1; |
} |
} |
|
|
Line 754 static handler_t proxy_write_request(server *srv, hand
|
Line 761 static handler_t proxy_write_request(server *srv, hand
|
|
|
int ret; |
int ret; |
|
|
if (!host || | if (!host || buffer_string_is_empty(host->host) || !host->port) return HANDLER_ERROR; |
(!host->host->used || !host->port)) return -1; | |
|
|
switch(hctx->state) { |
switch(hctx->state) { |
case PROXY_STATE_CONNECT: |
case PROXY_STATE_CONNECT: |
Line 767 static handler_t proxy_write_request(server *srv, hand
|
Line 773 static handler_t proxy_write_request(server *srv, hand
|
/* wait */ |
/* wait */ |
return HANDLER_WAIT_FOR_EVENT; |
return HANDLER_WAIT_FOR_EVENT; |
|
|
break; |
|
|
|
case PROXY_STATE_INIT: |
case PROXY_STATE_INIT: |
|
#if defined(HAVE_SYS_UN_H) |
|
if (strstr(host->host->ptr,"/")) { |
|
if (-1 == (hctx->fd = socket(AF_UNIX, SOCK_STREAM, 0))) { |
|
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno)); |
|
return HANDLER_ERROR; |
|
} |
|
} else |
|
#endif |
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON) |
if (strstr(host->host->ptr,":")) { |
if (strstr(host->host->ptr,":")) { |
if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) { | if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) { |
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno)); | log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno)); |
return HANDLER_ERROR; | return HANDLER_ERROR; |
} | } |
} else |
} else |
#endif |
#endif |
{ |
{ |
if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) { | if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) { |
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno)); | log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno)); |
return HANDLER_ERROR; | return HANDLER_ERROR; |
} | } |
} |
} |
hctx->fde_ndx = -1; |
hctx->fde_ndx = -1; |
|
|
Line 821 static handler_t proxy_write_request(server *srv, hand
|
Line 833 static handler_t proxy_write_request(server *srv, hand
|
case PROXY_STATE_PREPARE_WRITE: |
case PROXY_STATE_PREPARE_WRITE: |
proxy_create_env(srv, hctx); |
proxy_create_env(srv, hctx); |
|
|
|
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
proxy_set_state(srv, hctx, PROXY_STATE_WRITE); |
proxy_set_state(srv, hctx, PROXY_STATE_WRITE); |
|
|
/* fall through */ |
/* fall through */ |
Line 839 static handler_t proxy_write_request(server *srv, hand
|
Line 852 static handler_t proxy_write_request(server *srv, hand
|
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
if (hctx->wb->bytes_out == hctx->wb->bytes_in) { | if (hctx->wb->bytes_out == hctx->wb_reqlen) { |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
| #if (defined(__APPLE__) && defined(__MACH__)) \ |
| || defined(__FreeBSD__) || defined(__NetBSD__) \ |
| || defined(__OpenBSD__) || defined(__DragonflyBSD__) |
| /*(*BSD stack on remote might signal POLLHUP and remote |
| * might treat as socket error instead of half-close)*/ |
| #else |
| /*(remote could be different machine running affected OS, |
| * so only issue shutdown for known local sockets)*/ |
| if ( '/' == host->host->ptr[0] |
| || buffer_is_equal_string(host->host, CONST_STR_LEN("127.0.0.1")) |
| || buffer_is_equal_string(host->host, CONST_STR_LEN("::1"))) { |
| shutdown(hctx->fd, SHUT_WR);/* future: remove if HTTP/1.1 request */ |
| } |
| #endif |
proxy_set_state(srv, hctx, PROXY_STATE_READ); |
proxy_set_state(srv, hctx, PROXY_STATE_READ); |
|
|
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); |
|
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
|
} else { |
} else { |
fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); | off_t wblen = hctx->wb->bytes_in - hctx->wb->bytes_out; |
| if (hctx->wb->bytes_in < hctx->wb_reqlen && wblen < 65536 - 16384) { |
return HANDLER_WAIT_FOR_EVENT; | /*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/ |
| if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) { |
| con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN; |
| con->is_readable = 1; /* trigger optimistic read from client */ |
| } |
| } |
| if (0 == wblen) { |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
| } else { |
| fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); |
| } |
} |
} |
|
|
return HANDLER_WAIT_FOR_EVENT; |
return HANDLER_WAIT_FOR_EVENT; |
Line 858 static handler_t proxy_write_request(server *srv, hand
|
Line 893 static handler_t proxy_write_request(server *srv, hand
|
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); |
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
return HANDLER_GO_ON; |
|
} |
} |
|
|
#define PATCH(x) \ |
#define PATCH(x) \ |
Line 898 static int mod_proxy_patch_connection(server *srv, con
|
Line 931 static int mod_proxy_patch_connection(server *srv, con
|
} |
} |
#undef PATCH |
#undef PATCH |
|
|
SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { | static handler_t proxy_send_request(server *srv, handler_ctx *hctx) { |
plugin_data *p = p_d; | |
| |
handler_ctx *hctx = con->plugin_ctx[p->id]; | |
data_proxy *host; | |
| |
if (NULL == hctx) return HANDLER_GO_ON; | |
| |
mod_proxy_patch_connection(srv, con, p); | |
| |
host = hctx->host; | |
| |
/* not my job */ | |
if (con->mode != p->id) return HANDLER_GO_ON; | |
| |
/* ok, create the request */ |
/* ok, create the request */ |
switch(proxy_write_request(srv, hctx)) { | handler_t rc = proxy_write_request(srv, hctx); |
case HANDLER_ERROR: | if (HANDLER_ERROR != rc) { |
| return rc; |
| } else { |
| data_proxy *host = hctx->host; |
| connection *con = hctx->remote_conn; |
| plugin_data *p = hctx->plugin_data; |
log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:", |
log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:", |
host->host, |
host->host, |
host->port, |
host->port, |
Line 925 SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
|
Line 949 SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
|
host->is_disabled = 1; |
host->is_disabled = 1; |
host->disable_ts = srv->cur_ts; |
host->disable_ts = srv->cur_ts; |
|
|
|
/* reset the enviroment and restart the sub-request */ |
|
con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/ |
proxy_connection_close(srv, hctx); |
proxy_connection_close(srv, hctx); |
|
con->mode = p->id; |
|
|
/* reset the enviroment and restart the sub-request */ | return HANDLER_COMEBACK; |
buffer_reset(con->physical.path); | } |
con->mode = DIRECT; | } |
|
|
joblist_append(srv, con); |
|
|
|
/* mis-using HANDLER_WAIT_FOR_FD to break out of the loop | static handler_t proxy_recv_response(server *srv, handler_ctx *hctx); |
* and hope that the childs will be restarted | |
* | |
*/ | |
|
|
return HANDLER_WAIT_FOR_FD; | |
case HANDLER_WAIT_FOR_EVENT: | SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { |
break; | plugin_data *p = p_d; |
case HANDLER_WAIT_FOR_FD: | |
return HANDLER_WAIT_FOR_FD; | handler_ctx *hctx = con->plugin_ctx[p->id]; |
default: | |
break; | if (NULL == hctx) return HANDLER_GO_ON; |
| |
| /* not my job */ |
| if (con->mode != p->id) return HANDLER_GO_ON; |
| |
| if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) |
| && con->file_started) { |
| if (chunkqueue_length(con->write_queue) > 65536 - 4096) { |
| fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); |
| } else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) { |
| /* optimistic read from backend, which might re-enable FDEVENT_IN */ |
| handler_t rc = proxy_recv_response(srv, hctx); /*(might invalidate hctx)*/ |
| if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ |
| } |
} |
} |
|
|
if (con->file_started == 1) { | if (0 == hctx->wb->bytes_in |
return HANDLER_FINISHED; | ? con->state == CON_STATE_READ_POST |
} else { | : hctx->wb->bytes_in < hctx->wb_reqlen) { |
return HANDLER_WAIT_FOR_EVENT; | /*(64k - 4k to attempt to avoid temporary files |
| * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/ |
| if (hctx->wb->bytes_in - hctx->wb->bytes_out > 65536 - 4096 |
| && (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)){ |
| con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN; |
| if (0 != hctx->wb->bytes_in) return HANDLER_WAIT_FOR_EVENT; |
| } else { |
| handler_t r = connection_handle_read_post_state(srv, con); |
| chunkqueue *req_cq = con->request_content_queue; |
| if (0 != hctx->wb->bytes_in && !chunkqueue_is_empty(req_cq)) { |
| chunkqueue_append_chunkqueue(hctx->wb, req_cq); |
| if (fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_OUT) { |
| return (r == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : r; |
| } |
| } |
| if (r != HANDLER_GO_ON) return r; |
| } |
} |
} |
|
|
|
return ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb)) |
|
&& hctx->state != PROXY_STATE_CONNECT) |
|
? proxy_send_request(srv, hctx) |
|
: HANDLER_WAIT_FOR_EVENT; |
} |
} |
|
|
|
|
|
static handler_t proxy_recv_response(server *srv, handler_ctx *hctx) { |
|
|
|
switch (proxy_demux_response(srv, hctx)) { |
|
case 0: |
|
break; |
|
case -1: |
|
http_response_backend_error(srv, hctx->remote_conn); |
|
/* fall through */ |
|
case 1: |
|
/* we are done */ |
|
proxy_connection_close(srv, hctx); |
|
|
|
return HANDLER_FINISHED; |
|
} |
|
|
|
return HANDLER_GO_ON; |
|
} |
|
|
|
|
static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { |
static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { |
handler_ctx *hctx = ctx; |
handler_ctx *hctx = ctx; |
connection *con = hctx->remote_conn; |
connection *con = hctx->remote_conn; |
plugin_data *p = hctx->plugin_data; |
plugin_data *p = hctx->plugin_data; |
|
|
|
joblist_append(srv, con); |
|
|
if ((revents & FDEVENT_IN) && | if (revents & FDEVENT_IN) { |
hctx->state == PROXY_STATE_READ) { | |
|
|
if (p->conf.debug) { |
if (p->conf.debug) { |
log_error_write(srv, __FILE__, __LINE__, "sd", |
log_error_write(srv, __FILE__, __LINE__, "sd", |
"proxy: fdevent-in", hctx->state); |
"proxy: fdevent-in", hctx->state); |
} |
} |
|
|
switch (proxy_demux_response(srv, hctx)) { | { |
case 0: | handler_t rc = proxy_recv_response(srv,hctx);/*(might invalidate hctx)*/ |
break; | if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ |
case 1: | |
/* we are done */ | |
proxy_connection_close(srv, hctx); | |
| |
joblist_append(srv, con); | |
return HANDLER_FINISHED; | |
case -1: | |
if (con->file_started == 0) { | |
/* nothing has been send out yet, send a 500 */ | |
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); | |
con->http_status = 500; | |
con->mode = DIRECT; | |
} else { | |
/* response might have been already started, kill the connection */ | |
connection_set_state(srv, con, CON_STATE_ERROR); | |
} | |
| |
joblist_append(srv, con); | |
return HANDLER_FINISHED; | |
} |
} |
} |
} |
|
|
Line 1003 static handler_t proxy_handle_fdevent(server *srv, voi
|
Line 1061 static handler_t proxy_handle_fdevent(server *srv, voi
|
int socket_error; |
int socket_error; |
socklen_t socket_error_len = sizeof(socket_error); |
socklen_t socket_error_len = sizeof(socket_error); |
|
|
/* we don't need it anymore */ |
|
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); |
|
hctx->fde_ndx = -1; |
|
|
|
/* try to finish the connect() */ |
/* try to finish the connect() */ |
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) { |
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) { |
log_error_write(srv, __FILE__, __LINE__, "ss", |
log_error_write(srv, __FILE__, __LINE__, "ss", |
"getsockopt failed:", strerror(errno)); |
"getsockopt failed:", strerror(errno)); |
|
|
joblist_append(srv, con); |
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
if (socket_error != 0) { |
if (socket_error != 0) { |
Line 1020 static handler_t proxy_handle_fdevent(server *srv, voi
|
Line 1073 static handler_t proxy_handle_fdevent(server *srv, voi
|
"establishing connection failed:", strerror(socket_error), |
"establishing connection failed:", strerror(socket_error), |
"port:", hctx->host->port); |
"port:", hctx->host->port); |
|
|
joblist_append(srv, con); |
|
return HANDLER_FINISHED; |
return HANDLER_FINISHED; |
} |
} |
if (p->conf.debug) { |
if (p->conf.debug) { |
Line 1030 static handler_t proxy_handle_fdevent(server *srv, voi
|
Line 1082 static handler_t proxy_handle_fdevent(server *srv, voi
|
proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE); |
proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE); |
} |
} |
|
|
if (hctx->state == PROXY_STATE_PREPARE_WRITE || | return proxy_send_request(srv, hctx); /*(might invalidate hctx)*/ |
hctx->state == PROXY_STATE_WRITE) { | |
/* we are allowed to send something out | |
* | |
* 1. after a just finished connect() call | |
* 2. in a unfinished write() call (long POST request) | |
*/ | |
return mod_proxy_handle_subrequest(srv, con, p); | |
} else { | |
log_error_write(srv, __FILE__, __LINE__, "sd", | |
"proxy: out", hctx->state); | |
} | |
} |
} |
|
|
/* perhaps this issue is already handled */ |
/* perhaps this issue is already handled */ |
Line 1071 static handler_t proxy_handle_fdevent(server *srv, voi
|
Line 1112 static handler_t proxy_handle_fdevent(server *srv, voi
|
hctx->host->is_disabled = 1; |
hctx->host->is_disabled = 1; |
hctx->host->disable_ts = srv->cur_ts; |
hctx->host->disable_ts = srv->cur_ts; |
|
|
|
/* reset the environment and restart the sub-request */ |
|
con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/ |
proxy_connection_close(srv, hctx); |
proxy_connection_close(srv, hctx); |
| con->mode = p->id; |
/* reset the enviroment and restart the sub-request */ | |
buffer_reset(con->physical.path); | |
con->mode = DIRECT; | |
| |
joblist_append(srv, con); | |
} else { |
} else { |
proxy_connection_close(srv, hctx); |
proxy_connection_close(srv, hctx); |
joblist_append(srv, con); |
|
|
|
con->mode = DIRECT; |
|
con->http_status = 503; |
con->http_status = 503; |
} |
} |
| } else if (con->file_started) { |
return HANDLER_FINISHED; | /* drain any remaining data from kernel pipe buffers |
| * even if (con->conf.stream_response_body |
| * & FDEVENT_STREAM_RESPONSE_BUFMIN) |
| * since event loop will spin on fd FDEVENT_HUP event |
| * until unregistered. */ |
| handler_t rc; |
| do { |
| rc = proxy_recv_response(srv,hctx);/*(might invalidate hctx)*/ |
| } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/ |
| return rc; /* HANDLER_FINISHED or HANDLER_ERROR */ |
| } else { |
| proxy_connection_close(srv, hctx); |
} |
} |
|
|
if (!con->file_finished) { |
|
http_chunk_append_mem(srv, con, NULL, 0); |
|
} |
|
|
|
con->file_finished = 1; |
|
proxy_connection_close(srv, hctx); |
|
joblist_append(srv, con); |
|
} else if (revents & FDEVENT_ERR) { |
} else if (revents & FDEVENT_ERR) { |
/* kill all connections to the proxy process */ |
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents); |
log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents); |
|
|
con->file_finished = 1; | http_response_backend_error(srv, con); |
joblist_append(srv, con); | |
proxy_connection_close(srv, hctx); |
proxy_connection_close(srv, hctx); |
} |
} |
|
|
Line 1128 static handler_t mod_proxy_check_extension(server *srv
|
Line 1163 static handler_t mod_proxy_check_extension(server *srv
|
mod_proxy_patch_connection(srv, con, p); |
mod_proxy_patch_connection(srv, con, p); |
|
|
fn = con->uri.path; |
fn = con->uri.path; |
|
if (buffer_string_is_empty(fn)) return HANDLER_ERROR; |
|
s_len = buffer_string_length(fn); |
|
|
if (fn->used == 0) { |
|
return HANDLER_ERROR; |
|
} |
|
|
|
s_len = fn->used - 1; |
|
|
|
|
|
path_info_offset = 0; |
path_info_offset = 0; |
|
|
if (p->conf.debug) { |
if (p->conf.debug) { |
Line 1149 static handler_t mod_proxy_check_extension(server *srv
|
Line 1179 static handler_t mod_proxy_check_extension(server *srv
|
|
|
ext = (data_array *)p->conf.extensions->data[k]; |
ext = (data_array *)p->conf.extensions->data[k]; |
|
|
if (ext->key->used == 0) continue; | if (buffer_is_empty(ext->key)) continue; |
|
|
ct_len = ext->key->used - 1; | ct_len = buffer_string_length(ext->key); |
|
|
if (s_len < ct_len) continue; |
if (s_len < ct_len) continue; |
|
|
Line 1256 static handler_t mod_proxy_check_extension(server *srv
|
Line 1286 static handler_t mod_proxy_check_extension(server *srv
|
} |
} |
|
|
/* just to be sure */ |
/* just to be sure */ |
assert(extension->value->used < INT_MAX); | force_assert(extension->value->used < INT_MAX); |
|
|
host = (data_proxy *)extension->value->data[0]; |
host = (data_proxy *)extension->value->data[0]; |
|
|
Line 1333 static handler_t mod_proxy_check_extension(server *srv
|
Line 1363 static handler_t mod_proxy_check_extension(server *srv
|
return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
} |
} |
|
|
static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) { | static handler_t mod_proxy_connection_reset(server *srv, connection *con, void *p_d) { |
plugin_data *p = p_d; |
plugin_data *p = p_d; |
|
handler_ctx *hctx = con->plugin_ctx[p->id]; |
|
if (hctx) proxy_connection_close(srv, hctx); |
|
|
proxy_connection_close(srv, con->plugin_ctx[p->id]); |
|
|
|
return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
} |
} |
|
|
Line 1391 int mod_proxy_plugin_init(plugin *p) {
|
Line 1421 int mod_proxy_plugin_init(plugin *p) {
|
p->init = mod_proxy_init; |
p->init = mod_proxy_init; |
p->cleanup = mod_proxy_free; |
p->cleanup = mod_proxy_free; |
p->set_defaults = mod_proxy_set_defaults; |
p->set_defaults = mod_proxy_set_defaults; |
p->connection_reset = mod_proxy_connection_close_callback; /* end of req-resp cycle */ | p->connection_reset = mod_proxy_connection_reset; /* end of req-resp cycle */ |
p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */ | p->handle_connection_close = mod_proxy_connection_reset; /* end of client connection */ |
p->handle_uri_clean = mod_proxy_check_extension; |
p->handle_uri_clean = mod_proxy_check_extension; |
p->handle_subrequest = mod_proxy_handle_subrequest; |
p->handle_subrequest = mod_proxy_handle_subrequest; |
p->handle_trigger = mod_proxy_trigger; |
p->handle_trigger = mod_proxy_trigger; |