diff options
Diffstat (limited to 'src/response.c')
-rw-r--r-- | src/response.c | 262 |
1 files changed, 134 insertions, 128 deletions
diff --git a/src/response.c b/src/response.c index 45a1782..5f72a9b 100644 --- a/src/response.c +++ b/src/response.c @@ -30,9 +30,9 @@ int http_response_write_header(server *srv, connection *con) { size_t i; int have_date = 0; int have_server = 0; - + b = chunkqueue_get_prepend_buffer(con->write_queue); - + if (con->request.http_version == HTTP_VERSION_1_1) { BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 "); } else { @@ -41,23 +41,23 @@ int http_response_write_header(server *srv, connection *con) { buffer_append_long(b, con->http_status); BUFFER_APPEND_STRING_CONST(b, " "); buffer_append_string(b, get_http_status_name(con->http_status)); - + if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) { BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: "); buffer_append_string(b, con->keep_alive ? "keep-alive" : "close"); } - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked"); } - - + + /* add all headers */ for (i = 0; i < con->response.headers->used; i++) { data_string *ds; - + ds = (data_string *)con->response.headers->data[i]; - + if (ds->value->used && ds->key->used && 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1; @@ -68,28 +68,28 @@ int http_response_write_header(server *srv, connection *con) { BUFFER_APPEND_STRING_CONST(b, ": "); buffer_append_string_buffer(b, ds->value); #if 0 - log_error_write(srv, __FILE__, __LINE__, "bb", + log_error_write(srv, __FILE__, __LINE__, "bb", ds->key, ds->value); #endif } } - + if (!have_date) { /* HTTP/1.1 requires a Date: header */ BUFFER_APPEND_STRING_CONST(b, "\r\nDate: "); - + /* cache the generated timestamp */ if (srv->cur_ts != srv->last_generated_date_ts) { buffer_prepare_copy(srv->ts_date_str, 255); - - strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, + + strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts))); - + srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1; - + srv->last_generated_date_ts = srv->cur_ts; } - + buffer_append_string_buffer(b, srv->ts_date_str); } @@ -101,16 +101,16 @@ int http_response_write_header(server *srv, connection *con) { buffer_append_string_buffer(b, con->conf.server_tag); } } - + BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n"); - - + + con->bytes_header = b->used - 1; - + if (con->conf.log_response_header) { log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b); } - + return 0; } @@ -118,71 +118,77 @@ int http_response_write_header(server *srv, connection *con) { handler_t http_response_prepare(server *srv, connection *con) { handler_t r; - + /* looks like someone has already done a decision */ - if (con->mode == DIRECT && + if (con->mode == DIRECT && (con->http_status != 0 && con->http_status != 200)) { /* remove a packets in the queue */ if (con->file_finished == 0) { chunkqueue_reset(con->write_queue); } - + return HANDLER_FINISHED; } - + /* no decision yet, build conf->filename */ if (con->mode == DIRECT && con->physical.path->used == 0) { char *qstr; /* we only come here when we have the parse the full request again - * - * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a + * + * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a * problem here as mod_setenv might get called multiple times * * fastcgi-auth might lead to a COMEBACK too * fastcgi again dead server too * * mod_compress might add headers twice too - * + * * */ - + if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "run condition"); } config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */ - + /** * prepare strings - * - * - uri.path_raw + * + * - uri.path_raw * - uri.path (secure) * - uri.query - * + * */ - - /** + + /** * Name according to RFC 2396 - * + * * - scheme * - authority * - path * - query - * - * (scheme)://(authority)(path)?(query) - * - * + * + * (scheme)://(authority)(path)?(query)#fragment + * + * */ - + buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http"); buffer_copy_string_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); - + config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */ config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */ config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */ config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */ config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */ - + + /** their might be a fragment which has to be cut away */ + if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { + con->request.uri->used = qstr - con->request.uri->ptr; + con->request.uri->ptr[con->request.uri->used++] = '\0'; + } + /** extract query string from request.uri */ if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) { buffer_copy_string (con->uri.query, qstr + 1); @@ -200,22 +206,22 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query); } - + /* disable keep-alive if requested */ - + if (con->request_count > con->conf.max_keep_alive_requests) { con->keep_alive = 0; } - - + + /** - * - * call plugins - * + * + * call plugins + * * - based on the raw URL - * + * */ - + switch(r = plugins_call_handle_uri_raw(srv, con)) { case HANDLER_GO_ON: break; @@ -229,14 +235,14 @@ handler_t http_response_prepare(server *srv, connection *con) { break; } - /* build filename + /* build filename * * - decode url-encodings (e.g. %20 -> ' ') * - remove path-modifiers (e.g. /../) */ - - - + + + if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* OPTIONS * ... */ @@ -253,13 +259,13 @@ handler_t http_response_prepare(server *srv, connection *con) { } /** - * - * call plugins - * + * + * call plugins + * * - based on the clean URL - * + * */ - + config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */ config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */ @@ -280,11 +286,11 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, ""); break; } - + if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* option requests are handled directly without checking of the path */ - + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); con->http_status = 200; @@ -294,38 +300,38 @@ handler_t http_response_prepare(server *srv, connection *con) { } /*** - * - * border - * + * + * border + * * logical filename (URI) becomes a physical filename here - * - * - * + * + * + * */ - - - - + + + + /* 1. stat() * ... ISREG() -> ok, go on * ... ISDIR() -> index-file -> redirect - * - * 2. pathinfo() + * + * 2. pathinfo() * ... ISREG() - * + * * 3. -> 404 - * + * */ - + /* * SEARCH DOCUMENT ROOT */ - + /* set a default */ - + buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root); buffer_copy_string_buffer(con->physical.rel_path, con->uri.path); - + #if defined(__WIN32) || defined(__CYGWIN__) /* strip dots from the end and spaces * @@ -383,9 +389,9 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, ""); break; } - - /* MacOS X and Windows can't distiguish between upper and lower-case - * + + /* MacOS X and Windows can't distiguish between upper and lower-case + * * convert to lower-case */ if (con->conf.force_lowercase_filenames) { @@ -396,13 +402,13 @@ handler_t http_response_prepare(server *srv, connection *con) { if (buffer_is_empty(con->server_name)) { buffer_copy_string_buffer(con->server_name, con->uri.authority); } - - /** - * create physical filename + + /** + * create physical filename * -> physical.path = docroot + rel_path - * + * */ - + buffer_copy_string_buffer(con->physical.path, con->physical.doc_root); BUFFER_APPEND_SLASH(con->physical.path); buffer_copy_string_buffer(con->physical.basedir, con->physical.path); @@ -432,7 +438,7 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, ""); break; } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); @@ -440,19 +446,19 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } } - - /* + + /* * Noone catched away the file from normal path of execution yet (like mod_access) - * + * * Go on and check of the file exists at all */ - + if (con->mode == DIRECT) { char *slash = NULL; char *pathinfo = NULL; int found = 0; stat_cache_entry *sce = NULL; - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -460,7 +466,7 @@ handler_t http_response_prepare(server *srv, connection *con) { if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { /* file exists */ - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -481,9 +487,9 @@ handler_t http_response_prepare(server *srv, connection *con) { if (S_ISDIR(sce->st.st_mode)) { if (con->physical.path->ptr[con->physical.path->used - 2] != '/') { /* redirect to .../ */ - + http_response_redirect_to_directory(srv, con); - + return HANDLER_FINISHED; } #ifdef HAVE_LSTAT @@ -499,12 +505,12 @@ handler_t http_response_prepare(server *srv, connection *con) { switch (errno) { case EACCES: con->http_status = 403; - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } - + buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENOENT: @@ -524,74 +530,74 @@ handler_t http_response_prepare(server *srv, connection *con) { /* we have no idea what happend. let's tell the user so. */ con->http_status = 500; buffer_reset(con->physical.path); - + log_error_write(srv, __FILE__, __LINE__, "ssbsb", "file not found ... or so: ", strerror(errno), con->uri.path, "->", con->physical.path); - + return HANDLER_FINISHED; } - + /* not found, perhaps PATHINFO */ - + buffer_copy_string_buffer(srv->tmp_buf, con->physical.path); - + do { struct stat st; - + if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_string_buffer(con->physical.path, srv->tmp_buf); } - + if (0 == stat(con->physical.path->ptr, &(st)) && S_ISREG(st.st_mode)) { found = 1; break; } - + if (pathinfo != NULL) { *pathinfo = '\0'; } slash = strrchr(srv->tmp_buf->ptr, '/'); - + if (pathinfo != NULL) { /* restore '/' */ *pathinfo = '/'; } - + if (slash) pathinfo = slash; - } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2)); - + } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2))); + if (found == 0) { /* no it really doesn't exists */ con->http_status = 404; - + if (con->conf.log_file_not_found) { log_error_write(srv, __FILE__, __LINE__, "sbsb", "file not found:", con->uri.path, "->", con->physical.path); } - + buffer_reset(con->physical.path); - + return HANDLER_FINISHED; } - + /* we have a PATHINFO */ if (pathinfo) { buffer_copy_string(con->request.pathinfo, pathinfo); - + /* * shorten uri.path */ - + con->uri.path->used -= strlen(pathinfo); con->uri.path->ptr[con->uri.path->used - 1] = '\0'; } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -599,12 +605,12 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo); } } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } - + /* call the handlers */ switch(r = plugins_call_handle_subrequest_start(srv, con)) { case HANDLER_GO_ON: @@ -615,21 +621,21 @@ handler_t http_response_prepare(server *srv, connection *con) { if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished"); } - + /* something strange happend */ return r; } - + /* if we are still here, no one wanted the file, status 403 is ok I think */ - + if (con->mode == DIRECT) { con->http_status = 403; - + return HANDLER_FINISHED; } - + } - + switch(r = plugins_call_handle_subrequest(srv, con)) { case HANDLER_GO_ON: /* request was not handled, looks like we are done */ @@ -640,7 +646,7 @@ handler_t http_response_prepare(server *srv, connection *con) { /* something strange happend */ return r; } - + /* can't happen */ return HANDLER_COMEBACK; } |