2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "buffer.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "connections.h"
|
|
|
|
#include "fdevent.h"
|
|
|
|
|
2016-02-21 18:32:17 +00:00
|
|
|
#include "configfile.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "request.h"
|
|
|
|
#include "response.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "http_chunk.h"
|
2005-08-08 08:22:06 +00:00
|
|
|
#include "stat_cache.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "joblist.h"
|
|
|
|
|
|
|
|
#include "plugin.h"
|
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
#include "inet_ntop_cache.h"
|
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef USE_OPENSSL
|
2006-10-04 13:26:23 +00:00
|
|
|
# include <openssl/ssl.h>
|
|
|
|
# include <openssl/err.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_FILIO_H
|
|
|
|
# include <sys/filio.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "sys-socket.h"
|
|
|
|
|
2005-09-02 17:07:00 +00:00
|
|
|
typedef struct {
|
|
|
|
PLUGIN_DATA;
|
|
|
|
} plugin_data;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
static connection *connections_get_new_connection(server *srv) {
|
|
|
|
connections *conns = srv->conns;
|
|
|
|
size_t i;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (conns->size == 0) {
|
|
|
|
conns->size = 128;
|
|
|
|
conns->ptr = NULL;
|
|
|
|
conns->ptr = malloc(sizeof(*conns->ptr) * conns->size);
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != conns->ptr);
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < conns->size; i++) {
|
|
|
|
conns->ptr[i] = connection_init(srv);
|
|
|
|
}
|
|
|
|
} else if (conns->size == conns->used) {
|
|
|
|
conns->size += 128;
|
|
|
|
conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != conns->ptr);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = conns->used; i < conns->size; i++) {
|
|
|
|
conns->ptr[i] = connection_init(srv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
connection_reset(srv, conns->ptr[conns->used]);
|
2006-10-04 13:26:23 +00:00
|
|
|
#if 0
|
2005-02-20 14:27:00 +00:00
|
|
|
fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
|
|
|
|
for (i = 0; i < conns->used + 1; i++) {
|
|
|
|
fprintf(stderr, "%d ", conns->ptr[i]->fd);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
2006-10-04 13:26:23 +00:00
|
|
|
#endif
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
conns->ptr[conns->used]->ndx = conns->used;
|
|
|
|
return conns->ptr[conns->used++];
|
|
|
|
}
|
|
|
|
|
|
|
|
static int connection_del(server *srv, connection *con) {
|
|
|
|
size_t i;
|
|
|
|
connections *conns = srv->conns;
|
|
|
|
connection *temp;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (con == NULL) return -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (-1 == con->ndx) return -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2010-04-28 19:08:11 +00:00
|
|
|
buffer_reset(con->uri.authority);
|
|
|
|
buffer_reset(con->uri.path);
|
|
|
|
buffer_reset(con->uri.query);
|
|
|
|
buffer_reset(con->request.orig_uri);
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
i = con->ndx;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
/* not last element */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (i != conns->used - 1) {
|
|
|
|
temp = conns->ptr[i];
|
|
|
|
conns->ptr[i] = conns->ptr[conns->used - 1];
|
|
|
|
conns->ptr[conns->used - 1] = temp;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
conns->ptr[i]->ndx = i;
|
|
|
|
conns->ptr[conns->used - 1]->ndx = -1;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
conns->used--;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->ndx = -1;
|
|
|
|
#if 0
|
|
|
|
fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
|
|
|
|
for (i = 0; i < conns->used; i++) {
|
|
|
|
fprintf(stderr, "%d ", conns->ptr[i]->fd);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
2006-10-04 13:26:23 +00:00
|
|
|
#endif
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-07 23:47:49 +00:00
|
|
|
static int connection_close(server *srv, connection *con) {
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
server_socket *srv_sock = con->srv_socket;
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
if (srv_sock->is_ssl) {
|
|
|
|
if (con->ssl) SSL_free(con->ssl);
|
|
|
|
con->ssl = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
|
|
|
|
fdevent_unregister(srv->ev, con->fd);
|
|
|
|
#ifdef __WIN32
|
|
|
|
if (closesocket(con->fd)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sds",
|
|
|
|
"(warning) close:", con->fd, strerror(errno));
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (close(con->fd)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sds",
|
|
|
|
"(warning) close:", con->fd, strerror(errno));
|
|
|
|
}
|
|
|
|
#endif
|
2016-04-11 03:20:54 +00:00
|
|
|
con->fd = -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
srv->cur_fds--;
|
|
|
|
#if 0
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd",
|
|
|
|
"closed()", con->fd);
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
connection_del(srv, con);
|
|
|
|
connection_set_state(srv, con, CON_STATE_CONNECT);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-11 01:38:09 +00:00
|
|
|
static void connection_handle_errdoc_init(server *srv, connection *con) {
|
|
|
|
/* modules that produce headers required with error response should
|
|
|
|
* typically also produce an error document. Make an exception for
|
|
|
|
* mod_auth WWW-Authenticate response header. */
|
|
|
|
buffer *www_auth = NULL;
|
|
|
|
if (401 == con->http_status) {
|
|
|
|
data_string *ds = (data_string *)array_get_element(con->response.headers, "WWW-Authenticate");
|
|
|
|
if (NULL != ds) {
|
|
|
|
www_auth = buffer_init_buffer(ds->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-19 00:39:00 +00:00
|
|
|
con->response.transfer_encoding = 0;
|
2016-05-02 20:23:51 +00:00
|
|
|
buffer_reset(con->physical.path);
|
|
|
|
array_reset(con->response.headers);
|
|
|
|
chunkqueue_reset(con->write_queue);
|
2016-05-11 01:38:09 +00:00
|
|
|
|
|
|
|
if (NULL != www_auth) {
|
|
|
|
response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(www_auth));
|
|
|
|
buffer_free(www_auth);
|
|
|
|
}
|
2016-04-13 05:04:39 +00:00
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
static int connection_handle_write_prepare(server *srv, connection *con) {
|
2005-08-15 09:55:23 +00:00
|
|
|
if (con->mode == DIRECT) {
|
|
|
|
/* static files */
|
|
|
|
switch(con->request.http_method) {
|
|
|
|
case HTTP_METHOD_GET:
|
|
|
|
case HTTP_METHOD_POST:
|
|
|
|
case HTTP_METHOD_HEAD:
|
|
|
|
break;
|
2005-08-19 08:37:52 +00:00
|
|
|
case HTTP_METHOD_OPTIONS:
|
2006-01-03 13:59:46 +00:00
|
|
|
/*
|
|
|
|
* 400 is coming from the request-parser BEFORE uri.path is set
|
2006-10-04 13:26:23 +00:00
|
|
|
* 403 is from the response handler when noone else catched it
|
|
|
|
*
|
2006-01-03 13:59:46 +00:00
|
|
|
* */
|
2015-02-08 19:10:44 +00:00
|
|
|
if ((!con->http_status || con->http_status == 200) && !buffer_string_is_empty(con->uri.path) &&
|
2006-01-03 13:59:46 +00:00
|
|
|
con->uri.path->ptr[0] != '*') {
|
2005-08-19 08:37:52 +00:00
|
|
|
response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
|
|
|
|
|
2008-02-27 12:15:38 +00:00
|
|
|
con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
|
|
|
|
con->parsed_response &= ~HTTP_CONTENT_LENGTH;
|
|
|
|
|
2005-08-19 08:37:52 +00:00
|
|
|
con->http_status = 200;
|
|
|
|
con->file_finished = 1;
|
|
|
|
|
|
|
|
chunkqueue_reset(con->write_queue);
|
|
|
|
}
|
|
|
|
break;
|
2005-08-15 09:55:23 +00:00
|
|
|
default:
|
2013-06-29 10:53:22 +00:00
|
|
|
if (0 == con->http_status) {
|
2005-08-15 09:55:23 +00:00
|
|
|
con->http_status = 501;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
if (con->http_status == 0) {
|
|
|
|
con->http_status = 403;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
switch(con->http_status) {
|
2008-04-23 19:10:42 +00:00
|
|
|
case 204: /* class: header only */
|
|
|
|
case 205:
|
|
|
|
case 304:
|
|
|
|
/* disable chunked encoding again as we have no body */
|
|
|
|
con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
|
|
|
|
con->parsed_response &= ~HTTP_CONTENT_LENGTH;
|
|
|
|
chunkqueue_reset(con->write_queue);
|
|
|
|
|
|
|
|
con->file_finished = 1;
|
|
|
|
break;
|
|
|
|
default: /* class: header + body */
|
2005-08-15 09:55:23 +00:00
|
|
|
if (con->mode != DIRECT) break;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2008-04-23 19:10:42 +00:00
|
|
|
/* only custom body for 4xx and 5xx */
|
|
|
|
if (con->http_status < 400 || con->http_status >= 600) break;
|
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
con->file_finished = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-05-11 01:38:09 +00:00
|
|
|
connection_handle_errdoc_init(srv, con);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
/* try to send static errorfile */
|
2015-02-08 12:37:10 +00:00
|
|
|
if (!buffer_string_is_empty(con->conf.errorfile_prefix)) {
|
2005-08-15 09:55:23 +00:00
|
|
|
stat_cache_entry *sce = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(con->physical.path, con->conf.errorfile_prefix);
|
|
|
|
buffer_append_int(con->physical.path, con->http_status);
|
2008-04-23 19:10:42 +00:00
|
|
|
buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-03-30 10:39:33 +00:00
|
|
|
if (0 == http_chunk_append_file(srv, con, con->physical.path)) {
|
2005-08-15 09:55:23 +00:00
|
|
|
con->file_finished = 1;
|
2016-03-30 10:39:33 +00:00
|
|
|
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
|
|
|
|
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
if (!con->file_finished) {
|
2005-08-15 09:55:23 +00:00
|
|
|
buffer *b;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
buffer_reset(con->physical.path);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->file_finished = 1;
|
2015-02-08 19:10:36 +00:00
|
|
|
b = buffer_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
/* build default error-page */
|
2008-07-30 19:38:32 +00:00
|
|
|
buffer_copy_string_len(b, CONST_STR_LEN(
|
2005-08-15 09:55:23 +00:00
|
|
|
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
|
|
|
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
|
|
|
|
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
|
|
|
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
|
|
|
|
" <head>\n"
|
2008-07-30 19:38:32 +00:00
|
|
|
" <title>"));
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(b, con->http_status);
|
2008-07-30 19:38:32 +00:00
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(" - "));
|
2005-08-15 09:55:23 +00:00
|
|
|
buffer_append_string(b, get_http_status_name(con->http_status));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2008-07-30 19:38:32 +00:00
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(
|
2005-08-15 09:55:23 +00:00
|
|
|
"</title>\n"
|
|
|
|
" </head>\n"
|
|
|
|
" <body>\n"
|
2008-07-30 19:38:32 +00:00
|
|
|
" <h1>"));
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_append_int(b, con->http_status);
|
2008-07-30 19:38:32 +00:00
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(" - "));
|
2005-08-15 09:55:23 +00:00
|
|
|
buffer_append_string(b, get_http_status_name(con->http_status));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2008-07-30 19:38:32 +00:00
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("</h1>\n"
|
2005-08-15 09:55:23 +00:00
|
|
|
" </body>\n"
|
|
|
|
"</html>\n"
|
2008-07-30 19:38:32 +00:00
|
|
|
));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 19:10:36 +00:00
|
|
|
http_chunk_append_buffer(srv, con, b);
|
|
|
|
buffer_free(b);
|
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2005-08-15 09:55:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
if (con->file_finished) {
|
2006-10-04 13:26:23 +00:00
|
|
|
/* we have all the content and chunked encoding is not used, set a content-length */
|
|
|
|
|
|
|
|
if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
|
2006-10-07 17:47:49 +00:00
|
|
|
(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
|
|
|
|
off_t qlen = chunkqueue_length(con->write_queue);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2007-08-18 10:40:20 +00:00
|
|
|
/**
|
|
|
|
* The Content-Length header only can be sent if we have content:
|
|
|
|
* - HEAD doesn't have a content-body (but have a content-length)
|
|
|
|
* - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
|
|
|
|
*
|
|
|
|
* Otherwise generate a Content-Length header as chunked encoding is not
|
|
|
|
* available
|
|
|
|
*/
|
|
|
|
if ((con->http_status >= 100 && con->http_status < 200) ||
|
|
|
|
con->http_status == 204 ||
|
|
|
|
con->http_status == 304) {
|
2008-02-27 12:15:38 +00:00
|
|
|
data_string *ds;
|
2007-08-18 10:40:20 +00:00
|
|
|
/* no Content-Body, no Content-Length */
|
2008-02-27 12:15:38 +00:00
|
|
|
if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) {
|
2008-04-23 13:10:41 +00:00
|
|
|
buffer_reset(ds->value); /* Headers with empty values are ignored for output */
|
2008-02-27 12:15:38 +00:00
|
|
|
}
|
2008-02-27 18:35:42 +00:00
|
|
|
} else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) {
|
2007-09-06 11:24:20 +00:00
|
|
|
/* qlen = 0 is important for Redirects (301, ...) as they MAY have
|
|
|
|
* a content. Browsers are waiting for a Content otherwise
|
|
|
|
*/
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_int(srv->tmp_buf, qlen);
|
2006-10-07 17:47:49 +00:00
|
|
|
|
|
|
|
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
|
|
|
|
}
|
2005-08-21 17:52:06 +00:00
|
|
|
}
|
2005-08-15 09:55:23 +00:00
|
|
|
} else {
|
2007-08-17 15:37:45 +00:00
|
|
|
/**
|
|
|
|
* the file isn't finished yet, but we have all headers
|
|
|
|
*
|
|
|
|
* to get keep-alive we either need:
|
|
|
|
* - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
|
|
|
|
* - Transfer-Encoding: chunked (HTTP/1.1)
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) &&
|
2005-08-15 09:55:23 +00:00
|
|
|
((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
|
|
|
|
con->keep_alive = 0;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2007-08-17 15:37:45 +00:00
|
|
|
/**
|
|
|
|
* if the backend sent a Connection: close, follow the wish
|
|
|
|
*
|
|
|
|
* NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
|
|
|
|
* will close the connection. That's fine. We can always decide the close
|
|
|
|
* the connection
|
|
|
|
*
|
|
|
|
* FIXME: to be nice we should remove the Connection: ...
|
|
|
|
*/
|
|
|
|
if (con->parsed_response & HTTP_CONNECTION) {
|
2005-02-20 14:27:00 +00:00
|
|
|
/* a subrequest disable keep-alive although the client wanted it */
|
|
|
|
if (con->keep_alive && !con->response.keep_alive) {
|
|
|
|
con->keep_alive = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
if (con->request.http_method == HTTP_METHOD_HEAD) {
|
2006-10-05 10:23:27 +00:00
|
|
|
/**
|
|
|
|
* a HEAD request has the same as a GET
|
|
|
|
* without the content
|
|
|
|
*/
|
2008-02-27 12:15:38 +00:00
|
|
|
con->file_finished = 1;
|
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
chunkqueue_reset(con->write_queue);
|
2006-10-05 10:23:27 +00:00
|
|
|
con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
|
2005-08-15 09:55:23 +00:00
|
|
|
}
|
2005-08-19 08:37:52 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
http_response_write_header(srv, con);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int connection_handle_write(server *srv, connection *con) {
|
2011-08-22 15:12:28 +00:00
|
|
|
switch(network_write_chunkqueue(srv, con, con->write_queue, MAX_WRITE_LIMIT)) {
|
2005-02-20 14:27:00 +00:00
|
|
|
case 0:
|
2011-08-22 15:12:28 +00:00
|
|
|
con->write_request_ts = srv->cur_ts;
|
2005-02-20 14:27:00 +00:00
|
|
|
if (con->file_finished) {
|
|
|
|
connection_set_state(srv, con, CON_STATE_RESPONSE_END);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case -1: /* error on our side */
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd",
|
|
|
|
"connection closed: write failed on fd", con->fd);
|
|
|
|
connection_set_state(srv, con, CON_STATE_ERROR);
|
|
|
|
break;
|
|
|
|
case -2: /* remote close */
|
|
|
|
connection_set_state(srv, con, CON_STATE_ERROR);
|
|
|
|
break;
|
|
|
|
case 1:
|
2011-08-22 15:12:28 +00:00
|
|
|
con->write_request_ts = srv->cur_ts;
|
2005-02-20 14:27:00 +00:00
|
|
|
con->is_writable = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
/* not finished yet -> WRITE */
|
|
|
|
break;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
connection *connection_init(server *srv) {
|
|
|
|
connection *con;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
UNUSED(srv);
|
|
|
|
|
|
|
|
con = calloc(1, sizeof(*con));
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != con);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->fd = 0;
|
|
|
|
con->ndx = -1;
|
|
|
|
con->fde_ndx = -1;
|
|
|
|
con->bytes_written = 0;
|
|
|
|
con->bytes_read = 0;
|
|
|
|
con->bytes_header = 0;
|
2005-07-23 20:42:34 +00:00
|
|
|
con->loops_per_request = 0;
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
#define CLEAN(x) \
|
|
|
|
con->x = buffer_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(request.uri);
|
|
|
|
CLEAN(request.request_line);
|
|
|
|
CLEAN(request.request);
|
|
|
|
CLEAN(request.pathinfo);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(request.orig_uri);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(uri.scheme);
|
|
|
|
CLEAN(uri.authority);
|
|
|
|
CLEAN(uri.path);
|
|
|
|
CLEAN(uri.path_raw);
|
|
|
|
CLEAN(uri.query);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(physical.doc_root);
|
|
|
|
CLEAN(physical.path);
|
2005-08-08 09:42:27 +00:00
|
|
|
CLEAN(physical.basedir);
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(physical.rel_path);
|
|
|
|
CLEAN(physical.etag);
|
|
|
|
CLEAN(parse_request);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(server_name);
|
2005-08-25 20:09:46 +00:00
|
|
|
CLEAN(dst_addr_buf);
|
2009-10-14 13:39:59 +00:00
|
|
|
#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
|
|
|
|
CLEAN(tlsext_server_name);
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#undef CLEAN
|
|
|
|
con->write_queue = chunkqueue_init();
|
|
|
|
con->read_queue = chunkqueue_init();
|
2005-09-26 08:56:39 +00:00
|
|
|
con->request_content_queue = chunkqueue_init();
|
2015-11-07 12:51:14 +00:00
|
|
|
chunkqueue_set_tempdirs(
|
|
|
|
con->request_content_queue,
|
|
|
|
srv->srvconf.upload_tempdirs,
|
|
|
|
srv->srvconf.upload_temp_file_size);
|
2005-11-01 07:50:08 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->request.headers = array_init();
|
|
|
|
con->response.headers = array_init();
|
|
|
|
con->environment = array_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
/* init plugin specific connection structures */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-11-17 14:08:58 +00:00
|
|
|
con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != con->plugin_ctx);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != con->cond_cache);
|
2005-02-20 14:27:00 +00:00
|
|
|
config_setup_connection(srv, con);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return con;
|
|
|
|
}
|
|
|
|
|
|
|
|
void connections_free(server *srv) {
|
|
|
|
connections *conns = srv->conns;
|
2006-10-04 13:26:23 +00:00
|
|
|
size_t i;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < conns->size; i++) {
|
|
|
|
connection *con = conns->ptr[i];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
connection_reset(srv, con);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
chunkqueue_free(con->write_queue);
|
|
|
|
chunkqueue_free(con->read_queue);
|
2005-09-26 08:56:39 +00:00
|
|
|
chunkqueue_free(con->request_content_queue);
|
2005-02-20 14:27:00 +00:00
|
|
|
array_free(con->request.headers);
|
|
|
|
array_free(con->response.headers);
|
|
|
|
array_free(con->environment);
|
|
|
|
|
|
|
|
#define CLEAN(x) \
|
|
|
|
buffer_free(con->x);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(request.uri);
|
|
|
|
CLEAN(request.request_line);
|
|
|
|
CLEAN(request.request);
|
|
|
|
CLEAN(request.pathinfo);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(request.orig_uri);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(uri.scheme);
|
|
|
|
CLEAN(uri.authority);
|
|
|
|
CLEAN(uri.path);
|
|
|
|
CLEAN(uri.path_raw);
|
|
|
|
CLEAN(uri.query);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(physical.doc_root);
|
|
|
|
CLEAN(physical.path);
|
2005-08-08 09:42:27 +00:00
|
|
|
CLEAN(physical.basedir);
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(physical.etag);
|
|
|
|
CLEAN(physical.rel_path);
|
|
|
|
CLEAN(parse_request);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(server_name);
|
2005-08-25 20:09:46 +00:00
|
|
|
CLEAN(dst_addr_buf);
|
2009-10-14 13:39:59 +00:00
|
|
|
#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
|
|
|
|
CLEAN(tlsext_server_name);
|
|
|
|
#endif
|
2005-02-20 14:27:00 +00:00
|
|
|
#undef CLEAN
|
|
|
|
free(con->plugin_ctx);
|
2005-08-09 06:42:33 +00:00
|
|
|
free(con->cond_cache);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(con);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(conns->ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int connection_reset(server *srv, connection *con) {
|
|
|
|
size_t i;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
plugins_call_connection_reset(srv, con);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->is_readable = 1;
|
|
|
|
con->is_writable = 1;
|
|
|
|
con->http_status = 0;
|
|
|
|
con->file_finished = 0;
|
|
|
|
con->file_started = 0;
|
|
|
|
con->got_response = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->parsed_response = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->bytes_written = 0;
|
|
|
|
con->bytes_written_cur_second = 0;
|
|
|
|
con->bytes_read = 0;
|
|
|
|
con->bytes_header = 0;
|
2005-07-23 20:42:34 +00:00
|
|
|
con->loops_per_request = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->request.http_method = HTTP_METHOD_UNSET;
|
|
|
|
con->request.http_version = HTTP_VERSION_UNSET;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->request.http_if_modified_since = NULL;
|
|
|
|
con->request.http_if_none_match = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->response.keep_alive = 0;
|
|
|
|
con->response.content_length = -1;
|
|
|
|
con->response.transfer_encoding = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->mode = DIRECT;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#define CLEAN(x) \
|
|
|
|
if (con->x) buffer_reset(con->x);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(request.uri);
|
|
|
|
CLEAN(request.request_line);
|
|
|
|
CLEAN(request.pathinfo);
|
|
|
|
CLEAN(request.request);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2009-06-21 17:25:34 +00:00
|
|
|
/* CLEAN(request.orig_uri); */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(uri.scheme);
|
2009-06-21 17:25:34 +00:00
|
|
|
/* CLEAN(uri.authority); */
|
|
|
|
/* CLEAN(uri.path); */
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(uri.path_raw);
|
2009-06-21 17:25:34 +00:00
|
|
|
/* CLEAN(uri.query); */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(physical.doc_root);
|
|
|
|
CLEAN(physical.path);
|
2005-08-08 09:42:27 +00:00
|
|
|
CLEAN(physical.basedir);
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(physical.rel_path);
|
|
|
|
CLEAN(physical.etag);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(parse_request);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(server_name);
|
2009-11-05 17:32:08 +00:00
|
|
|
#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
|
|
|
|
CLEAN(tlsext_server_name);
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
#undef CLEAN
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#define CLEAN(x) \
|
2006-10-04 13:26:23 +00:00
|
|
|
if (con->x) con->x->used = 0;
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#undef CLEAN
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#define CLEAN(x) \
|
|
|
|
con->request.x = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
CLEAN(http_host);
|
|
|
|
CLEAN(http_range);
|
|
|
|
CLEAN(http_content_type);
|
|
|
|
#undef CLEAN
|
|
|
|
con->request.content_length = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
array_reset(con->request.headers);
|
|
|
|
array_reset(con->response.headers);
|
|
|
|
array_reset(con->environment);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
chunkqueue_reset(con->write_queue);
|
2005-09-26 08:56:39 +00:00
|
|
|
chunkqueue_reset(con->request_content_queue);
|
2005-08-08 08:22:06 +00:00
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
/* the plugins should cleanup themself */
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < srv->plugins.used; i++) {
|
2005-09-02 17:07:00 +00:00
|
|
|
plugin *p = ((plugin **)(srv->plugins.ptr))[i];
|
|
|
|
plugin_data *pd = p->data;
|
|
|
|
|
2005-11-17 14:08:58 +00:00
|
|
|
if (!pd) continue;
|
|
|
|
|
2005-09-02 17:07:00 +00:00
|
|
|
if (con->plugin_ctx[pd->id] != NULL) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "missing cleanup in", p->name);
|
2005-08-08 08:22:06 +00:00
|
|
|
}
|
|
|
|
|
2005-09-02 17:07:00 +00:00
|
|
|
con->plugin_ctx[pd->id] = NULL;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2008-02-26 16:19:42 +00:00
|
|
|
/* The cond_cache gets reset in response.c */
|
2008-04-23 13:10:41 +00:00
|
|
|
/* config_cond_cache_reset(srv, con); */
|
2006-09-01 09:53:44 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
con->header_len = 0;
|
2016-02-28 17:05:22 +00:00
|
|
|
con->error_handler_saved_status = 0;
|
[core] server.error-handler new directive for error pages (fixes #2702)
server.error-handler preserves HTTP status error code when error page
is static, and allows dynamic handlers to change HTTP status code
when error page is provided by dynamic handler. server.error-handler
intercepts all HTTP status codes >= 400 except when the content is
generated by a dynamic handler (cgi, ssi, fastcgi, scgi, proxy, lua).
The request method is unconditionally changed to GET for the request
to service the error handler, and the original request method is
later restored (for logging purposes). request body from the
original request, if present, is discarded.
server.error-handler is somewhat similar to server.error-handler-404,
but server.error-handler-404 is now deprecated, intercepts only 404
and 403 HTTP status codes, and returns 200 OK for static error pages,
a source of confusion for some admins. On the other hand, the new
server.error-handler, when set, will intercept all HTTP status error
codes >= 400. server.error-handler takes precedence over
server.error-handler-404 when both are set.
NOTE: a major difference between server.error-handler and the
now-deprecated server.error-handler-404 is that the values of the
non-standard CGI environment variables REQUEST_URI and REDIRECT_URI
have been swapped. Since REDIRECT_STATUS is the original HTTP
status code, REDIRECT_URI is now the original request, and REQUEST_URI
is the current request (e.g. the URI/URL to the error handler).
The prior behavior -- which reversed REQUEST_URI and REDIRECT_URI values
from those described above -- is preserved for server.error-handler-404.
Additionally, REDIRECT_STATUS is now available to mod_magnet, which
continues to have access to request.uri and request.orig_uri.
See further discussion at https://redmine.lighttpd.net/issues/2702
and https://redmine.lighttpd.net/issues/1828
github: closes #36
2016-03-01 05:57:48 +00:00
|
|
|
/*con->error_handler_saved_method = HTTP_METHOD_UNSET;*/
|
|
|
|
/*(error_handler_saved_method value is not valid unless error_handler_saved_status is set)*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|