[core] code cleanup: separate physical path sub
code cleanup: separate subroutine to check physical path
This commit is contained in:
parent
d5f37803dd
commit
a5a2654bd4
337
src/response.c
337
src/response.c
|
@ -128,6 +128,142 @@ int http_response_write_header(server *srv, connection *con) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static handler_t http_response_physical_path_check(server *srv, connection *con) {
|
||||
stat_cache_entry *sce = NULL;
|
||||
|
||||
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
|
||||
/* file exists */
|
||||
} else {
|
||||
char *pathinfo = NULL;
|
||||
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 */
|
||||
|
||||
{
|
||||
/*(might check at startup that s->document_root does not end in '/')*/
|
||||
size_t len = buffer_string_length(con->physical.basedir);
|
||||
if (len > 0 && '/' == con->physical.basedir->ptr[len-1]) --len;
|
||||
pathinfo = con->physical.path->ptr + len;
|
||||
if ('/' != *pathinfo) pathinfo = NULL;
|
||||
}
|
||||
|
||||
for (; pathinfo; pathinfo = strchr(pathinfo+1, '/')) {
|
||||
handler_t rc;
|
||||
*pathinfo = '\0';
|
||||
rc = stat_cache_get_entry(srv, con, con->physical.path, &sce);
|
||||
*pathinfo = '/';
|
||||
if (HANDLER_ERROR == rc) { pathinfo = NULL; break; }
|
||||
if (!S_ISDIR(sce->st.st_mode)) break;
|
||||
}
|
||||
|
||||
if (NULL == pathinfo || !S_ISREG(sce->st.st_mode)) {
|
||||
/* 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) {
|
||||
size_t len = strlen(pathinfo), reqlen;
|
||||
if (con->conf.force_lowercase_filenames
|
||||
&& len <= (reqlen = buffer_string_length(con->request.uri))
|
||||
&& 0 == strncasecmp(con->request.uri->ptr + reqlen - len, pathinfo, len)) {
|
||||
/* attempt to preserve case-insensitive PATH_INFO
|
||||
* (works in common case where mod_alias, mod_magnet, and other modules
|
||||
* have not modified the PATH_INFO portion of request URI, or did so
|
||||
* with exactly the PATH_INFO desired) */
|
||||
buffer_copy_string_len(con->request.pathinfo, con->request.uri->ptr + reqlen - len, len);
|
||||
} else {
|
||||
buffer_copy_string_len(con->request.pathinfo, pathinfo, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* shorten uri.path
|
||||
*/
|
||||
|
||||
buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - len);
|
||||
buffer_string_set_length(con->physical.path, (size_t)(pathinfo - con->physical.path->ptr));
|
||||
}
|
||||
}
|
||||
|
||||
#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 ?*/
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
handler_t http_response_prepare(server *srv, connection *con) {
|
||||
handler_t r;
|
||||
|
||||
|
@ -481,220 +617,39 @@ handler_t http_response_prepare(server *srv, connection *con) {
|
|||
*/
|
||||
|
||||
if (con->mode == DIRECT) {
|
||||
char *pathinfo = NULL;
|
||||
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 */
|
||||
|
||||
{
|
||||
/*(might check at startup that s->document_root does not end in '/')*/
|
||||
size_t len = buffer_string_length(con->physical.basedir);
|
||||
if (len > 0 && '/' == con->physical.basedir->ptr[len-1]) --len;
|
||||
pathinfo = con->physical.path->ptr + len;
|
||||
if ('/' != *pathinfo) pathinfo = NULL;
|
||||
}
|
||||
|
||||
for (; pathinfo; pathinfo = strchr(pathinfo+1, '/')) {
|
||||
handler_t rc;
|
||||
*pathinfo = '\0';
|
||||
rc = stat_cache_get_entry(srv, con, con->physical.path, &sce);
|
||||
*pathinfo = '/';
|
||||
if (HANDLER_ERROR == rc) { pathinfo = NULL; break; }
|
||||
if (!S_ISDIR(sce->st.st_mode)) break;
|
||||
}
|
||||
|
||||
if (NULL == pathinfo || !S_ISREG(sce->st.st_mode)) {
|
||||
/* 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) {
|
||||
size_t len = strlen(pathinfo), reqlen;
|
||||
if (con->conf.force_lowercase_filenames
|
||||
&& len <= (reqlen = buffer_string_length(con->request.uri))
|
||||
&& 0 == strncasecmp(con->request.uri->ptr + reqlen - len, pathinfo, len)) {
|
||||
/* attempt to preserve case-insensitive PATH_INFO
|
||||
* (works in common case where mod_alias, mod_magnet, and other modules
|
||||
* have not modified the PATH_INFO portion of request URI, or did so
|
||||
* with exactly the PATH_INFO desired) */
|
||||
buffer_copy_string_len(con->request.pathinfo, con->request.uri->ptr + reqlen - len, len);
|
||||
} else {
|
||||
buffer_copy_string_len(con->request.pathinfo, pathinfo, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* shorten uri.path
|
||||
*/
|
||||
|
||||
buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - len);
|
||||
buffer_string_set_length(con->physical.path, (size_t)(pathinfo - con->physical.path->ptr));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
r = http_response_physical_path_check(srv, con);
|
||||
if (HANDLER_GO_ON != r) return r;
|
||||
|
||||
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);
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
|
||||
}
|
||||
|
||||
/* 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:
|
||||
r = plugins_call_handle_subrequest_start(srv, con);
|
||||
if (HANDLER_GO_ON != r) {
|
||||
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;
|
||||
}
|
||||
|
||||
con->http_status = (con->request.http_method != HTTP_METHOD_OPTIONS) ? 403 : 200;
|
||||
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;
|
||||
r = plugins_call_handle_subrequest(srv, con);
|
||||
if (HANDLER_GO_ON == r) r = HANDLER_FINISHED; /* request was not handled, looks like we are done */
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue