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);
struct uh_action {
struct avl_node avl;
char path[PATH_MAX];
struct avl_node avl;
char path[PATH_MAX];
action_cb_t cb;
};

View File

@ -22,15 +22,15 @@
#include "uh_ssl.h"
const char *const http_versions[] = {
[UH_HTTP_VER_0_9] = "HTTP/0.9",
[UH_HTTP_VER_1_0] = "HTTP/1.0",
[UH_HTTP_VER_1_1] = "HTTP/1.1"
[UH_HTTP_VER_0_9] = "HTTP/0.9",
[UH_HTTP_VER_1_0] = "HTTP/1.0",
[UH_HTTP_VER_1_1] = "HTTP/1.1"
};
const char *const http_methods[] = {
[UH_HTTP_MSG_GET] = "GET",
[UH_HTTP_MSG_POST] = "POST",
[UH_HTTP_MSG_HEAD] = "HEAD"
[UH_HTTP_MSG_GET] = "GET",
[UH_HTTP_MSG_POST] = "POST",
[UH_HTTP_MSG_HEAD] = "HEAD"
};
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;
if (handle_file_request(cl, path))
return;
return;
if (cl->srv->error404_cb) {
cl->srv->error404_cb(cl);
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)
{
cl->us->eof = true;
cl->us->eof = true;
cl->state = CLIENT_STATE_CLOSE;
ustream_state_change(cl->us);
ustream_state_change(cl->us);
}
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);
}
static void dispatch_done(struct uh_client *cl)
{
if (cl->dispatch.free)
cl->dispatch.free(cl);
if (cl->dispatch.free)
cl->dispatch.free(cl);
}
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)
{
if (cl->response_length < 0)
if (cl->response_length < 0)
cl->printf(cl, "0\r\n\r\n");
dispatch_done(cl);
if (cl->connection_close) {
connection_close(cl);
if (cl->connection_close) {
connection_close(cl);
return;
}
@ -250,7 +250,7 @@ static bool client_init_cb(struct uh_client *cl, char *buf, int len)
return true;
}
*newline = 0;
*newline = 0;
cl->state = client_parse_request(cl, 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)
{
char *newline;
char *newline;
int line_len;
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);
static read_cb_t read_cbs[] = {
[CLIENT_STATE_INIT] = client_init_cb,
[CLIENT_STATE_HEADER] = client_header_cb,
[CLIENT_STATE_DATA] = client_data_cb,
[CLIENT_STATE_INIT] = client_init_cb,
[CLIENT_STATE_HEADER] = client_header_cb,
[CLIENT_STATE_DATA] = client_data_cb,
};
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)
{
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);
}
@ -434,15 +434,15 @@ static void client_notify_state(struct ustream *s)
void uh_accept_client(struct uh_server *srv, bool ssl)
{
struct uh_client *cl;
unsigned int sl;
int sfd;
unsigned int sl;
int sfd;
struct sockaddr_in addr;
sl = sizeof(addr);
sfd = accept(srv->fd.fd, (struct sockaddr *)&addr, &sl);
if (sfd < 0) {
sfd = accept(srv->fd.fd, (struct sockaddr *)&addr, &sl);
if (sfd < 0) {
uh_log_err("accept");
return;
return;
}
cl = calloc(1, sizeof(struct uh_client));

View File

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

View File

@ -1,18 +1,18 @@
/*
/*
* Copyright (C) 2017 Jianhui Zhao <jianhuizhao329@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _COMMON_H
@ -20,16 +20,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <stdbool.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/limits.h>

View File

@ -22,117 +22,117 @@
#include "uhttpd.h"
static const struct mimetype uh_mime_types[] = {
{ "txt", "text/plain" },
{ "log", "text/plain" },
{ "js", "text/javascript" },
{ "css", "text/css" },
{ "htm", "text/html" },
{ "html", "text/html" },
{ "diff", "text/x-patch" },
{ "patch", "text/x-patch" },
{ "c", "text/x-csrc" },
{ "h", "text/x-chdr" },
{ "o", "text/x-object" },
{ "ko", "text/x-object" },
{ "txt", "text/plain" },
{ "log", "text/plain" },
{ "js", "text/javascript" },
{ "css", "text/css" },
{ "htm", "text/html" },
{ "html", "text/html" },
{ "diff", "text/x-patch" },
{ "patch", "text/x-patch" },
{ "c", "text/x-csrc" },
{ "h", "text/x-chdr" },
{ "o", "text/x-object" },
{ "ko", "text/x-object" },
{ "bmp", "image/bmp" },
{ "gif", "image/gif" },
{ "png", "image/png" },
{ "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" },
{ "bmp", "image/bmp" },
{ "gif", "image/gif" },
{ "png", "image/png" },
{ "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" },
{ "json", "application/json" },
{ "jsonp", "application/javascript" },
{ "zip", "application/zip" },
{ "pdf", "application/pdf" },
{ "xml", "application/xml" },
{ "xsl", "application/xml" },
{ "doc", "application/msword" },
{ "ppt", "application/vnd.ms-powerpoint" },
{ "xls", "application/vnd.ms-excel" },
{ "odt", "application/vnd.oasis.opendocument.text" },
{ "odp", "application/vnd.oasis.opendocument.presentation" },
{ "pl", "application/x-perl" },
{ "sh", "application/x-shellscript" },
{ "php", "application/x-php" },
{ "deb", "application/x-deb" },
{ "iso", "application/x-cd-image" },
{ "tar.gz", "application/x-compressed-tar" },
{ "tgz", "application/x-compressed-tar" },
{ "gz", "application/x-gzip" },
{ "tar.bz2", "application/x-bzip-compressed-tar" },
{ "tbz", "application/x-bzip-compressed-tar" },
{ "bz2", "application/x-bzip" },
{ "tar", "application/x-tar" },
{ "rar", "application/x-rar-compressed" },
{ "json", "application/json" },
{ "jsonp", "application/javascript" },
{ "zip", "application/zip" },
{ "pdf", "application/pdf" },
{ "xml", "application/xml" },
{ "xsl", "application/xml" },
{ "doc", "application/msword" },
{ "ppt", "application/vnd.ms-powerpoint" },
{ "xls", "application/vnd.ms-excel" },
{ "odt", "application/vnd.oasis.opendocument.text" },
{ "odp", "application/vnd.oasis.opendocument.presentation" },
{ "pl", "application/x-perl" },
{ "sh", "application/x-shellscript" },
{ "php", "application/x-php" },
{ "deb", "application/x-deb" },
{ "iso", "application/x-cd-image" },
{ "tar.gz", "application/x-compressed-tar" },
{ "tgz", "application/x-compressed-tar" },
{ "gz", "application/x-gzip" },
{ "tar.bz2", "application/x-bzip-compressed-tar" },
{ "tbz", "application/x-bzip-compressed-tar" },
{ "bz2", "application/x-bzip" },
{ "tar", "application/x-tar" },
{ "rar", "application/x-rar-compressed" },
{ "mp3", "audio/mpeg" },
{ "ogg", "audio/x-vorbis+ogg" },
{ "wav", "audio/x-wav" },
{ "mp3", "audio/mpeg" },
{ "ogg", "audio/x-vorbis+ogg" },
{ "wav", "audio/x-wav" },
{ "mpg", "video/mpeg" },
{ "mpeg", "video/mpeg" },
{ "avi", "video/x-msvideo" },
{ "mpg", "video/mpeg" },
{ "mpeg", "video/mpeg" },
{ "avi", "video/x-msvideo" },
{ "README", "text/plain" },
{ "log", "text/plain" },
{ "cfg", "text/plain" },
{ "conf", "text/plain" },
{ "README", "text/plain" },
{ "log", "text/plain" },
{ "cfg", "text/plain" },
{ "conf", "text/plain" },
{ "pac", "application/x-ns-proxy-autoconfig" },
{ "wpad.dat", "application/x-ns-proxy-autoconfig" },
{ "pac", "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)
{
const char *path_cpy = path;
char *path_res = path_resolved;
const char *path_cpy = path;
char *path_res = path_resolved;
/* normalize */
while ((*path_cpy != '\0') && (path_cpy < (path + PATH_MAX - 2))) {
if (*path_cpy != '/')
goto next;
/* normalize */
while ((*path_cpy != '\0') && (path_cpy < (path + PATH_MAX - 2))) {
if (*path_cpy != '/')
goto next;
/* skip repeating / */
if (path_cpy[1] == '/') {
path_cpy++;
continue;
}
/* skip repeating / */
if (path_cpy[1] == '/') {
path_cpy++;
continue;
}
/* /./ or /../ */
if (path_cpy[1] == '.') {
/* skip /./ */
if ((path_cpy[2] == '/') || (path_cpy[2] == '\0')) {
path_cpy += 2;
continue;
}
/* /./ or /../ */
if (path_cpy[1] == '.') {
/* skip /./ */
if ((path_cpy[2] == '/') || (path_cpy[2] == '\0')) {
path_cpy += 2;
continue;
}
/* collapse /x/../ */
if ((path_cpy[2] == '.') &&
((path_cpy[3] == '/') || (path_cpy[3] == '\0'))) {
while ((path_res > path_resolved) && (*--path_res != '/'));
/* collapse /x/../ */
if ((path_cpy[2] == '.') &&
((path_cpy[3] == '/') || (path_cpy[3] == '\0'))) {
while ((path_res > path_resolved) && (*--path_res != '/'));
path_cpy += 3;
continue;
}
}
path_cpy += 3;
continue;
}
}
next:
*path_res++ = *path_cpy++;
}
*path_res++ = *path_cpy++;
}
/* remove trailing slash if not root / */
if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
path_res--;
else if (path_res == path_resolved)
*path_res++ = '/';
/* remove trailing slash if not root / */
if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
path_res--;
else if (path_res == path_resolved)
*path_res++ = '/';
*path_res = '\0';
*path_res = '\0';
return path_resolved;
return path_resolved;
}
/* Returns NULL on error.
@ -140,266 +140,266 @@ next:
** 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)
{
static char buf[PATH_MAX];
static char path_phys[PATH_MAX];
static char path_info[PATH_MAX];
static struct path_info p;
const char *path = cl->get_path(cl);
const char *query = cl->get_query(cl);
static char buf[PATH_MAX];
static char path_phys[PATH_MAX];
static char path_info[PATH_MAX];
static struct path_info p;
const char *path = cl->get_path(cl);
const char *query = cl->get_query(cl);
const char *docroot = cl->srv->docroot;
int docroot_len = strlen(docroot);
char *pathptr = NULL;
bool slash;
const char *docroot = cl->srv->docroot;
int docroot_len = strlen(docroot);
char *pathptr = NULL;
bool slash;
int i = 0;
int len;
int i = 0;
int len;
/* back out early if url is undefined */
if (url == NULL)
return NULL;
/* back out early if url is undefined */
if (url == NULL)
return NULL;
memset(&p, 0, sizeof(p));
path_phys[0] = 0;
path_info[0] = 0;
memset(&p, 0, sizeof(p));
path_phys[0] = 0;
path_info[0] = 0;
strcpy(buf, docroot);
strcat(buf, path);
strcpy(buf, docroot);
strcat(buf, path);
/* create canon path */
len = strlen(buf);
slash = len && buf[len - 1] == '/';
len = min(len, sizeof(path_phys) - 1);
/* create canon path */
len = strlen(buf);
slash = len && buf[len - 1] == '/';
len = min(len, sizeof(path_phys) - 1);
for (i = len; i >= 0; i--) {
char ch = buf[i];
bool exists;
for (i = len; i >= 0; i--) {
char ch = buf[i];
bool exists;
if (ch != 0 && ch != '/')
continue;
if (ch != 0 && ch != '/')
continue;
buf[i] = 0;
exists = !!canonpath(buf, path_phys);
buf[i] = ch;
buf[i] = 0;
exists = !!canonpath(buf, path_phys);
buf[i] = ch;
if (!exists)
continue;
if (!exists)
continue;
/* test current path */
if (stat(path_phys, &p.stat))
continue;
/* test current path */
if (stat(path_phys, &p.stat))
continue;
snprintf(path_info, sizeof(path_info), "%s", buf + i);
break;
}
snprintf(path_info, sizeof(path_info), "%s", buf + i);
break;
}
/* check whether found path is within docroot */
if (strncmp(path_phys, docroot, docroot_len) != 0 ||
(path_phys[docroot_len] != 0 &&
path_phys[docroot_len] != '/'))
return NULL;
/* check whether found path is within docroot */
if (strncmp(path_phys, docroot, docroot_len) != 0 ||
(path_phys[docroot_len] != 0 &&
path_phys[docroot_len] != '/'))
return NULL;
/* is a regular file */
if (p.stat.st_mode & S_IFREG) {
p.root = docroot;
p.phys = path_phys;
p.name = &path_phys[docroot_len];
p.info = path_info[0] ? path_info : NULL;
return &p;
}
/* is a regular file */
if (p.stat.st_mode & S_IFREG) {
p.root = docroot;
p.phys = path_phys;
p.name = &path_phys[docroot_len];
p.info = path_info[0] ? path_info : NULL;
return &p;
}
if (!(p.stat.st_mode & S_IFDIR))
return NULL;
if (!(p.stat.st_mode & S_IFDIR))
return NULL;
if (path_info[0])
return NULL;
if (path_info[0])
return NULL;
pathptr = path_phys + strlen(path_phys);
pathptr = path_phys + strlen(path_phys);
/* ensure trailing slash */
if (pathptr[-1] != '/') {
pathptr[0] = '/';
pathptr[1] = 0;
pathptr++;
}
/* ensure trailing slash */
if (pathptr[-1] != '/') {
pathptr[0] = '/';
pathptr[1] = 0;
pathptr++;
}
/* if requested url resolves to a directory and a trailing slash
is missing in the request url, redirect the client to the same
url with trailing slash appended */
if (!slash) {
cl->send_header(cl, 302, "Found", 0);
cl->printf(cl, "Location: %s%s%s\r\n\r\n", &path_phys[docroot_len],
query ? "?" : "", query ? query : "");
cl->request_done(cl);
p.redirected = 1;
return &p;
}
/* if requested url resolves to a directory and a trailing slash
is missing in the request url, redirect the client to the same
url with trailing slash appended */
if (!slash) {
cl->send_header(cl, 302, "Found", 0);
cl->printf(cl, "Location: %s%s%s\r\n\r\n", &path_phys[docroot_len],
query ? "?" : "", query ? query : "");
cl->request_done(cl);
p.redirected = 1;
return &p;
}
/* try to locate index file */
len = path_phys + sizeof(path_phys) - pathptr - 1;
/* try to locate index file */
len = path_phys + sizeof(path_phys) - pathptr - 1;
strcpy(pathptr, cl->srv->index_file);
if (stat(path_phys, &p.stat) < 0)
return NULL;
p.root = docroot;
p.phys = path_phys;
p.name = &path_phys[docroot_len];
p.root = docroot;
p.phys = path_phys;
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)
{
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)
{
const struct mimetype *m = &uh_mime_types[0];
const char *e;
const struct mimetype *m = &uh_mime_types[0];
const char *e;
while (m->extn) {
e = &path[strlen(path)-1];
while (m->extn) {
e = &path[strlen(path)-1];
while (e >= path) {
if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
return m->mime;
e--;
}
m++;
}
while (e >= path) {
if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
return m->mime;
e--;
}
m++;
}
return "application/octet-stream";
return "application/octet-stream";
}
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, "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)
{
cl->send_header(cl, 304, "Not Modified", 0);
uh_file_response_ok_hdrs(cl, s);
cl->send_header(cl, 304, "Not Modified", 0);
uh_file_response_ok_hdrs(cl, s);
}
static void uh_file_response_200(struct uh_client *cl, struct stat *s)
{
cl->send_header(cl, 200, "OK", s->st_size);
uh_file_response_ok_hdrs(cl, s);
cl->send_header(cl, 200, "OK", s->st_size);
uh_file_response_ok_hdrs(cl, 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;
if (!date)
return true;
if (!date)
return true;
memset(&t, 0, sizeof(t));
if ((strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) ? timegm(&t) : 0) >= s->st_mtime) {
uh_file_response_304(cl, s);
return false;
}
if ((strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) ? timegm(&t) : 0) >= s->st_mtime) {
uh_file_response_304(cl, s);
return false;
}
return true;
return true;
}
static void file_write_cb(struct uh_client *cl)
{
static char buf[4096];
int fd = cl->dispatch.file.fd;
int r;
static char buf[4096];
int fd = cl->dispatch.file.fd;
int r;
while (cl->us->w.data_bytes < 256) {
r = read(fd, buf, sizeof(buf));
if (r < 0) {
if (errno == EINTR)
continue;
uh_log_err("read");
}
while (cl->us->w.data_bytes < 256) {
r = read(fd, buf, sizeof(buf));
if (r < 0) {
if (errno == EINTR)
continue;
uh_log_err("read");
}
if (r <= 0) {
cl->request_done(cl);
return;
}
if (r <= 0) {
cl->request_done(cl);
return;
}
cl->send(cl, buf, r);
}
cl->send(cl, buf, r);
}
}
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)
{
/* test preconditions */
if ((!uh_file_if_modified_since(cl, &pi->stat))) {
/* test preconditions */
if ((!uh_file_if_modified_since(cl, &pi->stat))) {
cl->printf(cl, "\r\n");
cl->request_done(cl);
close(fd);
return;
}
cl->request_done(cl);
close(fd);
return;
}
/* write status */
uh_file_response_200(cl, &pi->stat);
/* write status */
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 */
if (cl->request.method == UH_HTTP_MSG_HEAD) {
cl->request_done(cl);
close(fd);
return;
}
/* send header */
if (cl->request.method == UH_HTTP_MSG_HEAD) {
cl->request_done(cl);
close(fd);
return;
}
cl->state = CLIENT_STATE_DONE;
cl->dispatch.file.fd = fd;
cl->dispatch.write_cb = file_write_cb;
cl->dispatch.free = uh_file_free;
file_write_cb(cl);
cl->dispatch.file.fd = fd;
cl->dispatch.write_cb = file_write_cb;
cl->dispatch.free = uh_file_free;
file_write_cb(cl);
}
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))
goto error;
if (!(pi->stat.st_mode & S_IROTH))
goto error;
if (pi->stat.st_mode & S_IFREG) {
fd = open(pi->phys, O_RDONLY);
if (fd < 0)
goto error;
if (pi->stat.st_mode & S_IFREG) {
fd = open(pi->phys, O_RDONLY);
if (fd < 0)
goto error;
uh_file_data(cl, pi, fd);
return;
}
uh_file_data(cl, pi, fd);
return;
}
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)
{
struct path_info *pi;
struct path_info *pi;
pi = uh_path_lookup(cl, path);
if (!pi)
return false;
pi = uh_path_lookup(cl, path);
if (!pi)
return false;
uh_log_debug("pi->root: %s", pi->root);
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->redirected: %d", pi->redirected);
if (pi->redirected)
return true;
if (pi->redirected)
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"
struct path_info {
const char *root;
const char *phys;
const char *name;
const char *info;
bool redirected;
struct stat stat;
const char *root;
const char *phys;
const char *name;
const char *info;
bool redirected;
struct stat stat;
};
struct mimetype {
const char *extn;
const char *mime;
const char *extn;
const char *mime;
};
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)
{
srv->ssl = true;
srv->ssl = true;
if (_init)
return 0;
if (_init)
return 0;
_init = true;
dlh = dlopen("libustream-ssl.so", RTLD_LAZY | RTLD_LOCAL);
if (!dlh) {
uh_log_err("Failed to load ustream-ssl library: %s", dlerror());
return -ENOENT;
}
_init = true;
dlh = dlopen("libustream-ssl.so", RTLD_LAZY | RTLD_LOCAL);
if (!dlh) {
uh_log_err("Failed to load ustream-ssl library: %s", dlerror());
return -ENOENT;
}
ops = dlsym(dlh, "ustream_ssl_ops");
if (!ops) {
uh_log_err("Could not find required symbol 'ustream_ssl_ops' in ustream-ssl library");
return -ENOENT;
}
ops = dlsym(dlh, "ustream_ssl_ops");
if (!ops) {
uh_log_err("Could not find required symbol 'ustream_ssl_ops' in ustream-ssl library");
return -ENOENT;
}
ctx = ops->context_new(true);
if (!ctx) {
uh_log_err("Failed to initialize ustream-ssl");
return -EINVAL;
}
ctx = ops->context_new(true);
if (!ctx) {
uh_log_err("Failed to initialize ustream-ssl");
return -EINVAL;
}
if (ops->context_set_crt_file(ctx, crt) ||
ops->context_set_key_file(ctx, key)) {
uh_log_err("Failed to load certificate/key files");
return -EINVAL;
}
if (ops->context_set_crt_file(ctx, crt) ||
ops->context_set_key_file(ctx, key)) {
uh_log_err("Failed to load certificate/key files");
return -EINVAL;
}
return 0;
return 0;
}
void uh_ssl_free()
{
if (_init) {
_init = false;
ops->context_free(ctx);
}
if (_init) {
_init = false;
ops->context_free(ctx);
}
}
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)
{
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)
cl->dispatch.write_cb(cl);
if (cl->dispatch.write_cb)
cl->dispatch.write_cb(cl);
}
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)
{
cl->us = &cl->ssl.stream;
ops->init(&cl->ssl, &cl->sfd.stream, ctx, true);
cl->us->notify_read = ssl_ustream_read_cb;
cl->us->notify_write = ssl_ustream_write_cb;
cl->us->notify_state = ssl_notify_state;
cl->us = &cl->ssl.stream;
ops->init(&cl->ssl, &cl->sfd.stream, ctx, true);
cl->us->notify_read = ssl_ustream_read_cb;
cl->us->notify_write = ssl_ustream_write_cb;
cl->us->notify_state = ssl_notify_state;
}
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)
{
return -1;
return -1;
}
static inline void uh_ssl_free()

View File

@ -23,14 +23,14 @@
struct uh_server {
bool ssl;
struct uloop_fd fd;
struct uloop_fd fd;
char *docroot;
char *index_file;
int nclients;
struct avl_tree actions;
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_index_file)(struct uh_server *srv, const char *index_file);
void (*error404_cb)(struct uh_client *cl);

View File

@ -19,12 +19,12 @@
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);
va_start(arg, format);
ustream_vprintf(cl->us, format, arg);
va_end(arg);
va_start(arg, format);
ustream_vprintf(cl->us, format, arg);
va_end(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)
{
struct ustream *us = cl->us;
struct ustream *us = cl->us;
uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000);
ustream_printf(us, "%X\r\n", len);
ustream_write(us, data, len, true);
ustream_printf(us, "\r\n", len);
ustream_printf(us, "%X\r\n", len);
ustream_write(us, data, len, true);
ustream_printf(us, "\r\n", len);
}
void uh_chunk_printf(struct uh_client *cl, const char *format, ...)
{
va_list arg;
va_list arg;
va_start(arg, format);
uh_chunk_vprintf(cl, format, arg);
va_end(arg);
va_start(arg, format);
uh_chunk_vprintf(cl, format, arg);
va_end(arg);
}
void uh_chunk_vprintf(struct uh_client *cl, const char *format, va_list arg)
{
struct ustream *us = cl->us;
char buf[256];
va_list arg2;
int len;
struct ustream *us = cl->us;
char buf[256];
va_list arg2;
int len;
uloop_timeout_set(&cl->timeout, UHTTPD_CONNECTION_TIMEOUT * 1000);
va_copy(arg2, arg);
len = vsnprintf(buf, sizeof(buf), format, arg2);
va_end(arg2);
va_copy(arg2, arg);
len = vsnprintf(buf, sizeof(buf), format, arg2);
va_end(arg2);
ustream_printf(us, "%X\r\n", len);
if (len < sizeof(buf))
ustream_write(cl->us, buf, len, true);
else
ustream_vprintf(cl->us, format, arg);
ustream_printf(us, "\r\n", len);
ustream_printf(us, "%X\r\n", len);
if (len < sizeof(buf))
ustream_write(cl->us, buf, len, true);
else
ustream_vprintf(cl->us, format, arg);
ustream_printf(us, "\r\n", len);
}
char *uh_split_header(char *str)
{
char *val;
char *val;
val = strchr(str, ':');
if (!val)
return NULL;
val = strchr(str, ':');
if (!val)
return NULL;
*val = 0;
val++;
*val = 0;
val++;
while (isspace(*val))
val++;
while (isspace(*val))
val++;
return val;
return val;
}
/* 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. */
int uh_urldecode(char *buf, int blen, const char *src, int slen)
{
int i;
int len = 0;
int i;
int len = 0;
#define hex(x) \
(((x) <= '9') ? ((x) - '0') : \
(((x) <= 'F') ? ((x) - 'A' + 10) : \
((x) - 'a' + 10)))
(((x) <= '9') ? ((x) - '0') : \
(((x) <= 'F') ? ((x) - 'A' + 10) : \
((x) - 'a' + 10)))
for (i = 0; (i < slen) && (len < blen); i++)
{
if (src[i] != '%') {
buf[len++] = src[i];
continue;
}
for (i = 0; (i < slen) && (len < blen); i++)
{
if (src[i] != '%') {
buf[len++] = src[i];
continue;
}
if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2]))
return -2;
if (i + 2 >= slen || !isxdigit(src[i + 1]) || !isxdigit(src[i + 2]))
return -2;
buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
i += 2;
}
buf[len] = 0;
buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
i += 2;
}
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
@ -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) */
int uh_urlencode(char *buf, int blen, const char *src, int slen)
{
int i;
int len = 0;
static const char hex[] = "0123456789abcdef";
int i;
int len = 0;
static const char hex[] = "0123456789abcdef";
for (i = 0; (i < slen) && (len < blen); i++)
{
if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
(src[i] == '.') || (src[i] == '~') )
{
buf[len++] = src[i];
}
else if ((len+3) <= blen)
{
buf[len++] = '%';
buf[len++] = hex[(src[i] >> 4) & 15];
buf[len++] = hex[ src[i] & 15];
}
else
{
len = -1;
break;
}
}
for (i = 0; (i < slen) && (len < blen); i++)
{
if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
(src[i] == '.') || (src[i] == '~') )
{
buf[len++] = src[i];
}
else if ((len+3) <= blen)
{
buf[len++] = '%';
buf[len++] = hex[(src[i] >> 4) & 15];
buf[len++] = hex[ src[i] & 15];
}
else
{
len = -1;
break;
}
}
return (i == slen) ? len : -1;
return (i == slen) ? len : -1;
}
int find_idx(const char *const *list, int max, const char *str)