Index: filed.c
==================================================================
--- filed.c
+++ filed.c
@@ -74,10 +74,16 @@
FILED_REQUEST_METHOD_HEAD
} method;
/*** Path being requested ***/
char path[FILED_PATH_BUFFER_SIZE];
+
+ /*** Path type ***/
+ enum {
+ FILED_REQUEST_TYPE_DIRECTORY,
+ FILED_REQUEST_TYPE_OTHER
+ } type;
struct {
struct {
int present;
off_t offset; /*** Range start ***/
@@ -632,11 +638,11 @@
/* Process an HTTP request and return the path requested */
static struct filed_http_request *filed_get_http_request(FILE *fp, struct filed_http_request *buffer_st, struct filed_options *options) {
char *method, *path;
char *buffer, *workbuffer, *workbuffer_next;
char *fgets_ret;
- size_t buffer_len;
+ size_t buffer_len, path_len;
off_t range_start, range_end, range_length;
int range_request;
int snprintf_ret;
int i;
@@ -686,11 +692,23 @@
/* HEAD request */
buffer_st->method = FILED_REQUEST_METHOD_HEAD;
}
/* Note path */
- strcpy(buffer_st->path, path);
+ path_len = strlen(path);
+ memcpy(buffer_st->path, path, path_len + 1);
+
+ /* Determine type of request from path */
+ if (path_len == 0) {
+ buffer_st->type = FILED_REQUEST_TYPE_DIRECTORY;
+ } else {
+ if (path[path_len - 1] == '/') {
+ buffer_st->type = FILED_REQUEST_TYPE_DIRECTORY;
+ } else {
+ buffer_st->type = FILED_REQUEST_TYPE_OTHER;
+ }
+ }
/* Reset buffer for later use */
buffer = buffer_st->tmpbuf;
for (i = 0; i < 100; i++) {
@@ -781,11 +799,11 @@
return(buffer_st);
}
/* Return an error page */
-static void filed_error_page(FILE *fp, const char *date_current, int error_number, int method) {
+static void filed_error_page(FILE *fp, const char *date_current, int error_number, int method, const char *reason, struct filed_log_entry *log) {
char *error_string = "
ERRORUnable to process request";
fprintf(fp, "HTTP/1.1 %i Not OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: %llu\r\nContent-Type: %s\r\nConnection: close\r\n\r\n",
error_number,
date_current,
@@ -797,11 +815,46 @@
/* silence error string for HEAD requests */
if (method != FILED_REQUEST_METHOD_HEAD) {
fprintf(fp, "%s", error_string);
}
+ /* Log error */
+ /** reason must point to a globally allocated value **/
+ log->reason = reason;
+ log->http_code = error_number;
+
+ filed_log_entry(log);
+
+ /* Close connection */
+ fclose(fp);
+
+ return;
+}
+
+/* Return a redirect to index.html */
+static void filed_redirect_index(FILE *fp, const char *date_current, const char *path, struct filed_log_entry *log) {
+ int http_code = 301;
+ fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: 0\r\nConnection: close\r\nLocation: %s\r\n\r\n",
+ http_code,
+ date_current,
+ date_current,
+ "index.html"
+ );
+
+ /* Log redirect */
+ log->reason = "redirect";
+ log->http_code = http_code;
+
+ filed_log_entry(log);
+
+ /* Close connection */
+ fclose(fp);
+
return;
+
+ /* Currently unused: path */
+ path = path;
}
/* Handle a single request from a client */
static void filed_handle_client(int fd, struct filed_http_request *request, struct filed_log_entry *log, struct filed_options *options) {
struct filed_fileinfo *fileinfo;
@@ -831,173 +884,167 @@
}
request = filed_get_http_request(fp, request, options);
if (request == NULL) {
- filed_error_page(fp, date_current, 500, FILED_REQUEST_METHOD_GET);
-
log->buffer[0] = '\0';
- log->http_code = 500;
- log->reason = "format";
- filed_log_entry(log);
-
- fclose(fp);
+ filed_error_page(fp, date_current, 500, FILED_REQUEST_METHOD_GET, "format", log);
return;
}
path = request->path;
strcpy(log->buffer, path);
log->method = request->method;
- http_code = -1;
-
- fileinfo = filed_open_file(path, &request->fileinfo);
- if (fileinfo == NULL) {
- filed_error_page(fp, date_current, 404, request->method);
-
- log->http_code = 404;
- log->reason = "open_failed";
-
- filed_log_entry(log);
- } else {
- if (request->headers.range.offset != 0 || request->headers.range.length >= 0) {
- if (request->headers.range.offset >= fileinfo->len) {
- filed_error_page(fp, date_current, 416, request->method);
-
- log->http_code = 416;
- log->reason = "range_invalid";
-
- filed_log_entry(log);
- } else {
- if (request->headers.range.length == ((off_t) -1)) {
- filed_log_msg_debug("Computing length to fit in bounds: fileinfo->len = %llu, request->headers.range.offset = %llu",
- (unsigned long long) fileinfo->len,
- (unsigned long long) request->headers.range.offset
- );
-
- request->headers.range.length = fileinfo->len - request->headers.range.offset;
- }
-
- filed_log_msg_debug("Partial request, starting at: %llu and running for %lli bytes",
- (unsigned long long) request->headers.range.offset,
- (long long) request->headers.range.length
- );
-
- http_code = 206;
- }
- } else {
- if (request->headers.range.present) {
- http_code = 206;
- } else {
- http_code = 200;
- }
- request->headers.range.offset = 0;
- request->headers.range.length = fileinfo->len;
- }
-
- if (http_code > 0) {
- fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: %llu\r\nAccept-Ranges: bytes\r\nContent-Type: %s\r\nConnection: close\r\nETag: \"%s\"\r\n",
- http_code,
- date_current,
- fileinfo->lastmod,
- (unsigned long long) request->headers.range.length,
- fileinfo->type,
- fileinfo->etag
- );
- if (http_code == 206) {
- fprintf(fp, "Content-Range: bytes %llu-%llu/%llu\r\n",
- (unsigned long long) request->headers.range.offset,
- (unsigned long long) (request->headers.range.offset + request->headers.range.length - 1),
- (unsigned long long) fileinfo->len
- );
- }
- fprintf(fp, "\r\n");
- fflush(fp);
-
- log->http_code = http_code;
- log->reason = "OK";
- log->starttime = time(NULL);
- log->req_offset = request->headers.range.offset;
- log->req_length = request->headers.range.length;
- log->file_length = fileinfo->len;
-
-#ifdef FILED_NONBLOCK_HTTP
- int socket_flags;
- fd_set rfd, wfd;
- char sinkbuf[8192];
- ssize_t read_ret;
-
- FD_ZERO(&rfd);
- FD_ZERO(&wfd);
- FD_SET(fd, &rfd);
- FD_SET(fd, &wfd);
-
- socket_flags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, socket_flags | O_NONBLOCK);
-#endif
-
- sendfile_offset = request->headers.range.offset;
- sendfile_len = request->headers.range.length;
- sendfile_sent = 0;
- while (request->method == FILED_REQUEST_METHOD_GET) {
- if (sendfile_len > FILED_SENDFILE_MAX) {
- sendfile_size = FILED_SENDFILE_MAX;
- } else {
- sendfile_size = sendfile_len;
- }
-
- sendfile_ret = sendfile(fd, fileinfo->fd, &sendfile_offset, sendfile_size);
- if (sendfile_ret <= 0) {
-#ifdef FILED_NONBLOCK_HTTP
- if (errno == EAGAIN) {
- sendfile_ret = 0;
-
- while (1) {
- select(fd + 1, &rfd, &wfd, NULL, NULL);
- if (FD_ISSET(fd, &rfd)) {
- read_ret = read(fd, sinkbuf, sizeof(sinkbuf));
-
- if (read_ret <= 0) {
- break;
- }
- }
-
- if (FD_ISSET(fd, &wfd)) {
- read_ret = 1;
-
- break;
- }
- }
-
- if (read_ret <= 0) {
- break;
- }
- } else {
- break;
- }
-#else
- break;
-#endif
- }
-
- sendfile_len -= sendfile_ret;
- sendfile_sent += sendfile_ret;
- if (sendfile_len == 0) {
- break;
- }
- }
-
- log->endtime = (time_t) -1;
- log->sent_length = sendfile_sent;
-
- filed_log_entry(log);
- }
-
- close(fileinfo->fd);
- }
+ /* If the requested path is a directory, redirect to index page */
+ if (request->type == FILED_REQUEST_TYPE_DIRECTORY) {
+ filed_redirect_index(fp, date_current, path, log);
+
+ return;
+ }
+
+ fileinfo = filed_open_file(path, &request->fileinfo);
+ if (fileinfo == NULL) {
+ filed_error_page(fp, date_current, 404, request->method, "open_failed", log);
+
+ return;
+ }
+
+ if (request->headers.range.present) {
+ if (request->headers.range.offset != 0 || request->headers.range.length >= 0) {
+ if (request->headers.range.offset >= fileinfo->len) {
+ filed_error_page(fp, date_current, 416, request->method, "range_invalid", log);
+
+ close(fileinfo->fd);
+
+ return;
+ }
+
+ if (request->headers.range.length == ((off_t) -1)) {
+ filed_log_msg_debug("Computing length to fit in bounds: fileinfo->len = %llu, request->headers.range.offset = %llu",
+ (unsigned long long) fileinfo->len,
+ (unsigned long long) request->headers.range.offset
+ );
+
+ request->headers.range.length = fileinfo->len - request->headers.range.offset;
+ }
+
+ filed_log_msg_debug("Partial request, starting at: %llu and running for %lli bytes",
+ (unsigned long long) request->headers.range.offset,
+ (long long) request->headers.range.length
+ );
+
+ }
+
+ http_code = 206;
+ } else {
+ http_code = 200;
+
+ /* Compute fake range parameters that includes the entire file */
+ request->headers.range.offset = 0;
+ request->headers.range.length = fileinfo->len;
+ }
+
+ fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: %llu\r\nAccept-Ranges: bytes\r\nContent-Type: %s\r\nConnection: close\r\nETag: \"%s\"\r\n",
+ http_code,
+ date_current,
+ fileinfo->lastmod,
+ (unsigned long long) request->headers.range.length,
+ fileinfo->type,
+ fileinfo->etag
+ );
+
+ if (http_code == 206) {
+ fprintf(fp, "Content-Range: bytes %llu-%llu/%llu\r\n",
+ (unsigned long long) request->headers.range.offset,
+ (unsigned long long) (request->headers.range.offset + request->headers.range.length - 1),
+ (unsigned long long) fileinfo->len
+ );
+ }
+ fprintf(fp, "\r\n");
+ fflush(fp);
+
+ log->http_code = http_code;
+ log->reason = "OK";
+ log->starttime = time(NULL);
+ log->req_offset = request->headers.range.offset;
+ log->req_length = request->headers.range.length;
+ log->file_length = fileinfo->len;
+
+#ifdef FILED_NONBLOCK_HTTP
+ int socket_flags;
+ fd_set rfd, wfd;
+ char sinkbuf[8192];
+ ssize_t read_ret;
+
+ FD_ZERO(&rfd);
+ FD_ZERO(&wfd);
+ FD_SET(fd, &rfd);
+ FD_SET(fd, &wfd);
+
+ socket_flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, socket_flags | O_NONBLOCK);
+#endif
+ sendfile_offset = request->headers.range.offset;
+ sendfile_len = request->headers.range.length;
+ sendfile_sent = 0;
+ while (request->method == FILED_REQUEST_METHOD_GET) {
+ if (sendfile_len > FILED_SENDFILE_MAX) {
+ sendfile_size = FILED_SENDFILE_MAX;
+ } else {
+ sendfile_size = sendfile_len;
+ }
+
+ sendfile_ret = sendfile(fd, fileinfo->fd, &sendfile_offset, sendfile_size);
+ if (sendfile_ret <= 0) {
+#ifdef FILED_NONBLOCK_HTTP
+ if (errno == EAGAIN) {
+ sendfile_ret = 0;
+
+ while (1) {
+ select(fd + 1, &rfd, &wfd, NULL, NULL);
+ if (FD_ISSET(fd, &rfd)) {
+ read_ret = read(fd, sinkbuf, sizeof(sinkbuf));
+
+ if (read_ret <= 0) {
+ break;
+ }
+ }
+
+ if (FD_ISSET(fd, &wfd)) {
+ read_ret = 1;
+
+ break;
+ }
+ }
+
+ if (read_ret <= 0) {
+ break;
+ }
+ } else {
+ break;
+ }
+#else
+ break;
+#endif
+ }
+
+ sendfile_len -= sendfile_ret;
+ sendfile_sent += sendfile_ret;
+ if (sendfile_len == 0) {
+ break;
+ }
+ }
+
+ log->endtime = (time_t) -1;
+ log->sent_length = sendfile_sent;
+
+ filed_log_entry(log);
+
+ close(fileinfo->fd);
fclose(fp);
return;
}