parent
3aa5d2aeed
commit
2ab4ebc2f0
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
54
src/client.c
54
src/client.c
|
@ -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));
|
||||
|
|
32
src/client.h
32
src/client.h
|
@ -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;
|
||||
|
|
36
src/common.h
36
src/common.h
|
@ -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>
|
||||
|
||||
|
|
510
src/file.c
510
src/file.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
16
src/file.h
16
src/file.h
|
@ -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);
|
||||
|
|
84
src/uh_ssl.c
84
src/uh_ssl.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
150
src/utils.c
150
src/utils.c
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue