Skip to content

Commit

Permalink
perf: support path info
Browse files Browse the repository at this point in the history
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
  • Loading branch information
zhaojh329 committed Aug 25, 2021
1 parent a0fa330 commit 60c9c78
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 25 deletions.
94 changes: 69 additions & 25 deletions src/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,68 @@
#include "utils.h"
#include "file.h"

struct path_info *parse_path_info(struct uh_connection_internal *conn)
{
struct uh_server_internal *srv = conn->srv;
struct uh_str path = conn->com.get_path(&conn->com);
const char *docroot = srv->docroot;
const char *index_page = srv->index_page;
static char buf[PATH_MAX];
static char path_phys[PATH_MAX];
static char path_info[PATH_MAX];
static struct path_info pi = {};
int docroot_len, i;

if (!docroot || !docroot[0])
docroot = ".";

docroot_len = strlen(docroot);

if (docroot[docroot_len - 1] == '/')
docroot_len--;

if (!index_page || !index_page[0])
index_page = "index.html";

memcpy(buf, docroot, docroot_len);

if (path.len == 1) {
buf[docroot_len] = '/';
strcpy(buf + docroot_len + 1, index_page);
} else if (urldecode(buf + docroot_len, PATH_MAX - docroot_len, path.p, path.len) < 0) {
return NULL;
}

for (i = strlen(buf); i > docroot_len; i--) {
char ch = buf[i];

if (ch != '\0' && ch != '/')
continue;

memcpy(path_phys, buf, i);
path_phys[i] = '\0';

if (access(path_phys, F_OK))
continue;

snprintf(path_info, sizeof(path_info), "%s", buf + i);
break;
}

if (i > docroot_len) {
pi.phys = path_phys;
pi.name = &path_phys[docroot_len];
} else {
pi.phys = buf;
pi.name = &buf[docroot_len];
}

pi.root = docroot;
pi.info = path_info;

return &pi;
}

static const char *file_mktag(struct stat *s, char *buf, int len)
{
snprintf(buf, len, "\"%" PRIx64 "-%" PRIx64 "-%" PRIx64 "\"",
Expand Down Expand Up @@ -253,36 +315,18 @@ static bool file_range(struct uh_connection *conn, uint64_t size, uint64_t *star
void serve_file(struct uh_connection *conn)
{
struct uh_connection_internal *conni = (struct uh_connection_internal *)conn;
const struct uh_str path = conn->get_path(conn);
struct uh_server_internal *srv = conni->srv;
const char *docroot = srv->docroot;
const char *index_page = srv->index_page;
static char fullpath[PATH_MAX];
struct path_info *pi = parse_path_info(conni);
uint64_t start, end;
int docroot_len;
const char *mime;
struct stat st;
bool ranged;

if (!docroot || !docroot[0])
docroot = ".";

if (!index_page || !index_page[0])
index_page = "index.html";

docroot_len = strlen(docroot);

memcpy(fullpath, docroot, docroot_len);

if (!strncmp(path.p, "/", path.len)) {
fullpath[docroot_len] = '/';
strcpy(fullpath + docroot_len + 1, index_page);
} else if (urldecode(fullpath + docroot_len, PATH_MAX - docroot_len, path.p, path.len) < 0) {
conn->error(conn, HTTP_STATUS_NOT_FOUND, NULL);
if (!pi) {
conn->error(conn, HTTP_STATUS_BAD_REQUEST, NULL);
return;
}

if (stat(fullpath, &st) < 0) {
if (stat(pi->phys, &st) < 0) {
int code;

switch (errno) {
Expand Down Expand Up @@ -331,22 +375,22 @@ void serve_file(struct uh_connection *conn)

file_response_ok_hdrs(conn, &st);

mime = file_mime_lookup(fullpath);
mime = file_mime_lookup(pi->phys);

conn->printf(conn, "Content-Type: %s\r\n", mime);
conn->printf(conn, "Content-Length: %" PRIu64 "\r\n", end - start + 1);

if (ranged)
conn->printf(conn, "Content-Range: bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64 "\r\n", start, end, (uint64_t)st.st_size);
else
file_if_gzip(conn, fullpath, mime);
file_if_gzip(conn, pi->phys, mime);

conn->printf(conn, "\r\n");

if (conn->get_method(conn) == HTTP_HEAD)
return;

conn->send_file(conn, fullpath, start, end - start + 1);
conn->send_file(conn, pi->phys, start, end - start + 1);

conn->done(conn);
}
11 changes: 11 additions & 0 deletions src/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,19 @@
#ifndef LIBUHTTPD_FILE_H
#define LIBUHTTPD_FILE_H

#include <sys/stat.h>

#include "connection.h"

struct path_info {
const char *root;
const char *phys;
const char *name;
const char *info;
};

struct path_info *parse_path_info(struct uh_connection_internal *conn);

void serve_file(struct uh_connection *conn);

#endif

0 comments on commit 60c9c78

Please sign in to comment.