* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
+
#define _BSD_SOURCE
#define _DARWIN_C_SOURCE
#define _XOPEN_SOURCE 700
struct dispatch_handler *d;
struct client *cl;
struct path_info pi;
+ char *url;
bool called, path;
};
{
static char path_phys[PATH_MAX];
static char path_info[PATH_MAX];
+ static char path_query[PATH_MAX];
static struct path_info p;
const char *docroot = conf.docroot;
/* separate query string from url */
if ((pathptr = strchr(url, '?')) != NULL) {
- p.query = pathptr[1] ? pathptr + 1 : NULL;
+ if (pathptr[1]) {
+ p.query = path_query;
+ snprintf(path_query, sizeof(path_query), "%s",
+ pathptr + 1);
+ }
/* urldecode component w/o query */
if (pathptr > url) {
return uh_file_response_ok_hdrs(cl, s);
}
+static void uh_file_response_405(struct client *cl)
+{
+ uh_http_header(cl, 405, "Method Not Allowed");
+}
+
static void uh_file_response_412(struct client *cl)
{
uh_http_header(cl, 412, "Precondition Failed");
const char *type = "directory";
unsigned int mode = S_IXOTH;
struct stat s;
+ char *escaped;
char *file;
char buf[128];
int i;
if (!(s.st_mode & mode))
goto next;
+ escaped = uh_htmlescape(name);
+
+ if (!escaped)
+ goto next;
+
uh_chunk_printf(cl,
"<li><strong><a href='%s%s%s'>%s</a>%s"
"</strong><br /><small>modified: %s"
"<br />%s - %.02f kbyte<br />"
"<br /></small></li>",
- path, name, suffix,
- name, suffix,
+ path, escaped, suffix,
+ escaped, suffix,
uh_file_unix2date(s.st_mtime, buf, sizeof(buf)),
type, s.st_size / 1024.0);
+ free(escaped);
*file = 0;
next:
free(files[i]);
static void uh_file_dirlist(struct client *cl, struct path_info *pi)
{
struct dirent **files = NULL;
+ char *escaped_path = uh_htmlescape(pi->name);
int count = 0;
+ if (!escaped_path)
+ {
+ uh_client_error(cl, 500, "Internal Server Error", "Out of memory");
+ return;
+ }
+
uh_file_response_200(cl, NULL);
- ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n");
+ ustream_printf(cl->us, "Content-Type: text/html; charset=%s\r\n\r\n",
+ conf.dirlist_charset ? conf.dirlist_charset : "UTF-8");
uh_chunk_printf(cl,
"<html><head><title>Index of %s</title></head>"
"<body><h1>Index of %s</h1><hr /><ol>",
- pi->name, pi->name);
+ escaped_path, escaped_path);
count = scandir(pi->phys, &files, NULL, dirent_cmp);
if (count > 0) {
strcpy(uh_buf, pi->phys);
- list_entries(cl, files, count, pi->name, uh_buf);
+ list_entries(cl, files, count, escaped_path, uh_buf);
}
+ free(escaped_path);
free(files);
uh_chunk_printf(cl, "</ol><hr /></body></html>");
file_write_cb(cl);
}
-static bool __handle_file_request(struct client *cl, char *url);
+static bool __handle_file_request(struct client *cl, char *url, bool is_error_handler);
static void uh_file_request(struct client *cl, const char *url,
struct path_info *pi, struct blob_attr **tb)
{
int fd;
struct http_request *req = &cl->request;
- char *error_handler;
+ char *error_handler, *escaped_url;
+
+ switch (cl->request.method) {
+ case UH_HTTP_MSG_GET:
+ case UH_HTTP_MSG_POST:
+ case UH_HTTP_MSG_HEAD:
+ case UH_HTTP_MSG_OPTIONS:
+ break;
+
+ default:
+ uh_file_response_405(cl);
+ ustream_printf(cl->us, "\r\n");
+ uh_request_done(cl);
+ return;
+ }
if (!(pi->stat.st_mode & S_IROTH))
goto error;
req->redirect_status = 403;
error_handler = alloca(strlen(conf.error_handler) + 1);
strcpy(error_handler, conf.error_handler);
- if (__handle_file_request(cl, error_handler))
+ if (__handle_file_request(cl, error_handler, true))
return;
}
+ escaped_url = uh_htmlescape(url);
+
uh_client_error(cl, 403, "Forbidden",
"You don't have permission to access %s on this server.",
- url);
+ escaped_url ? escaped_url : "the url");
+
+ if (escaped_url)
+ free(escaped_url);
}
void uh_dispatch_add(struct dispatch_handler *d)
}
static void
-uh_invoke_script(struct client *cl, struct dispatch_handler *d, struct path_info *pi)
+uh_invoke_script(struct client *cl, struct dispatch_handler *d, char *url, struct path_info *pi)
{
- char *url = blobmsg_data(blob_data(cl->hdr.head));
-
n_requests++;
d->handle_request(cl, url, pi);
}
cl = dr->cl;
dr->called = true;
cl->dispatch.data_blocked = false;
- uh_invoke_script(cl, dr->d, dr->path ? &dr->pi : NULL);
+ uh_invoke_script(cl, dr->d, dr->url, dr->path ? &dr->pi : NULL);
client_poll_post_data(cl);
+ ustream_poll(cl->us);
}
}
_field(query)
static void
-uh_defer_script(struct client *cl, struct dispatch_handler *d, struct path_info *pi)
+uh_defer_script(struct client *cl, struct dispatch_handler *d, char *url, struct path_info *pi)
{
struct deferred_request *dr;
- char *_root, *_phys, *_name, *_info, *_query;
+ char *_url, *_root, *_phys, *_name, *_info, *_query;
cl->dispatch.req_free = uh_free_pending_request;
/* allocate enough memory to duplicate all path_info strings in one block */
#undef _field
#define _field(_name) &_##_name, field_len(pi->_name),
- dr = calloc_a(sizeof(*dr), path_info_fields NULL);
+ dr = calloc_a(sizeof(*dr), &_url, strlen(url) + 1, path_info_fields NULL);
memcpy(&dr->pi, pi, sizeof(*pi));
dr->path = true;
#define _field(_name) if (pi->_name) dr->pi._name = strcpy(_##_name, pi->_name);
path_info_fields
} else {
- dr = calloc(1, sizeof(*dr));
+ dr = calloc_a(sizeof(*dr), &_url, strlen(url) + 1, NULL);
}
cl->dispatch.req_data = dr;
cl->dispatch.data_blocked = true;
+ dr->url = strcpy(_url, url);
dr->cl = cl;
dr->d = d;
list_add(&dr->list, &pending_requests);
return d->handle_request(cl, url, pi);
if (n_requests >= conf.max_script_requests)
- return uh_defer_script(cl, d, pi);
+ return uh_defer_script(cl, d, url, pi);
cl->dispatch.req_free = uh_complete_request;
- uh_invoke_script(cl, d, pi);
+ uh_invoke_script(cl, d, url, pi);
}
-static bool __handle_file_request(struct client *cl, char *url)
+static bool __handle_file_request(struct client *cl, char *url, bool is_error_handler)
{
static const struct blobmsg_policy hdr_policy[__HDR_MAX] = {
[HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING },
struct dispatch_handler *d;
struct blob_attr *tb[__HDR_MAX];
struct path_info *pi;
- char *user, *pass;
+ char *user, *pass, *auth;
+
+ if (is_error_handler) {
+ d = dispatch_find(url, NULL);
+
+ if (d) {
+ uh_invoke_handler(cl, d, url, NULL);
+
+ return true;
+ }
+ }
pi = uh_path_lookup(cl, url);
if (!pi)
return true;
blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head));
- if (tb[HDR_AUTHORIZATION]) {
- if (!uh_auth_check(cl, pi->name, blobmsg_data(tb[HDR_AUTHORIZATION]), &user, &pass))
- return true;
- if (user && pass) {
- blobmsg_add_string(&cl->hdr, "http-auth-user", user);
- blobmsg_add_string(&cl->hdr, "http-auth-pass", pass);
- }
+ auth = tb[HDR_AUTHORIZATION] ? blobmsg_data(tb[HDR_AUTHORIZATION]) : NULL;
+
+ if (!uh_auth_check(cl, pi->name, auth, &user, &pass))
+ return true;
+
+ if (user && pass) {
+ blobmsg_add_string(&cl->hdr, "http-auth-user", user);
+ blobmsg_add_string(&cl->hdr, "http-auth-pass", pass);
}
d = dispatch_find(url, pi);
struct http_request *req = &cl->request;
struct dispatch_handler *d;
char *url = blobmsg_data(blob_data(cl->hdr.head));
- char *error_handler;
+ char *error_handler, *escaped_url;
blob_buf_init(&cl->hdr_response, 0);
url = uh_handle_alias(url);
if (d)
return uh_invoke_handler(cl, d, url, NULL);
- if (__handle_file_request(cl, url))
+ if (__handle_file_request(cl, url, false))
return;
if (uh_handler_run(cl, &url, true)) {
return;
uh_handler_run(cl, &url, false);
- if (__handle_file_request(cl, url))
+ if (__handle_file_request(cl, url, false))
return;
}
if (conf.error_handler) {
error_handler = alloca(strlen(conf.error_handler) + 1);
strcpy(error_handler, conf.error_handler);
- if (__handle_file_request(cl, error_handler))
+ if (__handle_file_request(cl, error_handler, true))
return;
}
- uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.", url);
+ escaped_url = uh_htmlescape(url);
+
+ uh_client_error(cl, 404, "Not Found", "The requested URL %s was not found on this server.",
+ escaped_url ? escaped_url : "");
+
+ if (escaped_url)
+ free(escaped_url);
}