All Tabs indent to Spaces

Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
main
Jianhui Zhao 2017-12-30 11:40:37 +08:00
parent 3aa5d2aeed
commit 2ab4ebc2f0
10 changed files with 446 additions and 446 deletions

View File

@ -27,8 +27,8 @@
typedef void (*action_cb_t)(struct uh_client *cl); typedef void (*action_cb_t)(struct uh_client *cl);
struct uh_action { struct uh_action {
struct avl_node avl; struct avl_node avl;
char path[PATH_MAX]; char path[PATH_MAX];
action_cb_t cb; action_cb_t cb;
}; };

View File

@ -22,15 +22,15 @@
#include "uh_ssl.h" #include "uh_ssl.h"
const char *const http_versions[] = { const char *const http_versions[] = {
[UH_HTTP_VER_0_9] = "HTTP/0.9", [UH_HTTP_VER_0_9] = "HTTP/0.9",
[UH_HTTP_VER_1_0] = "HTTP/1.0", [UH_HTTP_VER_1_0] = "HTTP/1.0",
[UH_HTTP_VER_1_1] = "HTTP/1.1" [UH_HTTP_VER_1_1] = "HTTP/1.1"
}; };
const char *const http_methods[] = { const char *const http_methods[] = {
[UH_HTTP_MSG_GET] = "GET", [UH_HTTP_MSG_GET] = "GET",
[UH_HTTP_MSG_POST] = "POST", [UH_HTTP_MSG_POST] = "POST",
[UH_HTTP_MSG_HEAD] = "HEAD" [UH_HTTP_MSG_HEAD] = "HEAD"
}; };
static inline void client_send(struct uh_client *cl, const void *data, int len) static inline void client_send(struct uh_client *cl, const void *data, int len)
@ -120,34 +120,34 @@ static void uh_handle_request(struct uh_client *cl)
return; return;
if (handle_file_request(cl, path)) if (handle_file_request(cl, path))
return; return;
if (cl->srv->error404_cb) { if (cl->srv->error404_cb) {
cl->srv->error404_cb(cl); cl->srv->error404_cb(cl);
return; return;
} }
cl->send_error(cl, 404, "Not Found", "The requested PATH %s was not found on this server.", path); cl->send_error(cl, 404, "Not Found", "The requested PATH %s was not found on this server.", path);
} }
static inline void connection_close(struct uh_client *cl) static inline void connection_close(struct uh_client *cl)
{ {
cl->us->eof = true; cl->us->eof = true;
cl->state = CLIENT_STATE_CLOSE; cl->state = CLIENT_STATE_CLOSE;
ustream_state_change(cl->us); ustream_state_change(cl->us);
} }
static inline void keepalive_cb(struct uloop_timeout *timeout) static inline void keepalive_cb(struct uloop_timeout *timeout)
{ {
struct uh_client *cl = container_of(timeout, struct uh_client, timeout); struct uh_client *cl = container_of(timeout, struct uh_client, timeout);
connection_close(cl); connection_close(cl);
} }
static void dispatch_done(struct uh_client *cl) static void dispatch_done(struct uh_client *cl)
{ {
if (cl->dispatch.free) if (cl->dispatch.free)
cl->dispatch.free(cl); cl->dispatch.free(cl);
} }
static inline int hdr_get_len(struct kvlist *kv, const void *data) static inline int hdr_get_len(struct kvlist *kv, const void *data)
@ -157,13 +157,13 @@ static inline int hdr_get_len(struct kvlist *kv, const void *data)
static void client_request_done(struct uh_client *cl) static void client_request_done(struct uh_client *cl)
{ {
if (cl->response_length < 0) if (cl->response_length < 0)
cl->printf(cl, "0\r\n\r\n"); cl->printf(cl, "0\r\n\r\n");
dispatch_done(cl); dispatch_done(cl);
if (cl->connection_close) { if (cl->connection_close) {
connection_close(cl); connection_close(cl);
return; return;
} }
@ -250,7 +250,7 @@ static bool client_init_cb(struct uh_client *cl, char *buf, int len)
return true; return true;
} }
*newline = 0; *newline = 0;
cl->state = client_parse_request(cl, buf); cl->state = client_parse_request(cl, buf);
ustream_consume(cl->us, newline + 2 - buf); ustream_consume(cl->us, newline + 2 - buf);
@ -349,7 +349,7 @@ static void client_parse_header(struct uh_client *cl, char *data)
static bool client_header_cb(struct uh_client *cl, char *buf, int len) static bool client_header_cb(struct uh_client *cl, char *buf, int len)
{ {
char *newline; char *newline;
int line_len; int line_len;
newline = strstr(buf, "\r\n"); newline = strstr(buf, "\r\n");
@ -368,9 +368,9 @@ static bool client_header_cb(struct uh_client *cl, char *buf, int len)
typedef bool (*read_cb_t)(struct uh_client *cl, char *buf, int len); typedef bool (*read_cb_t)(struct uh_client *cl, char *buf, int len);
static read_cb_t read_cbs[] = { static read_cb_t read_cbs[] = {
[CLIENT_STATE_INIT] = client_init_cb, [CLIENT_STATE_INIT] = client_init_cb,
[CLIENT_STATE_HEADER] = client_header_cb, [CLIENT_STATE_HEADER] = client_header_cb,
[CLIENT_STATE_DATA] = client_data_cb, [CLIENT_STATE_DATA] = client_data_cb,
}; };
void uh_client_read_cb(struct uh_client *cl) void uh_client_read_cb(struct uh_client *cl)
@ -426,7 +426,7 @@ void uh_client_notify_state(struct uh_client *cl)
static void client_notify_state(struct ustream *s) static void client_notify_state(struct ustream *s)
{ {
struct uh_client *cl = container_of(s, struct uh_client, sfd.stream); struct uh_client *cl = container_of(s, struct uh_client, sfd.stream);
uh_client_notify_state(cl); uh_client_notify_state(cl);
} }
@ -434,15 +434,15 @@ static void client_notify_state(struct ustream *s)
void uh_accept_client(struct uh_server *srv, bool ssl) void uh_accept_client(struct uh_server *srv, bool ssl)
{ {
struct uh_client *cl; struct uh_client *cl;
unsigned int sl; unsigned int sl;
int sfd; int sfd;
struct sockaddr_in addr; struct sockaddr_in addr;
sl = sizeof(addr); sl = sizeof(addr);
sfd = accept(srv->fd.fd, (struct sockaddr *)&addr, &sl); sfd = accept(srv->fd.fd, (struct sockaddr *)&addr, &sl);
if (sfd < 0) { if (sfd < 0) {
uh_log_err("accept"); uh_log_err("accept");
return; return;
} }
cl = calloc(1, sizeof(struct uh_client)); cl = calloc(1, sizeof(struct uh_client));

View File

@ -27,22 +27,22 @@
#define UHTTPD_CONNECTION_TIMEOUT 30 #define UHTTPD_CONNECTION_TIMEOUT 30
enum http_method { enum http_method {
UH_HTTP_MSG_GET, UH_HTTP_MSG_GET,
UH_HTTP_MSG_POST, UH_HTTP_MSG_POST,
UH_HTTP_MSG_HEAD UH_HTTP_MSG_HEAD
}; };
enum http_version { enum http_version {
UH_HTTP_VER_0_9, UH_HTTP_VER_0_9,
UH_HTTP_VER_1_0, UH_HTTP_VER_1_0,
UH_HTTP_VER_1_1 UH_HTTP_VER_1_1
}; };
enum client_state { enum client_state {
CLIENT_STATE_INIT, CLIENT_STATE_INIT,
CLIENT_STATE_HEADER, CLIENT_STATE_HEADER,
CLIENT_STATE_DATA, CLIENT_STATE_DATA,
CLIENT_STATE_DONE, CLIENT_STATE_DONE,
CLIENT_STATE_CLOSE CLIENT_STATE_CLOSE
}; };
@ -74,16 +74,16 @@ struct dispatch {
}; };
struct uh_client { struct uh_client {
struct list_head list; struct list_head list;
struct uh_server *srv; struct uh_server *srv;
struct ustream *us; struct ustream *us;
struct ustream_fd sfd; struct ustream_fd sfd;
#if (UHTTPD_SSL_SUPPORT) #if (UHTTPD_SSL_SUPPORT)
struct ustream_ssl ssl; struct ustream_ssl ssl;
#endif #endif
struct uloop_timeout timeout; struct uloop_timeout timeout;
enum client_state state; enum client_state state;
struct http_request request; struct http_request request;
struct sockaddr_in peer_addr; struct sockaddr_in peer_addr;
struct dispatch dispatch; struct dispatch dispatch;
bool connection_close; bool connection_close;

View File

@ -22,117 +22,117 @@
#include "uhttpd.h" #include "uhttpd.h"
static const struct mimetype uh_mime_types[] = { static const struct mimetype uh_mime_types[] = {
{ "txt", "text/plain" }, { "txt", "text/plain" },
{ "log", "text/plain" }, { "log", "text/plain" },
{ "js", "text/javascript" }, { "js", "text/javascript" },
{ "css", "text/css" }, { "css", "text/css" },
{ "htm", "text/html" }, { "htm", "text/html" },
{ "html", "text/html" }, { "html", "text/html" },
{ "diff", "text/x-patch" }, { "diff", "text/x-patch" },
{ "patch", "text/x-patch" }, { "patch", "text/x-patch" },
{ "c", "text/x-csrc" }, { "c", "text/x-csrc" },
{ "h", "text/x-chdr" }, { "h", "text/x-chdr" },
{ "o", "text/x-object" }, { "o", "text/x-object" },
{ "ko", "text/x-object" }, { "ko", "text/x-object" },
{ "bmp", "image/bmp" }, { "bmp", "image/bmp" },
{ "gif", "image/gif" }, { "gif", "image/gif" },
{ "png", "image/png" }, { "png", "image/png" },
{ "jpg", "image/jpeg" }, { "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" }, { "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" }, { "svg", "image/svg+xml" },
{ "json", "application/json" }, { "json", "application/json" },
{ "jsonp", "application/javascript" }, { "jsonp", "application/javascript" },
{ "zip", "application/zip" }, { "zip", "application/zip" },
{ "pdf", "application/pdf" }, { "pdf", "application/pdf" },
{ "xml", "application/xml" }, { "xml", "application/xml" },
{ "xsl", "application/xml" }, { "xsl", "application/xml" },
{ "doc", "application/msword" }, { "doc", "application/msword" },
{ "ppt", "application/vnd.ms-powerpoint" }, { "ppt", "application/vnd.ms-powerpoint" },
{ "xls", "application/vnd.ms-excel" }, { "xls", "application/vnd.ms-excel" },
{ "odt", "application/vnd.oasis.opendocument.text" }, { "odt", "application/vnd.oasis.opendocument.text" },
{ "odp", "application/vnd.oasis.opendocument.presentation" }, { "odp", "application/vnd.oasis.opendocument.presentation" },
{ "pl", "application/x-perl" }, { "pl", "application/x-perl" },
{ "sh", "application/x-shellscript" }, { "sh", "application/x-shellscript" },
{ "php", "application/x-php" }, { "php", "application/x-php" },
{ "deb", "application/x-deb" }, { "deb", "application/x-deb" },
{ "iso", "application/x-cd-image" }, { "iso", "application/x-cd-image" },
{ "tar.gz", "application/x-compressed-tar" }, { "tar.gz", "application/x-compressed-tar" },
{ "tgz", "application/x-compressed-tar" }, { "tgz", "application/x-compressed-tar" },
{ "gz", "application/x-gzip" }, { "gz", "application/x-gzip" },
{ "tar.bz2", "application/x-bzip-compressed-tar" }, { "tar.bz2", "application/x-bzip-compressed-tar" },
{ "tbz", "application/x-bzip-compressed-tar" }, { "tbz", "application/x-bzip-compressed-tar" },
{ "bz2", "application/x-bzip" }, { "bz2", "application/x-bzip" },
{ "tar", "application/x-tar" }, { "tar", "application/x-tar" },
{ "rar", "application/x-rar-compressed" }, { "rar", "application/x-rar-compressed" },
{ "mp3", "audio/mpeg" }, { "mp3", "audio/mpeg" },
{ "ogg", "audio/x-vorbis+ogg" }, { "ogg", "audio/x-vorbis+ogg" },
{ "wav", "audio/x-wav" }, { "wav", "audio/x-wav" },
{ "mpg", "video/mpeg" }, { "mpg", "video/mpeg" },
{ "mpeg", "video/mpeg" }, { "mpeg", "video/mpeg" },
{ "avi", "video/x-msvideo" }, { "avi", "video/x-msvideo" },
{ "README", "text/plain" }, { "README", "text/plain" },
{ "log", "text/plain" }, { "log", "text/plain" },
{ "cfg", "text/plain" }, { "cfg", "text/plain" },
{ "conf", "text/plain" }, { "conf", "text/plain" },
{ "pac", "application/x-ns-proxy-autoconfig" }, { "pac", "application/x-ns-proxy-autoconfig" },
{ "wpad.dat", "application/x-ns-proxy-autoconfig" }, { "wpad.dat", "application/x-ns-proxy-autoconfig" },
{ NULL, NULL } { NULL, NULL }
}; };
static char *canonpath(const char *path, char *path_resolved) static char *canonpath(const char *path, char *path_resolved)
{ {
const char *path_cpy = path; const char *path_cpy = path;
char *path_res = path_resolved; char *path_res = path_resolved;
/* normalize */ /* normalize */
while ((*path_cpy != '\0') && (path_cpy < (path + PATH_MAX - 2))) { while ((*path_cpy != '\0') && (path_cpy < (path + PATH_MAX - 2))) {
if (*path_cpy != '/') if (*path_cpy != '/')
goto next; goto next;
/* skip repeating / */ /* skip repeating / */
if (path_cpy[1] == '/') { if (path_cpy[1] == '/') {
path_cpy++; path_cpy++;
continue; continue;
} }
/* /./ or /../ */ /* /./ or /../ */
if (path_cpy[1] == '.') { if (path_cpy[1] == '.') {
/* skip /./ */ /* skip /./ */
if ((path_cpy[2] == '/') || (path_cpy[2] == '\0')) { if ((path_cpy[2] == '/') || (path_cpy[2] == '\0')) {
path_cpy += 2; path_cpy += 2;
continue; continue;
} }
/* collapse /x/../ */ /* collapse /x/../ */
if ((path_cpy[2] == '.') && if ((path_cpy[2] == '.') &&
((path_cpy[3] == '/') || (path_cpy[3] == '\0'))) { ((path_cpy[3] == '/') || (path_cpy[3] == '\0'))) {
while ((path_res > path_resolved) && (*--path_res != '/')); while ((path_res > path_resolved) && (*--path_res != '/'));
path_cpy += 3; path_cpy += 3;
continue; continue;
} }
} }
next: next:
*path_res++ = *path_cpy++; *path_res++ = *path_cpy++;
} }
/* remove trailing slash if not root / */ /* remove trailing slash if not root / */
if ((path_res > (path_resolved+1)) && (path_res[-1] == '/')) if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
path_res--; path_res--;
else if (path_res == path_resolved) else if (path_res == path_resolved)
*path_res++ = '/'; *path_res++ = '/';
*path_res = '\0'; *path_res = '\0';
return path_resolved; return path_resolved;
} }
/* Returns NULL on error. /* Returns NULL on error.
@ -140,266 +140,266 @@ next:
** NULL here causes 404 [Not Found], but that's not too unreasonable. */ ** NULL here causes 404 [Not Found], but that's not too unreasonable. */
struct path_info *uh_path_lookup(struct uh_client *cl, const char *url) struct path_info *uh_path_lookup(struct uh_client *cl, const char *url)
{ {
static char buf[PATH_MAX]; static char buf[PATH_MAX];
static char path_phys[PATH_MAX]; static char path_phys[PATH_MAX];
static char path_info[PATH_MAX]; static char path_info[PATH_MAX];
static struct path_info p; static struct path_info p;
const char *path = cl->get_path(cl); const char *path = cl->get_path(cl);
const char *query = cl->get_query(cl); const char *query = cl->get_query(cl);
const char *docroot = cl->srv->docroot; const char *docroot = cl->srv->docroot;
int docroot_len = strlen(docroot); int docroot_len = strlen(docroot);
char *pathptr = NULL; char *pathptr = NULL;
bool slash; bool slash;
int i = 0; int i = 0;
int len; int len;
/* back out early if url is undefined */ /* back out early if url is undefined */
if (url == NULL) if (url == NULL)
return NULL; return NULL;
memset(&p, 0, sizeof(p)); memset(&p, 0, sizeof(p));
path_phys[0] = 0; path_phys[0] = 0;
path_info[0] = 0; path_info[0] = 0;
strcpy(buf, docroot); strcpy(buf, docroot);
strcat(buf, path); strcat(buf, path);
/* create canon path */ /* create canon path */
len = strlen(buf); len = strlen(buf);
slash = len && buf[len - 1] == '/'; slash = len && buf[len - 1] == '/';
len = min(len, sizeof(path_phys) - 1); len = min(len, sizeof(path_phys) - 1);
for (i = len; i >= 0; i--) { for (i = len; i >= 0; i--) {
char ch = buf[i]; char ch = buf[i];
bool exists; bool exists;
if (ch != 0 && ch != '/') if (ch != 0 && ch != '/')
continue; continue;
buf[i] = 0; buf[i] = 0;
exists = !!canonpath(buf, path_phys); exists = !!canonpath(buf, path_phys);
buf[i] = ch; buf[i] = ch;
if (!exists) if (!exists)
continue; continue;
/* test current path */ /* test current path */
if (stat(path_phys, &p.stat)) if (stat(path_phys, &p.stat))
continue; continue;
snprintf(path_info, sizeof(path_info), "%s", buf + i); snprintf(path_info, sizeof(path_info), "%s", buf + i);
break; break;
} }
/* check whether found path is within docroot */ /* check whether found path is within docroot */
if (strncmp(path_phys, docroot, docroot_len) != 0 || if (strncmp(path_phys, docroot, docroot_len) != 0 ||
(path_phys[docroot_len] != 0 && (path_phys[docroot_len] != 0 &&
path_phys[docroot_len] != '/')) path_phys[docroot_len] != '/'))
return NULL; return NULL;
/* is a regular file */ /* is a regular file */
if (p.stat.st_mode & S_IFREG) { if (p.stat.st_mode & S_IFREG) {
p.root = docroot; p.root = docroot;
p.phys = path_phys; p.phys = path_phys;
p.name = &path_phys[docroot_len]; p.name = &path_phys[docroot_len];
p.info = path_info[0] ? path_info : NULL; p.info = path_info[0] ? path_info : NULL;
return &p; return &p;
} }
if (!(p.stat.st_mode & S_IFDIR)) if (!(p.stat.st_mode & S_IFDIR))
return NULL; return NULL;
if (path_info[0]) if (path_info[0])
return NULL; return NULL;
pathptr = path_phys + strlen(path_phys); pathptr = path_phys + strlen(path_phys);
/* ensure trailing slash */ /* ensure trailing slash */
if (pathptr[-1] != '/') { if (pathptr[-1] != '/') {
pathptr[0] = '/'; pathptr[0] = '/';
pathptr[1] = 0; pathptr[1] = 0;
pathptr++; pathptr++;
} }
/* if requested url resolves to a directory and a trailing slash /* if requested url resolves to a directory and a trailing slash
is missing in the request url, redirect the client to the same is missing in the request url, redirect the client to the same
url with trailing slash appended */ url with trailing slash appended */
if (!slash) { if (!slash) {
cl->send_header(cl, 302, "Found", 0); cl->send_header(cl, 302, "Found", 0);
cl->printf(cl, "Location: %s%s%s\r\n\r\n", &path_phys[docroot_len], cl->printf(cl, "Location: %s%s%s\r\n\r\n", &path_phys[docroot_len],
query ? "?" : "", query ? query : ""); query ? "?" : "", query ? query : "");
cl->request_done(cl); cl->request_done(cl);
p.redirected = 1; p.redirected = 1;
return &p; return &p;
} }
/* try to locate index file */ /* try to locate index file */
len = path_phys + sizeof(path_phys) - pathptr - 1; len = path_phys + sizeof(path_phys) - pathptr - 1;
strcpy(pathptr, cl->srv->index_file); strcpy(pathptr, cl->srv->index_file);
if (stat(path_phys, &p.stat) < 0) if (stat(path_phys, &p.stat) < 0)
return NULL; return NULL;
p.root = docroot; p.root = docroot;
p.phys = path_phys; p.phys = path_phys;
p.name = &path_phys[docroot_len]; p.name = &path_phys[docroot_len];
return p.phys ? &p : NULL; return p.phys ? &p : NULL;
} }
static char *file_unix2date(time_t ts, char *buf, int len) static char *file_unix2date(time_t ts, char *buf, int len)
{ {
struct tm *t = gmtime(&ts); struct tm *t = gmtime(&ts);
strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", t); strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", t);
return buf; return buf;
} }
static const char * uh_file_mime_lookup(const char *path) static const char * uh_file_mime_lookup(const char *path)
{ {
const struct mimetype *m = &uh_mime_types[0]; const struct mimetype *m = &uh_mime_types[0];
const char *e; const char *e;
while (m->extn) { while (m->extn) {
e = &path[strlen(path)-1]; e = &path[strlen(path)-1];
while (e >= path) { while (e >= path) {
if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn)) if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
return m->mime; return m->mime;
e--; e--;
} }
m++; m++;
} }
return "application/octet-stream"; return "application/octet-stream";
} }
static void uh_file_response_ok_hdrs(struct uh_client *cl, struct stat *s) static void uh_file_response_ok_hdrs(struct uh_client *cl, struct stat *s)
{ {
char buf[128]; char buf[128];
cl->printf(cl, "Last-Modified: %s\r\n", file_unix2date(s->st_mtime, buf, sizeof(buf))); cl->printf(cl, "Last-Modified: %s\r\n", file_unix2date(s->st_mtime, buf, sizeof(buf)));
cl->printf(cl, "Date: %s\r\n", file_unix2date(time(NULL), buf, sizeof(buf))); cl->printf(cl, "Date: %s\r\n", file_unix2date(time(NULL), buf, sizeof(buf)));
} }
static void uh_file_response_304(struct uh_client *cl, struct stat *s) static void uh_file_response_304(struct uh_client *cl, struct stat *s)
{ {
cl->send_header(cl, 304, "Not Modified", 0); cl->send_header(cl, 304, "Not Modified", 0);
uh_file_response_ok_hdrs(cl, s); uh_file_response_ok_hdrs(cl, s);
} }
static void uh_file_response_200(struct uh_client *cl, struct stat *s) static void uh_file_response_200(struct uh_client *cl, struct stat *s)
{ {
cl->send_header(cl, 200, "OK", s->st_size); cl->send_header(cl, 200, "OK", s->st_size);
uh_file_response_ok_hdrs(cl, s); uh_file_response_ok_hdrs(cl, s);
} }
static int uh_file_if_modified_since(struct uh_client *cl, struct stat *s) static int uh_file_if_modified_since(struct uh_client *cl, struct stat *s)
{ {
const char *date = kvlist_get(&cl->request.hdr, "if-modified-since"); const char *date = kvlist_get(&cl->request.hdr, "if-modified-since");
struct tm t; struct tm t;
if (!date) if (!date)
return true; return true;
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
if ((strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) ? timegm(&t) : 0) >= s->st_mtime) { if ((strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) ? timegm(&t) : 0) >= s->st_mtime) {
uh_file_response_304(cl, s); uh_file_response_304(cl, s);
return false; return false;
} }
return true; return true;
} }
static void file_write_cb(struct uh_client *cl) static void file_write_cb(struct uh_client *cl)
{ {
static char buf[4096]; static char buf[4096];
int fd = cl->dispatch.file.fd; int fd = cl->dispatch.file.fd;
int r; int r;
while (cl->us->w.data_bytes < 256) { while (cl->us->w.data_bytes < 256) {
r = read(fd, buf, sizeof(buf)); r = read(fd, buf, sizeof(buf));
if (r < 0) { if (r < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
uh_log_err("read"); uh_log_err("read");
} }
if (r <= 0) { if (r <= 0) {
cl->request_done(cl); cl->request_done(cl);
return; return;
} }
cl->send(cl, buf, r); cl->send(cl, buf, r);
} }
} }
static void uh_file_free(struct uh_client *cl) static void uh_file_free(struct uh_client *cl)
{ {
close(cl->dispatch.file.fd); close(cl->dispatch.file.fd);
} }
static void uh_file_data(struct uh_client *cl, struct path_info *pi, int fd) static void uh_file_data(struct uh_client *cl, struct path_info *pi, int fd)
{ {
/* test preconditions */ /* test preconditions */
if ((!uh_file_if_modified_since(cl, &pi->stat))) { if ((!uh_file_if_modified_since(cl, &pi->stat))) {
cl->printf(cl, "\r\n"); cl->printf(cl, "\r\n");
cl->request_done(cl); cl->request_done(cl);
close(fd); close(fd);
return; return;
} }
/* write status */ /* write status */
uh_file_response_200(cl, &pi->stat); uh_file_response_200(cl, &pi->stat);
cl->printf(cl, "Content-Type: %s\r\n\r\n", uh_file_mime_lookup(pi->name)); cl->printf(cl, "Content-Type: %s\r\n\r\n", uh_file_mime_lookup(pi->name));
/* send header */ /* send header */
if (cl->request.method == UH_HTTP_MSG_HEAD) { if (cl->request.method == UH_HTTP_MSG_HEAD) {
cl->request_done(cl); cl->request_done(cl);
close(fd); close(fd);
return; return;
} }
cl->state = CLIENT_STATE_DONE; cl->state = CLIENT_STATE_DONE;
cl->dispatch.file.fd = fd; cl->dispatch.file.fd = fd;
cl->dispatch.write_cb = file_write_cb; cl->dispatch.write_cb = file_write_cb;
cl->dispatch.free = uh_file_free; cl->dispatch.free = uh_file_free;
file_write_cb(cl); file_write_cb(cl);
} }
static void uh_file_request(struct uh_client *cl, const char *path, struct path_info *pi) static void uh_file_request(struct uh_client *cl, const char *path, struct path_info *pi)
{ {
int fd; int fd;
if (!(pi->stat.st_mode & S_IROTH)) if (!(pi->stat.st_mode & S_IROTH))
goto error; goto error;
if (pi->stat.st_mode & S_IFREG) { if (pi->stat.st_mode & S_IFREG) {
fd = open(pi->phys, O_RDONLY); fd = open(pi->phys, O_RDONLY);
if (fd < 0) if (fd < 0)
goto error; goto error;
uh_file_data(cl, pi, fd); uh_file_data(cl, pi, fd);
return; return;
} }
error: error:
cl->send_error(cl, 403, "Forbidden", "You don't have permission to access %s on this server.", path); cl->send_error(cl, 403, "Forbidden", "You don't have permission to access %s on this server.", path);
} }
bool handle_file_request(struct uh_client *cl, const char *path) bool handle_file_request(struct uh_client *cl, const char *path)
{ {
struct path_info *pi; struct path_info *pi;
pi = uh_path_lookup(cl, path); pi = uh_path_lookup(cl, path);
if (!pi) if (!pi)
return false; return false;
uh_log_debug("pi->root: %s", pi->root); uh_log_debug("pi->root: %s", pi->root);
uh_log_debug("pi->phys: %s", pi->phys); uh_log_debug("pi->phys: %s", pi->phys);
@ -407,11 +407,11 @@ bool handle_file_request(struct uh_client *cl, const char *path)
uh_log_debug("pi->info: %s", pi->info); uh_log_debug("pi->info: %s", pi->info);
uh_log_debug("pi->redirected: %d", pi->redirected); uh_log_debug("pi->redirected: %d", pi->redirected);
if (pi->redirected) if (pi->redirected)
return true; return true;
uh_file_request(cl, path, pi); uh_file_request(cl, path, pi);
return true; return true;
} }

View File

@ -21,17 +21,17 @@
#include "client.h" #include "client.h"
struct path_info { struct path_info {
const char *root; const char *root;
const char *phys; const char *phys;
const char *name; const char *name;
const char *info; const char *info;
bool redirected; bool redirected;
struct stat stat; struct stat stat;
}; };
struct mimetype { struct mimetype {
const char *extn; const char *extn;
const char *mime; const char *mime;
}; };
bool handle_file_request(struct uh_client *cl, const char *path); bool handle_file_request(struct uh_client *cl, const char *path);

View File

@ -27,79 +27,79 @@ static void *ctx;
int uh_ssl_init(struct uh_server *srv, const char *key, const char *crt) int uh_ssl_init(struct uh_server *srv, const char *key, const char *crt)
{ {
srv->ssl = true; srv->ssl = true;
if (_init) if (_init)
return 0; return 0;
_init = true; _init = true;
dlh = dlopen("libustream-ssl.so", RTLD_LAZY | RTLD_LOCAL); dlh = dlopen("libustream-ssl.so", RTLD_LAZY | RTLD_LOCAL);
if (!dlh) { if (!dlh) {
uh_log_err("Failed to load ustream-ssl library: %s", dlerror()); uh_log_err("Failed to load ustream-ssl library: %s", dlerror());
return -ENOENT; return -ENOENT;
} }
ops = dlsym(dlh, "ustream_ssl_ops"); ops = dlsym(dlh, "ustream_ssl_ops");
if (!ops) { if (!ops) {
uh_log_err("Could not find required symbol 'ustream_ssl_ops' in ustream-ssl library"); uh_log_err("Could not find required symbol 'ustream_ssl_ops' in ustream-ssl library");
return -ENOENT; return -ENOENT;
} }
ctx = ops->context_new(true); ctx = ops->context_new(true);
if (!ctx) { if (!ctx) {
uh_log_err("Failed to initialize ustream-ssl"); uh_log_err("Failed to initialize ustream-ssl");
return -EINVAL; return -EINVAL;
} }
if (ops->context_set_crt_file(ctx, crt) || if (ops->context_set_crt_file(ctx, crt) ||
ops->context_set_key_file(ctx, key)) { ops->context_set_key_file(ctx, key)) {
uh_log_err("Failed to load certificate/key files"); uh_log_err("Failed to load certificate/key files");
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
void uh_ssl_free() void uh_ssl_free()
{ {
if (_init) { if (_init) {
_init = false; _init = false;
ops->context_free(ctx); ops->context_free(ctx);
} }
} }
static void ssl_ustream_read_cb(struct ustream *s, int bytes) static void ssl_ustream_read_cb(struct ustream *s, int bytes)
{ {
struct uh_client *cl = container_of(s, struct uh_client, ssl.stream); struct uh_client *cl = container_of(s, struct uh_client, ssl.stream);
uh_client_read_cb(cl); uh_client_read_cb(cl);
} }
static void ssl_ustream_write_cb(struct ustream *s, int bytes) static void ssl_ustream_write_cb(struct ustream *s, int bytes)
{ {
struct uh_client *cl = container_of(s, struct uh_client, ssl.stream); struct uh_client *cl = container_of(s, struct uh_client, ssl.stream);
if (cl->dispatch.write_cb) if (cl->dispatch.write_cb)
cl->dispatch.write_cb(cl); cl->dispatch.write_cb(cl);
} }
static void ssl_notify_state(struct ustream *s) static void ssl_notify_state(struct ustream *s)
{ {
struct uh_client *cl = container_of(s, struct uh_client, ssl.stream); struct uh_client *cl = container_of(s, struct uh_client, ssl.stream);
uh_client_notify_state(cl); uh_client_notify_state(cl);
} }
void uh_ssl_client_attach(struct uh_client *cl) void uh_ssl_client_attach(struct uh_client *cl)
{ {
cl->us = &cl->ssl.stream; cl->us = &cl->ssl.stream;
ops->init(&cl->ssl, &cl->sfd.stream, ctx, true); ops->init(&cl->ssl, &cl->sfd.stream, ctx, true);
cl->us->notify_read = ssl_ustream_read_cb; cl->us->notify_read = ssl_ustream_read_cb;
cl->us->notify_write = ssl_ustream_write_cb; cl->us->notify_write = ssl_ustream_write_cb;
cl->us->notify_state = ssl_notify_state; cl->us->notify_state = ssl_notify_state;
} }
void uh_ssl_client_detach(struct uh_client *cl) void uh_ssl_client_detach(struct uh_client *cl)
{ {
ustream_free(&cl->ssl.stream); ustream_free(&cl->ssl.stream);
} }

View File

@ -30,7 +30,7 @@ void uh_ssl_client_detach(struct uh_client *cl);
static inline int uh_ssl_init(const char *key, const char *crt) static inline int uh_ssl_init(const char *key, const char *crt)
{ {
return -1; return -1;
} }
static inline void uh_ssl_free() static inline void uh_ssl_free()

View File

@ -23,14 +23,14 @@
struct uh_server { struct uh_server {
bool ssl; bool ssl;
struct uloop_fd fd; struct uloop_fd fd;
char *docroot; char *docroot;
char *index_file; char *index_file;
int nclients; int nclients;
struct avl_tree actions; struct avl_tree actions;
struct list_head clients; struct list_head clients;
void (*free)(struct uh_server *srv); void (*free)(struct uh_server *srv);
void (*set_docroot)(struct uh_server *srv, const char *docroot); void (*set_docroot)(struct uh_server *srv, const char *docroot);
void (*set_index_file)(struct uh_server *srv, const char *index_file); void (*set_index_file)(struct uh_server *srv, const char *index_file);
void (*error404_cb)(struct uh_client *cl); void (*error404_cb)(struct uh_client *cl);

View File

@ -19,12 +19,12 @@
void uh_printf(struct uh_client *cl, const char *format, ...) void uh_printf(struct uh_client *cl, const char *format, ...)
{ {
va_list arg; va_list arg;
uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000); uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000);
va_start(arg, format); va_start(arg, format);
ustream_vprintf(cl->us, format, arg); ustream_vprintf(cl->us, format, arg);
va_end(arg); va_end(arg);
} }
void uh_vprintf(struct uh_client *cl, const char *format, va_list arg) void uh_vprintf(struct uh_client *cl, const char *format, va_list arg)
@ -35,59 +35,59 @@ void uh_vprintf(struct uh_client *cl, const char *format, va_list arg)
void uh_chunk_send(struct uh_client *cl, const void *data, int len) void uh_chunk_send(struct uh_client *cl, const void *data, int len)
{ {
struct ustream *us = cl->us; struct ustream *us = cl->us;
uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000); uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000);
ustream_printf(us, "%X\r\n", len); ustream_printf(us, "%X\r\n", len);
ustream_write(us, data, len, true); ustream_write(us, data, len, true);
ustream_printf(us, "\r\n", len); ustream_printf(us, "\r\n", len);
} }
void uh_chunk_printf(struct uh_client *cl, const char *format, ...) void uh_chunk_printf(struct uh_client *cl, const char *format, ...)
{ {
va_list arg; va_list arg;
va_start(arg, format); va_start(arg, format);
uh_chunk_vprintf(cl, format, arg); uh_chunk_vprintf(cl, format, arg);
va_end(arg); va_end(arg);
} }
void uh_chunk_vprintf(struct uh_client *cl, const char *format, va_list arg) void uh_chunk_vprintf(struct uh_client *cl, const char *format, va_list arg)
{ {
struct ustream *us = cl->us; struct ustream *us = cl->us;
char buf[256]; char buf[256];
va_list arg2; va_list arg2;
int len; int len;
uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000); uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000);
va_copy(arg2, arg); va_copy(arg2, arg);
len = vsnprintf(buf, sizeof(buf), format, arg2); len = vsnprintf(buf, sizeof(buf), format, arg2);
va_end(arg2); va_end(arg2);
ustream_printf(us, "%X\r\n", len); ustream_printf(us, "%X\r\n", len);
if (len < sizeof(buf)) if (len < sizeof(buf))
ustream_write(cl->us, buf, len, true); ustream_write(cl->us, buf, len, true);
else else
ustream_vprintf(cl->us, format, arg); ustream_vprintf(cl->us, format, arg);
ustream_printf(us, "\r\n", len); ustream_printf(us, "\r\n", len);
} }
char *uh_split_header(char *str) char *uh_split_header(char *str)
{ {
char *val; char *val;
val = strchr(str, ':'); val = strchr(str, ':');
if (!val) if (!val)
return NULL; return NULL;
*val = 0; *val = 0;
val++; val++;
while (isspace(*val)) while (isspace(*val))
val++; val++;
return val; return val;
} }
/* blen is the size of buf; slen is the length of src. The input-string need /* blen is the size of buf; slen is the length of src. The input-string need
@ -95,30 +95,30 @@ char *uh_split_header(char *str)
** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */ ** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
int uh_urldecode(char *buf, int blen, const char *src, int slen) int uh_urldecode(char *buf, int blen, const char *src, int slen)
{ {
int i; int i;
int len = 0; int len = 0;
#define hex(x) \ #define hex(x) \
(((x) <= '9') ? ((x) - '0') : \ (((x) <= '9') ? ((x) - '0') : \
(((x) <= 'F') ? ((x) - 'A' + 10) : \ (((x) <= 'F') ? ((x) - 'A' + 10) : \
((x) - 'a' + 10))) ((x) - 'a' + 10)))
for (i = 0; (i < slen) && (len < blen); i++) for (i = 0; (i < slen) && (len < blen); i++)
{ {
if (src[i] != '%') { if (src[i] != '%') {
buf[len++] = src[i]; buf[len++] = src[i];
continue; continue;
} }
if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2])) if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2]))
return -2; return -2;
buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2])); buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
i += 2; i += 2;
} }
buf[len] = 0; buf[len] = 0;
return (i == slen) ? len : -1; return (i == slen) ? len : -1;
} }
/* blen is the size of buf; slen is the length of src. The input-string need /* blen is the size of buf; slen is the length of src. The input-string need
@ -126,31 +126,31 @@ int uh_urldecode(char *buf, int blen, const char *src, int slen)
** length of the encoded string, or -1 on error (buffer overflow) */ ** length of the encoded string, or -1 on error (buffer overflow) */
int uh_urlencode(char *buf, int blen, const char *src, int slen) int uh_urlencode(char *buf, int blen, const char *src, int slen)
{ {
int i; int i;
int len = 0; int len = 0;
static const char hex[] = "0123456789abcdef"; static const char hex[] = "0123456789abcdef";
for (i = 0; (i < slen) && (len < blen); i++) for (i = 0; (i < slen) && (len < blen); i++)
{ {
if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') || if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
(src[i] == '.') || (src[i] == '~') ) (src[i] == '.') || (src[i] == '~') )
{ {
buf[len++] = src[i]; buf[len++] = src[i];
} }
else if ((len+3) <= blen) else if ((len+3) <= blen)
{ {
buf[len++] = '%'; buf[len++] = '%';
buf[len++] = hex[(src[i] >> 4) & 15]; buf[len++] = hex[(src[i] >> 4) & 15];
buf[len++] = hex[ src[i] & 15]; buf[len++] = hex[ src[i] & 15];
} }
else else
{ {
len = -1; len = -1;
break; break;
} }
} }
return (i == slen) ? len : -1; return (i == slen) ? len : -1;
} }
int find_idx(const char *const *list, int max, const char *str) int find_idx(const char *const *list, int max, const char *str)