static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) { stat_cache_entry *sce = NULL; force_assert(!buffer_string_is_empty(p->conf.server_root)); buffer_string_prepare_copy(out, 127); buffer_copy_buffer(out, p->conf.server_root); if (!buffer_string_is_empty(host)) { /* a hostname has to start with a alpha-numerical character * and must not contain a slash "/" */ char *dp; buffer_append_slash(out); if (NULL == (dp = strchr(host->ptr, ':'))) { buffer_append_string_buffer(out, host); } else { buffer_append_string_len(out, host->ptr, dp - host->ptr); } } buffer_append_slash(out); if (buffer_string_length(p->conf.document_root) > 1 && p->conf.document_root->ptr[0] == '/') { buffer_append_string_len(out, p->conf.document_root->ptr + 1, buffer_string_length(p->conf.document_root) - 1); } else { buffer_append_string_buffer(out, p->conf.document_root); buffer_append_slash(out); } if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), out); } return -1; } else if (!S_ISDIR(sce->st.st_mode)) { return -1; } return 0; }
static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); buffer_append_string_len(out, CONST_STR_LEN( "</tbody>\n" "</table>\n" "</div>\n" )); if (!buffer_string_is_empty(p->conf.show_readme)) { /* if we have a README file, display it in <pre class="readme"></pre> */ buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_slash(p->tmp_buf); buffer_append_string_buffer(p->tmp_buf, p->conf.show_readme); http_list_directory_include_file(out, p->tmp_buf, "readme", p->conf.encode_readme); } if(p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<div class=\"foot\">" )); if (!buffer_string_is_empty(p->conf.set_footer)) { buffer_append_string_buffer(out, p->conf.set_footer); } else { buffer_append_string_buffer(out, con->conf.server_tag); } buffer_append_string_len(out, CONST_STR_LEN( "</div>\n" )); if (!buffer_string_is_empty(p->conf.external_js)) { buffer_append_string_len(out, CONST_STR_LEN("<script type=\"text/javascript\" src=\"")); buffer_append_string_buffer(out, p->conf.external_js); buffer_append_string_len(out, CONST_STR_LEN("\"></script>\n")); } else if (buffer_is_empty(p->conf.external_js)) { http_dirlist_append_js_table_resort(out, con); } buffer_append_string_len(out, CONST_STR_LEN( "</body>\n" "</html>\n" )); } }
static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); buffer_append_string_len(out, CONST_STR_LEN( "</tbody>\n" "</table>\n" "</div>\n" )); if (p->conf.show_readme) { stream s; /* if we have a README file, display it in <pre class="readme"></pre> */ buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_slash(p->tmp_buf); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt")); if (-1 != stream_open(&s, p->tmp_buf)) { if (p->conf.encode_readme) { buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"readme\">")); buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</pre>")); } else { buffer_append_string_len(out, s.start, s.size); } } stream_close(&s); } if(p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<div class=\"foot\">" )); if (!buffer_string_is_empty(p->conf.set_footer)) { buffer_append_string_buffer(out, p->conf.set_footer); } else if (buffer_is_empty(con->conf.server_tag)) { buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_DESC)); } else { buffer_append_string_buffer(out, con->conf.server_tag); } buffer_append_string_len(out, CONST_STR_LEN( "</div>\n" "</body>\n" "</html>\n" )); } }
static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); if (p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<!DOCTYPE html>\n" "<html>\n" "<head>\n" )); if (!buffer_string_is_empty(p->conf.encoding)) { buffer_append_string_len(out, CONST_STR_LEN("<meta charset=\"")); buffer_append_string_buffer(out, p->conf.encoding); buffer_append_string_len(out, CONST_STR_LEN("\">\n")); } buffer_append_string_len(out, CONST_STR_LEN("<title>Index of ")); buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</title>\n")); if (!buffer_string_is_empty(p->conf.external_css)) { buffer_append_string_len(out, CONST_STR_LEN("<meta name=\"viewport\" content=\"initial-scale=1\">")); buffer_append_string_len(out, CONST_STR_LEN("<link rel=\"stylesheet\" type=\"text/css\" href=\"")); buffer_append_string_buffer(out, p->conf.external_css); buffer_append_string_len(out, CONST_STR_LEN("\">\n")); } else { buffer_append_string_len(out, CONST_STR_LEN( "<style type=\"text/css\">\n" "a, a:active {text-decoration: none; color: blue;}\n" "a:visited {color: #48468F;}\n" "a:hover, a:focus {text-decoration: underline; color: red;}\n" "body {background-color: #F5F5F5;}\n" "h2 {margin-bottom: 12px;}\n" "table {margin-left: 12px;}\n" "th, td {" " font: 90% monospace;" " text-align: left;" "}\n" "th {" " font-weight: bold;" " padding-right: 14px;" " padding-bottom: 3px;" "}\n" "td {padding-right: 14px;}\n" "td.s, th.s {text-align: right;}\n" "div.list {" " background-color: white;" " border-top: 1px solid #646464;" " border-bottom: 1px solid #646464;" " padding-top: 10px;" " padding-bottom: 14px;" "}\n" "div.foot {" " font: 90% monospace;" " color: #787878;" " padding-top: 4px;" "}\n" "</style>\n" )); } buffer_append_string_len(out, CONST_STR_LEN("</head>\n<body>\n")); } if (!buffer_string_is_empty(p->conf.show_header)) { /* if we have a HEADER file, display it in <pre class="header"></pre> */ buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_slash(p->tmp_buf); buffer_append_string_buffer(p->tmp_buf, p->conf.show_header); http_list_directory_include_file(out, p->tmp_buf, "header", p->conf.encode_header); } buffer_append_string_len(out, CONST_STR_LEN("<h2>Index of ")); buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN( "</h2>\n" "<div class=\"list\">\n" "<table summary=\"Directory Listing\" cellpadding=\"0\" cellspacing=\"0\">\n" "<thead>" "<tr>" "<th class=\"n\">Name</th>" "<th class=\"m\">Last Modified</th>" "<th class=\"s\">Size</th>" "<th class=\"t\">Type</th>" "</tr>" "</thead>\n" "<tbody>\n" "<tr class=\"d\">" "<td class=\"n\"><a href=\"../\">..</a>/</td>" "<td class=\"m\"> </td>" "<td class=\"s\">- </td>" "<td class=\"t\">Directory</td>" "</tr>\n" )); }
static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); if (p->conf.auto_layout) { buffer_append_string_len(out, CONST_STR_LEN( "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n" "<head>\n" "<title>Index of " )); buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</title>\n")); if (!buffer_string_is_empty(p->conf.external_css)) { buffer_append_string_len(out, CONST_STR_LEN("<link rel=\"stylesheet\" type=\"text/css\" href=\"")); buffer_append_string_buffer(out, p->conf.external_css); buffer_append_string_len(out, CONST_STR_LEN("\" />\n")); } else { buffer_append_string_len(out, CONST_STR_LEN( "<style type=\"text/css\">\n" "a, a:active {text-decoration: none; color: blue;}\n" "a:visited {color: #48468F;}\n" "a:hover, a:focus {text-decoration: underline; color: red;}\n" "body {background-color: #F5F5F5;}\n" "h2 {margin-bottom: 12px;}\n" "table {margin-left: 12px;}\n" "th, td {" " font: 90% monospace;" " text-align: left;" "}\n" "th {" " font-weight: bold;" " padding-right: 14px;" " padding-bottom: 3px;" "}\n" "td {padding-right: 14px;}\n" "td.s, th.s {text-align: right;}\n" "div.list {" " background-color: white;" " border-top: 1px solid #646464;" " border-bottom: 1px solid #646464;" " padding-top: 10px;" " padding-bottom: 14px;" "}\n" "div.foot {" " font: 90% monospace;" " color: #787878;" " padding-top: 4px;" "}\n" "</style>\n" )); } buffer_append_string_len(out, CONST_STR_LEN("</head>\n<body>\n")); } /* HEADER.txt */ if (p->conf.show_header) { stream s; /* if we have a HEADER file, display it in <pre class="header"></pre> */ buffer_copy_buffer(p->tmp_buf, con->physical.path); buffer_append_slash(p->tmp_buf); buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("HEADER.txt")); if (-1 != stream_open(&s, p->tmp_buf)) { if (p->conf.encode_header) { buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"header\">")); buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN("</pre>")); } else { buffer_append_string_len(out, s.start, s.size); } } stream_close(&s); } buffer_append_string_len(out, CONST_STR_LEN("<h2>Index of ")); buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML); buffer_append_string_len(out, CONST_STR_LEN( "</h2>\n" "<div class=\"list\">\n" "<table summary=\"Directory Listing\" cellpadding=\"0\" cellspacing=\"0\">\n" "<thead>" "<tr>" "<th class=\"n\">Name</th>" "<th class=\"m\">Last Modified</th>" "<th class=\"s\">Size</th>" "<th class=\"t\">Type</th>" "</tr>" "</thead>\n" "<tbody>\n" "<tr>" "<td class=\"n\"><a href=\"../\">Parent Directory</a>/</td>" "<td class=\"m\"> </td>" "<td class=\"s\">- </td>" "<td class=\"t\">Directory</td>" "</tr>\n" )); }
handler_t http_response_prepare(server *srv, connection *con) { handler_t r; /* looks like someone has already done a decision */ 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 && buffer_is_empty(con->physical.path)) { 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 * 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 * * */ config_cond_cache_reset(srv, con); config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */ 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 (secure) * - uri.query * */ /** * Name according to RFC 2396 * * - scheme * - authority * - path * - query * * (scheme)://(authority)(path)?(query)#fragment * * */ /* initial scheme value. can be overwritten for example by mod_extforward later */ if (con->srv_socket->is_ssl) { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https")); } else { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http")); } buffer_copy_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */ config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */ config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */ config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */ config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent: */ config_patch_connection(srv, con, COMP_HTTP_LANGUAGE); /* Accept-Language: */ config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */ config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */ /** their might be a fragment which has to be cut away */ if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { buffer_string_set_length(con->request.uri, qstr - con->request.uri->ptr); } /** extract query string from request.uri */ if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) { buffer_copy_string (con->uri.query, qstr + 1); buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr); } else { buffer_reset (con->uri.query); buffer_copy_buffer(con->uri.path_raw, con->request.uri); } /* decode url to path * * - 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 * ... */ buffer_copy_buffer(con->uri.path, con->uri.path_raw); } else { buffer_copy_buffer(srv->tmp_buf, con->uri.path_raw); buffer_urldecode_path(srv->tmp_buf); buffer_path_simplify(con->uri.path, srv->tmp_buf); } config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */ config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */ #ifdef USE_OPENSSL if (con->srv_socket->is_ssl && con->conf.ssl_verifyclient) { https_add_ssl_entries(con); } #endif /* do we have to downgrade to 1.0 ? */ if (!con->conf.allow_http11) { con->request.http_version = HTTP_VERSION_1_0; } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- splitting Request-URI"); log_error_write(srv, __FILE__, __LINE__, "sb", "Request-URI : ", con->request.uri); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-scheme : ", con->uri.scheme); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-authority : ", con->uri.authority); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (raw) : ", con->uri.path_raw); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (clean): ", con->uri.path); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query); } /** * * call plugins * * - based on the raw URL * */ switch(r = plugins_call_handle_uri_raw(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r); break; } /** * * call plugins * * - based on the clean URL * */ switch(r = plugins_call_handle_uri_clean(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: 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; con->file_finished = 1; return HANDLER_FINISHED; } /*** * * border * * logical filename (URI) becomes a physical filename here * * * */ /* 1. stat() * ... ISREG() -> ok, go on * ... ISDIR() -> index-file -> redirect * * 2. pathinfo() * ... ISREG() * * 3. -> 404 * */ /* * SEARCH DOCUMENT ROOT */ /* set a default */ buffer_copy_buffer(con->physical.doc_root, con->conf.document_root); buffer_copy_buffer(con->physical.rel_path, con->uri.path); #if defined(__WIN32) || defined(__CYGWIN__) /* strip dots from the end and spaces * * windows/dos handle those filenames as the same file * * foo == foo. == foo..... == "foo... " == "foo.. ./" * * This will affect in some cases PATHINFO * * on native windows we could prepend the filename with \\?\ to circumvent * this behaviour. I have no idea how to push this through cygwin * * */ if (con->physical.rel_path->used > 1) { buffer *b = con->physical.rel_path; size_t len = buffer_string_length(b); size_t i; /* strip trailing " /" or "./" once */ if (len > 1 && b->ptr[len - 1] == '/' && (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) { len -= 2; } /* strip all trailing " " and "." */ while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len; buffer_string_set_length(b, len); } #endif if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } /* the docroot plugin should set the doc_root and might also set the physical.path * for us (all vhost-plugins are supposed to set the doc_root) * */ switch(r = plugins_call_handle_docroot(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: log_error_write(srv, __FILE__, __LINE__, ""); break; } /* MacOS X and Windows can't distiguish between upper and lower-case * * convert to lower-case */ if (con->conf.force_lowercase_filenames) { buffer_to_lower(con->physical.rel_path); } /* the docroot plugins might set the servername, if they don't we take http-host */ if (buffer_string_is_empty(con->server_name)) { buffer_copy_buffer(con->server_name, con->uri.authority); } /** * create physical filename * -> physical.path = docroot + rel_path * */ buffer_copy_buffer(con->physical.basedir, con->physical.doc_root); buffer_copy_buffer(con->physical.path, con->physical.doc_root); buffer_append_slash(con->physical.path); if (!buffer_string_is_empty(con->physical.rel_path) && con->physical.rel_path->ptr[0] == '/') { buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, buffer_string_length(con->physical.rel_path) - 1); } else { buffer_append_string_buffer(con->physical.path, con->physical.rel_path); } if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } switch(r = plugins_call_handle_physical(srv, con)) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: case HANDLER_COMEBACK: case HANDLER_WAIT_FOR_EVENT: case HANDLER_ERROR: return r; default: 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); log_error_write(srv, __FILE__, __LINE__, "sb", "Basedir :", con->physical.basedir); log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); 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); } 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); } #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; }; #endif if (S_ISDIR(sce->st.st_mode)) { if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') { /* redirect to .../ */ http_response_redirect_to_directory(srv, con); return HANDLER_FINISHED; } #ifdef HAVE_LSTAT } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) { #else } else if (!S_ISREG(sce->st.st_mode)) { #endif /* any special handling of non-reg files ?*/ } } else { 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 ENAMETOOLONG: /* file name to be read was too long. return 404 */ case ENOENT: con->http_status = 404; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file not found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENOTDIR: /* PATH_INFO ! :) */ break; default: /* 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_buffer(srv->tmp_buf, con->physical.path); do { if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_buffer(con->physical.path, srv->tmp_buf); } if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { found = S_ISREG(sce->st.st_mode); 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) && ((size_t)(slash - srv->tmp_buf->ptr) > (buffer_string_length(con->physical.basedir) - 1))); 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; } #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } buffer_reset(con->physical.path); return HANDLER_FINISHED; }; #endif /* we have a PATHINFO */ if (pathinfo) { buffer_copy_string(con->request.pathinfo, pathinfo); /* * shorten uri.path */ buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - strlen(pathinfo)); } 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); log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); 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: /* request was not handled */ break; case HANDLER_FINISHED: default: 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 == 0) { switch (con->request.http_method) { case HTTP_METHOD_OPTIONS: con->http_status = 200; break; default: 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 */ return HANDLER_FINISHED; case HANDLER_FINISHED: /* request is finished */ default: /* something strange happend */ return r; } /* can't happen */ return HANDLER_COMEBACK; }
static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; size_t i; array *parsed_host; register char *ptr; int not_good = 0; stat_cache_entry *sce = NULL; /* not authority set */ if (buffer_string_is_empty(con->uri.authority)) return HANDLER_GO_ON; mod_evhost_patch_connection(srv, con, p); /* missing even default(global) conf */ if (0 == p->conf.len) { return HANDLER_GO_ON; } parsed_host = array_init(); mod_evhost_parse_host(con, parsed_host); /* build document-root */ buffer_reset(p->tmp_buf); for (i = 0; i < p->conf.len; i++) { ptr = p->conf.path_pieces[i]->ptr; if (*ptr == '%') { data_string *ds; if (*(ptr+1) == '%') { /* %% */ buffer_append_string_len(p->tmp_buf,CONST_STR_LEN("%")); } else if (*(ptr+1) == '_' ) { /* %_ == full hostname */ char *colon = strchr(con->uri.authority->ptr, ':'); if(colon == NULL) { buffer_append_string_buffer(p->tmp_buf, con->uri.authority); /* adds fqdn */ } else { /* strip the port out of the authority-part of the URI scheme */ buffer_append_string_len(p->tmp_buf, con->uri.authority->ptr, colon - con->uri.authority->ptr); /* adds fqdn */ } } else if (NULL != (ds = (data_string *)array_get_element(parsed_host,p->conf.path_pieces[i]->ptr))) { buffer_append_string_buffer(p->tmp_buf,ds->value); } else { /* unhandled %-sequence */ } } else { buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]); } } buffer_append_slash(p->tmp_buf); array_free(parsed_host); if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf); not_good = 1; } else if(!S_ISDIR(sce->st.st_mode)) { log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf); not_good = 1; } if (!not_good) { buffer_copy_buffer(con->physical.doc_root, p->tmp_buf); } return HANDLER_GO_ON; }