Optimize code and fix gzip encoding
Signed-off-by: zhaojh329 <zhaojh329@gmail.com>main
parent
87a209c3b8
commit
28c8146740
|
@ -36,16 +36,18 @@ static const char *index_page = "index.html";
|
|||
static void on_request(struct uh_connection *conn)
|
||||
{
|
||||
if (!serve_file) {
|
||||
int body_len;
|
||||
const char *body = conn->get_body(conn, &body_len);
|
||||
const struct uh_str path = conn->get_path(conn);
|
||||
const struct uh_str query = conn->get_query(conn);
|
||||
const struct uh_str ua = conn->get_header(conn, "User-Agent");
|
||||
const struct uh_str body = conn->get_body(conn);
|
||||
|
||||
conn->send_head(conn, HTTP_STATUS_OK, -1, NULL);
|
||||
conn->chunk_printf(conn, "I'm Libuhttpd: %s\n", UHTTPD_VERSION_STRING);
|
||||
conn->chunk_printf(conn, "Method: %s\n", conn->get_method_str(conn));
|
||||
conn->chunk_printf(conn, "Path: %s\n", conn->get_path(conn));
|
||||
conn->chunk_printf(conn, "Query: %s\n", conn->get_query(conn));
|
||||
conn->chunk_printf(conn, "User-Agent: %s\n", conn->get_header(conn, "User-Agent"));
|
||||
conn->chunk_printf(conn, "Body: %.*s\n", body_len, body);
|
||||
conn->chunk_printf(conn, "Path: %.*s\n", path.len ,path.p);
|
||||
conn->chunk_printf(conn, "Query: %.*s\n", query.len, query.p);
|
||||
conn->chunk_printf(conn, "User-Agent: %.*s\n", ua.len, ua.p);
|
||||
conn->chunk_printf(conn, "Body: %.*s\n", body.len, body.p);
|
||||
conn->chunk_end(conn);
|
||||
} else {
|
||||
conn->serve_file(conn, docroot, index_page);
|
||||
|
|
113
src/connection.c
113
src/connection.c
|
@ -169,75 +169,58 @@ static const char *conn_get_method_str(struct uh_connection *conn)
|
|||
return http_method_str(conn->parser.method);
|
||||
}
|
||||
|
||||
/* offset of the request field */
|
||||
#define ROF(c, a) (a - (const char *)c->rb.data)
|
||||
|
||||
/* data of the request field */
|
||||
#define O2D(c, o) ((const char *)c->rb.data + o)
|
||||
|
||||
static const char *conn_get_path(struct uh_connection *conn)
|
||||
static const struct uh_str conn_get_path(struct uh_connection *conn)
|
||||
{
|
||||
struct http_parser_url *u = &conn->url_parser;
|
||||
struct uh_request *req = &conn->req;
|
||||
struct uh_str path;
|
||||
|
||||
if (!req->url.path)
|
||||
req->url.path = strndup(O2D(conn, u->field_data[UF_PATH].off) + req->url.offset, u->field_data[UF_PATH].len);
|
||||
return req->url.path;
|
||||
path.p = req->url.p + u->field_data[UF_PATH].off;
|
||||
path.len = u->field_data[UF_PATH].len;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static const char *conn_get_query(struct uh_connection *conn)
|
||||
static const struct uh_str conn_get_query(struct uh_connection *conn)
|
||||
{
|
||||
struct http_parser_url *u = &conn->url_parser;
|
||||
struct uh_request *req = &conn->req;
|
||||
struct uh_str query = {};
|
||||
|
||||
if (!(u->field_set & (1 << UF_QUERY)))
|
||||
return "";
|
||||
return query;
|
||||
|
||||
if (!req->url.query)
|
||||
req->url.query = strndup(O2D(conn, u->field_data[UF_QUERY].off) + req->url.offset, u->field_data[UF_QUERY].len);
|
||||
query.p = req->url.p + u->field_data[UF_QUERY].off;
|
||||
query.len = u->field_data[UF_QUERY].len;
|
||||
|
||||
return req->url.query;
|
||||
return query;
|
||||
}
|
||||
|
||||
static const char *conn_get_header(struct uh_connection *conn, const char *name)
|
||||
static const struct uh_str conn_get_header(struct uh_connection *conn, const char *name)
|
||||
{
|
||||
struct uh_request *req = &conn->req;
|
||||
int name_len = strlen(name);
|
||||
int i, j;
|
||||
struct uh_str *field;
|
||||
struct uh_str value = {};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < UHTTPD_MAX_HEADER_NUM; i++) {
|
||||
if (!req->headers[i].name)
|
||||
break;
|
||||
if (!strcasecmp(req->headers[i].name, name))
|
||||
return req->headers[i].value;
|
||||
}
|
||||
field = &req->headers[i].field;
|
||||
if (!field->p)
|
||||
return value;
|
||||
|
||||
if (i == UHTTPD_MAX_HEADER_NUM)
|
||||
return NULL;
|
||||
|
||||
for (j = 0; j < UHTTPD_MAX_HEADER_NUM; j++) {
|
||||
if (req->headers_info[j].name_offset > 0) {
|
||||
const char *p = O2D(conn, req->headers_info[j].name_offset);
|
||||
if (name_len == req->headers_info[j].name_len && !strncasecmp(p, name, req->headers_info[j].name_len)) {
|
||||
req->headers[i].name = strndup(p, req->headers_info[j].name_len);
|
||||
req->headers[i].value = strndup(O2D(conn, req->headers_info[j].value_offset), req->headers_info[j].value_len);
|
||||
req->headers_info[j].name_len = 0;
|
||||
return req->headers[i].value;
|
||||
}
|
||||
if (name_len == field->len && !strncasecmp(field->p, name, name_len)) {
|
||||
value.p = req->headers[i].value.p;
|
||||
value.len = req->headers[i].value.len;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return value;
|
||||
}
|
||||
|
||||
static const char *conn_get_body(struct uh_connection *conn, int *len)
|
||||
static const struct uh_str conn_get_body(struct uh_connection *conn)
|
||||
{
|
||||
struct uh_request *req = &conn->req;
|
||||
const char *at = O2D(conn, req->body.offset);
|
||||
|
||||
*len = req->body.len;
|
||||
|
||||
return at;
|
||||
return conn->req.body;
|
||||
}
|
||||
|
||||
static int on_message_begin_cb(struct http_parser *parser)
|
||||
|
@ -247,20 +230,19 @@ static int on_message_begin_cb(struct http_parser *parser)
|
|||
|
||||
req->last_was_header_value = true;
|
||||
|
||||
http_parser_url_init(&conn->url_parser);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_url_cb(struct http_parser *parser, const char *at, size_t length)
|
||||
{
|
||||
struct uh_connection *conn = (struct uh_connection *)parser->data;
|
||||
struct uh_request *req = &conn->req;
|
||||
struct uh_str *url = &conn->req.url;
|
||||
|
||||
if (req->url.offset == 0) {
|
||||
req->url.offset = ROF(conn, at);
|
||||
http_parser_url_init(&conn->url_parser);
|
||||
}
|
||||
|
||||
req->url.length += length;
|
||||
if (!url->p)
|
||||
url->p = at;
|
||||
url->len += length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -279,10 +261,10 @@ static int on_header_field_cb(struct http_parser *parser, const char *at, size_t
|
|||
return 1;
|
||||
}
|
||||
|
||||
req->headers_info[req->header_num - 1].name_offset = ROF(conn, at);
|
||||
req->headers[req->header_num - 1].field.p = at;
|
||||
}
|
||||
|
||||
req->headers_info[req->header_num - 1].name_len += length;
|
||||
req->headers[req->header_num - 1].field.len += length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -294,10 +276,10 @@ static int on_header_value_cb(struct http_parser *parser, const char *at, size_t
|
|||
|
||||
if (!req->last_was_header_value) {
|
||||
req->last_was_header_value = true;
|
||||
req->headers_info[req->header_num - 1].value_offset = ROF(conn, at);
|
||||
req->headers[req->header_num - 1].value.p = at;
|
||||
}
|
||||
|
||||
req->headers_info[req->header_num - 1].value_len += length;
|
||||
req->headers[req->header_num - 1].value.len += length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -307,8 +289,8 @@ static int on_body_cb(struct http_parser *parser, const char *at, size_t length)
|
|||
struct uh_connection *conn = (struct uh_connection *)parser->data;
|
||||
struct uh_request *req = &conn->req;
|
||||
|
||||
if (req->body.offset == 0)
|
||||
req->body.offset = ROF(conn, at);
|
||||
if (!req->body.p)
|
||||
req->body.p = at;
|
||||
req->body.len += length;
|
||||
|
||||
return 0;
|
||||
|
@ -317,9 +299,10 @@ static int on_body_cb(struct http_parser *parser, const char *at, size_t length)
|
|||
static bool run_plugins(struct uh_connection *conn)
|
||||
{
|
||||
struct uh_plugin *p = conn->srv->plugins;
|
||||
struct uh_str path = conn->get_path(conn);
|
||||
|
||||
while (p) {
|
||||
if (!strcmp(conn->get_path(conn), p->path)) {
|
||||
if (strlen(p->path) == path.len && !strncmp(path.p, p->path, path.len)) {
|
||||
p->handler(conn);
|
||||
return true;
|
||||
}
|
||||
|
@ -332,9 +315,8 @@ static int on_message_complete_cb(struct http_parser *parser)
|
|||
{
|
||||
struct uh_connection *conn = (struct uh_connection *)parser->data;
|
||||
struct uh_request *req = &conn->req;
|
||||
int i;
|
||||
|
||||
http_parser_parse_url(O2D(conn, req->url.offset), req->url.length, false, &conn->url_parser);
|
||||
http_parser_parse_url(req->url.p, req->url.len, false, &conn->url_parser);
|
||||
|
||||
if (!run_plugins(conn)) {
|
||||
if (conn->srv->on_request)
|
||||
|
@ -345,19 +327,6 @@ static int on_message_complete_cb(struct http_parser *parser)
|
|||
|
||||
buffer_pull(&conn->rb, NULL, buffer_length(&conn->rb));
|
||||
|
||||
if (req->url.path)
|
||||
free(req->url.path);
|
||||
|
||||
if (req->url.query)
|
||||
free(req->url.query);
|
||||
|
||||
for (i = 0; i < UHTTPD_MAX_HEADER_NUM; i++) {
|
||||
if (req->headers[i].name)
|
||||
free(req->headers[i].name);
|
||||
if (req->headers[i].value)
|
||||
free(req->headers[i].value);
|
||||
}
|
||||
|
||||
memset(req, 0, sizeof(struct uh_request));
|
||||
|
||||
return 0;
|
||||
|
@ -441,7 +410,7 @@ static void conn_write_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
|||
|
||||
if (buffer_length(&conn->wb) == 0) {
|
||||
if (conn->file.fd > 0) {
|
||||
ssize_t ret = sendfile(w->fd, conn->file.fd, NULL, conn->file.size);
|
||||
ret = sendfile(w->fd, conn->file.fd, NULL, conn->file.size);
|
||||
if (ret < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
uh_log_err("write error: %s\n", strerror(errno));
|
||||
|
|
|
@ -41,31 +41,22 @@
|
|||
|
||||
struct uh_server;
|
||||
|
||||
struct uh_request {
|
||||
struct {
|
||||
int length;
|
||||
int offset;
|
||||
char *path;
|
||||
char *query;
|
||||
} url;
|
||||
struct uh_str {
|
||||
const char *p;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct uh_request {
|
||||
struct uh_str url;
|
||||
|
||||
struct {
|
||||
int name_offset;
|
||||
int name_len;
|
||||
int value_offset;
|
||||
int value_len;
|
||||
} headers_info[UHTTPD_MAX_HEADER_NUM];
|
||||
int header_num;
|
||||
bool last_was_header_value;
|
||||
struct {
|
||||
char *name;
|
||||
char *value;
|
||||
struct uh_str field;
|
||||
struct uh_str value;
|
||||
} headers[UHTTPD_MAX_HEADER_NUM];
|
||||
|
||||
struct {
|
||||
int offset;
|
||||
int len;
|
||||
} body;
|
||||
struct uh_str body;
|
||||
};
|
||||
|
||||
struct uh_connection {
|
||||
|
@ -107,10 +98,10 @@ struct uh_connection {
|
|||
void (*chunk_end)(struct uh_connection *conn);
|
||||
enum http_method (*get_method)(struct uh_connection *conn);
|
||||
const char *(*get_method_str)(struct uh_connection *conn);
|
||||
const char *(*get_path)(struct uh_connection *conn);
|
||||
const char *(*get_query)(struct uh_connection *conn);
|
||||
const char *(*get_header)(struct uh_connection *conn, const char *name);
|
||||
const char *(*get_body)(struct uh_connection *conn, int *len);
|
||||
const struct uh_str (*get_path)(struct uh_connection *conn);
|
||||
const struct uh_str (*get_query)(struct uh_connection *conn);
|
||||
const struct uh_str (*get_header)(struct uh_connection *conn, const char *name);
|
||||
const struct uh_str (*get_body)(struct uh_connection *conn);
|
||||
};
|
||||
|
||||
struct uh_connection *uh_new_connection(struct uh_server *srv, int sock, struct sockaddr_in *addr);
|
||||
|
|
64
src/file.c
64
src/file.c
|
@ -32,11 +32,12 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "connection.h"
|
||||
#include "mimetypes.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
static const char *file_mktag(struct stat *s, char *buf, int len)
|
||||
{
|
||||
|
@ -55,13 +56,16 @@ static char *unix2date(time_t ts, char *buf, int len)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static time_t date2unix(const char *date)
|
||||
static time_t date2unix(const struct uh_str date)
|
||||
{
|
||||
struct tm t;
|
||||
char buf[128] = "";
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
if (strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL)
|
||||
strncpy(buf, date.p, date.len);
|
||||
|
||||
if (strptime(buf, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL)
|
||||
return timegm(&t);
|
||||
|
||||
return 0;
|
||||
|
@ -88,8 +92,8 @@ static void file_response_304(struct uh_connection *conn, struct stat *s)
|
|||
|
||||
static bool file_if_modified_since(struct uh_connection *conn, struct stat *s)
|
||||
{
|
||||
const char *hdr = conn->get_header(conn, "If-Modified-Since");
|
||||
if (!hdr)
|
||||
const struct uh_str hdr = conn->get_header(conn, "If-Modified-Since");
|
||||
if (!hdr.p)
|
||||
return true;
|
||||
|
||||
if (date2unix(hdr) >= s->st_mtime) {
|
||||
|
@ -102,7 +106,8 @@ static bool file_if_modified_since(struct uh_connection *conn, struct stat *s)
|
|||
|
||||
static bool file_if_range(struct uh_connection *conn, struct stat *s)
|
||||
{
|
||||
if (conn->get_header(conn, "If-Range")) {
|
||||
const struct uh_str hdr = conn->get_header(conn, "If-Range");
|
||||
if (hdr.p) {
|
||||
conn->error(conn, HTTP_STATUS_PRECONDITION_FAILED, NULL);
|
||||
return false;
|
||||
}
|
||||
|
@ -112,8 +117,8 @@ static bool file_if_range(struct uh_connection *conn, struct stat *s)
|
|||
|
||||
static bool file_if_unmodified_since(struct uh_connection *conn, struct stat *s)
|
||||
{
|
||||
const char *hdr = conn->get_header(conn, "If-Modified-Since");
|
||||
if (hdr && date2unix(hdr) <= s->st_mtime) {
|
||||
const struct uh_str hdr = conn->get_header(conn, "If-Modified-Since");
|
||||
if (hdr.p && date2unix(hdr) <= s->st_mtime) {
|
||||
conn->error(conn, HTTP_STATUS_PRECONDITION_FAILED, NULL);
|
||||
return false;
|
||||
}
|
||||
|
@ -121,22 +126,37 @@ static bool file_if_unmodified_since(struct uh_connection *conn, struct stat *s)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void file_if_gzip(struct uh_connection *conn, const char *path)
|
||||
static void file_if_gzip(struct uh_connection *conn, const char *path, const char *mime)
|
||||
{
|
||||
const char *hdr = conn->get_header(conn, "Accept-Encoding");
|
||||
const char *extn = rindex(path, '.');
|
||||
const struct uh_str hdr = conn->get_header(conn, "Accept-Encoding");
|
||||
uint8_t magic[2] = {};
|
||||
int fd;
|
||||
|
||||
if (!hdr || !strstr(hdr, "gzip"))
|
||||
if (!hdr.p || !memmem(hdr.p, hdr.len, "gzip", 4))
|
||||
return;
|
||||
|
||||
if (extn && !strcmp(extn, ".gz"))
|
||||
conn->printf(conn, "Content-Encoding: gzip\r\n");
|
||||
if (strcmp(mime, "text/css") && strcmp(mime, "text/javascript") && strcmp(mime, "text/html"))
|
||||
return;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (read(fd, magic, 2) != 2) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* gzip magic */
|
||||
if (magic[0] != 0x1f || magic[1] != 0x8b)
|
||||
return;
|
||||
|
||||
conn->printf(conn, "Content-Encoding: gzip\r\n");
|
||||
}
|
||||
|
||||
void serve_file(struct uh_connection *conn, const char *docroot, const char *index_page)
|
||||
{
|
||||
const char *path = conn->get_path(conn);
|
||||
const struct uh_str path = conn->get_path(conn);
|
||||
static char fullpath[512];
|
||||
const char *mime;
|
||||
struct stat st;
|
||||
|
||||
if (!docroot || !docroot[0])
|
||||
|
@ -147,12 +167,12 @@ void serve_file(struct uh_connection *conn, const char *docroot, const char *ind
|
|||
|
||||
strcpy(fullpath, docroot);
|
||||
|
||||
if (!strcmp(path, "/")) {
|
||||
if (!strncmp(path.p, "/", path.len)) {
|
||||
strcat(fullpath, "/");
|
||||
path = index_page;
|
||||
strcat(fullpath, index_page);
|
||||
} else {
|
||||
strncat(fullpath, path.p, path.len);
|
||||
}
|
||||
|
||||
strcat(fullpath, path);
|
||||
|
||||
if (stat(fullpath, &st) < 0) {
|
||||
int code;
|
||||
|
@ -196,10 +216,12 @@ void serve_file(struct uh_connection *conn, const char *docroot, const char *ind
|
|||
conn->send_status_line(conn, HTTP_STATUS_OK, NULL);
|
||||
file_response_ok_hdrs(conn, &st);
|
||||
|
||||
conn->printf(conn, "Content-Type: %s\r\n", file_mime_lookup(path));
|
||||
mime = file_mime_lookup(fullpath);
|
||||
|
||||
conn->printf(conn, "Content-Type: %s\r\n", mime);
|
||||
conn->printf(conn, "Content-Length: %" PRIu64 "\r\n", st.st_size);
|
||||
|
||||
file_if_gzip(conn, path);
|
||||
file_if_gzip(conn, fullpath, mime);
|
||||
|
||||
conn->printf(conn, "\r\n");
|
||||
|
||||
|
|
|
@ -102,8 +102,8 @@ const char *file_mime_lookup(const char *path)
|
|||
while (m->extn) {
|
||||
e = &path[strlen(path)-1];
|
||||
|
||||
while (e >= path) {
|
||||
if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
|
||||
while (e >= path && *e != '/') {
|
||||
if (*e == '.' && !strcasecmp(&e[1], m->extn))
|
||||
return m->mime;
|
||||
|
||||
e--;
|
||||
|
|
Loading…
Reference in New Issue