Optimize code and fix gzip encoding

Signed-off-by: zhaojh329 <zhaojh329@gmail.com>
main
zhaojh329 2020-09-07 10:03:32 +08:00 committed by Jianhui Zhao
parent 87a209c3b8
commit 28c8146740
5 changed files with 108 additions and 124 deletions

View File

@ -36,16 +36,18 @@ static const char *index_page = "index.html";
static void on_request(struct uh_connection *conn) static void on_request(struct uh_connection *conn)
{ {
if (!serve_file) { if (!serve_file) {
int body_len; const struct uh_str path = conn->get_path(conn);
const char *body = conn->get_body(conn, &body_len); 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->send_head(conn, HTTP_STATUS_OK, -1, NULL);
conn->chunk_printf(conn, "I'm Libuhttpd: %s\n", UHTTPD_VERSION_STRING); 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, "Method: %s\n", conn->get_method_str(conn));
conn->chunk_printf(conn, "Path: %s\n", conn->get_path(conn)); conn->chunk_printf(conn, "Path: %.*s\n", path.len ,path.p);
conn->chunk_printf(conn, "Query: %s\n", conn->get_query(conn)); conn->chunk_printf(conn, "Query: %.*s\n", query.len, query.p);
conn->chunk_printf(conn, "User-Agent: %s\n", conn->get_header(conn, "User-Agent")); conn->chunk_printf(conn, "User-Agent: %.*s\n", ua.len, ua.p);
conn->chunk_printf(conn, "Body: %.*s\n", body_len, body); conn->chunk_printf(conn, "Body: %.*s\n", body.len, body.p);
conn->chunk_end(conn); conn->chunk_end(conn);
} else { } else {
conn->serve_file(conn, docroot, index_page); conn->serve_file(conn, docroot, index_page);

View File

@ -169,75 +169,58 @@ static const char *conn_get_method_str(struct uh_connection *conn)
return http_method_str(conn->parser.method); return http_method_str(conn->parser.method);
} }
/* offset of the request field */ static const struct uh_str conn_get_path(struct uh_connection *conn)
#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)
{ {
struct http_parser_url *u = &conn->url_parser; struct http_parser_url *u = &conn->url_parser;
struct uh_request *req = &conn->req; struct uh_request *req = &conn->req;
struct uh_str path;
if (!req->url.path) path.p = req->url.p + u->field_data[UF_PATH].off;
req->url.path = strndup(O2D(conn, u->field_data[UF_PATH].off) + req->url.offset, u->field_data[UF_PATH].len); path.len = u->field_data[UF_PATH].len;
return req->url.path;
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 http_parser_url *u = &conn->url_parser;
struct uh_request *req = &conn->req; struct uh_request *req = &conn->req;
struct uh_str query = {};
if (!(u->field_set & (1 << UF_QUERY))) if (!(u->field_set & (1 << UF_QUERY)))
return ""; return query;
if (!req->url.query) query.p = req->url.p + u->field_data[UF_QUERY].off;
req->url.query = strndup(O2D(conn, u->field_data[UF_QUERY].off) + req->url.offset, u->field_data[UF_QUERY].len); 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; struct uh_request *req = &conn->req;
int name_len = strlen(name); 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++) { for (i = 0; i < UHTTPD_MAX_HEADER_NUM; i++) {
if (!req->headers[i].name) field = &req->headers[i].field;
break; if (!field->p)
if (!strcasecmp(req->headers[i].name, name)) return value;
return req->headers[i].value;
}
if (i == UHTTPD_MAX_HEADER_NUM) if (name_len == field->len && !strncasecmp(field->p, name, name_len)) {
return NULL; value.p = req->headers[i].value.p;
value.len = req->headers[i].value.len;
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;
}
} }
} }
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; return conn->req.body;
const char *at = O2D(conn, req->body.offset);
*len = req->body.len;
return at;
} }
static int on_message_begin_cb(struct http_parser *parser) 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; req->last_was_header_value = true;
http_parser_url_init(&conn->url_parser);
return 0; return 0;
} }
static int on_url_cb(struct http_parser *parser, const char *at, size_t length) 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_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) { if (!url->p)
req->url.offset = ROF(conn, at); url->p = at;
http_parser_url_init(&conn->url_parser); url->len += length;
}
req->url.length += length;
return 0; return 0;
} }
@ -279,10 +261,10 @@ static int on_header_field_cb(struct http_parser *parser, const char *at, size_t
return 1; 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; 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) { if (!req->last_was_header_value) {
req->last_was_header_value = true; 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; 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_connection *conn = (struct uh_connection *)parser->data;
struct uh_request *req = &conn->req; struct uh_request *req = &conn->req;
if (req->body.offset == 0) if (!req->body.p)
req->body.offset = ROF(conn, at); req->body.p = at;
req->body.len += length; req->body.len += length;
return 0; 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) static bool run_plugins(struct uh_connection *conn)
{ {
struct uh_plugin *p = conn->srv->plugins; struct uh_plugin *p = conn->srv->plugins;
struct uh_str path = conn->get_path(conn);
while (p) { 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); p->handler(conn);
return true; 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_connection *conn = (struct uh_connection *)parser->data;
struct uh_request *req = &conn->req; 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 (!run_plugins(conn)) {
if (conn->srv->on_request) 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)); 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)); memset(req, 0, sizeof(struct uh_request));
return 0; 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 (buffer_length(&conn->wb) == 0) {
if (conn->file.fd > 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 (ret < 0) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
uh_log_err("write error: %s\n", strerror(errno)); uh_log_err("write error: %s\n", strerror(errno));

View File

@ -41,31 +41,22 @@
struct uh_server; struct uh_server;
struct uh_request { struct uh_str {
struct { const char *p;
int length; size_t len;
int offset; };
char *path;
char *query; struct uh_request {
} url; 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; int header_num;
bool last_was_header_value; bool last_was_header_value;
struct { struct {
char *name; struct uh_str field;
char *value; struct uh_str value;
} headers[UHTTPD_MAX_HEADER_NUM]; } headers[UHTTPD_MAX_HEADER_NUM];
struct { struct uh_str body;
int offset;
int len;
} body;
}; };
struct uh_connection { struct uh_connection {
@ -107,10 +98,10 @@ struct uh_connection {
void (*chunk_end)(struct uh_connection *conn); void (*chunk_end)(struct uh_connection *conn);
enum http_method (*get_method)(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_method_str)(struct uh_connection *conn);
const char *(*get_path)(struct uh_connection *conn); const struct uh_str (*get_path)(struct uh_connection *conn);
const char *(*get_query)(struct uh_connection *conn); const struct uh_str (*get_query)(struct uh_connection *conn);
const char *(*get_header)(struct uh_connection *conn, const char *name); const struct uh_str (*get_header)(struct uh_connection *conn, const char *name);
const char *(*get_body)(struct uh_connection *conn, int *len); 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); struct uh_connection *uh_new_connection(struct uh_server *srv, int sock, struct sockaddr_in *addr);

View File

@ -32,11 +32,12 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include "connection.h" #include "connection.h"
#include "mimetypes.h" #include "mimetypes.h"
#include "log.h"
static const char *file_mktag(struct stat *s, char *buf, int len) 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; return buf;
} }
static time_t date2unix(const char *date) static time_t date2unix(const struct uh_str date)
{ {
struct tm t; struct tm t;
char buf[128] = "";
memset(&t, 0, sizeof(t)); 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 timegm(&t);
return 0; 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) static bool file_if_modified_since(struct uh_connection *conn, struct stat *s)
{ {
const char *hdr = conn->get_header(conn, "If-Modified-Since"); const struct uh_str hdr = conn->get_header(conn, "If-Modified-Since");
if (!hdr) if (!hdr.p)
return true; return true;
if (date2unix(hdr) >= s->st_mtime) { 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) 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); conn->error(conn, HTTP_STATUS_PRECONDITION_FAILED, NULL);
return false; 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) static bool file_if_unmodified_since(struct uh_connection *conn, struct stat *s)
{ {
const char *hdr = conn->get_header(conn, "If-Modified-Since"); const struct uh_str hdr = conn->get_header(conn, "If-Modified-Since");
if (hdr && date2unix(hdr) <= s->st_mtime) { if (hdr.p && date2unix(hdr) <= s->st_mtime) {
conn->error(conn, HTTP_STATUS_PRECONDITION_FAILED, NULL); conn->error(conn, HTTP_STATUS_PRECONDITION_FAILED, NULL);
return false; return false;
} }
@ -121,22 +126,37 @@ static bool file_if_unmodified_since(struct uh_connection *conn, struct stat *s)
return true; 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 struct uh_str hdr = conn->get_header(conn, "Accept-Encoding");
const char *extn = rindex(path, '.'); uint8_t magic[2] = {};
int fd;
if (!hdr || !strstr(hdr, "gzip")) if (!hdr.p || !memmem(hdr.p, hdr.len, "gzip", 4))
return; return;
if (extn && !strcmp(extn, ".gz")) if (strcmp(mime, "text/css") && strcmp(mime, "text/javascript") && strcmp(mime, "text/html"))
conn->printf(conn, "Content-Encoding: gzip\r\n"); 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) 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]; static char fullpath[512];
const char *mime;
struct stat st; struct stat st;
if (!docroot || !docroot[0]) if (!docroot || !docroot[0])
@ -147,12 +167,12 @@ void serve_file(struct uh_connection *conn, const char *docroot, const char *ind
strcpy(fullpath, docroot); strcpy(fullpath, docroot);
if (!strcmp(path, "/")) { if (!strncmp(path.p, "/", path.len)) {
strcat(fullpath, "/"); strcat(fullpath, "/");
path = index_page; strcat(fullpath, index_page);
} else {
strncat(fullpath, path.p, path.len);
} }
strcat(fullpath, path);
if (stat(fullpath, &st) < 0) { if (stat(fullpath, &st) < 0) {
int code; 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); conn->send_status_line(conn, HTTP_STATUS_OK, NULL);
file_response_ok_hdrs(conn, &st); 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); 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"); conn->printf(conn, "\r\n");

View File

@ -102,8 +102,8 @@ const char *file_mime_lookup(const char *path)
while (m->extn) { while (m->extn) {
e = &path[strlen(path)-1]; e = &path[strlen(path)-1];
while (e >= path) { while (e >= path && *e != '/') {
if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn)) if (*e == '.' && !strcasecmp(&e[1], m->extn))
return m->mime; return m->mime;
e--; e--;