diff options
Diffstat (limited to 'src/blogc-runserver')
-rw-r--r-- | src/blogc-runserver/httpd-utils.c | 105 | ||||
-rw-r--r-- | src/blogc-runserver/httpd-utils.h | 19 | ||||
-rw-r--r-- | src/blogc-runserver/httpd.c | 413 | ||||
-rw-r--r-- | src/blogc-runserver/httpd.h | 15 | ||||
-rw-r--r-- | src/blogc-runserver/main.c | 153 | ||||
-rw-r--r-- | src/blogc-runserver/mime.c | 164 | ||||
-rw-r--r-- | src/blogc-runserver/mime.h | 15 |
7 files changed, 0 insertions, 884 deletions
diff --git a/src/blogc-runserver/httpd-utils.c b/src/blogc-runserver/httpd-utils.c deleted file mode 100644 index 9d374ae..0000000 --- a/src/blogc-runserver/httpd-utils.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdbool.h> -#include <string.h> -#include <unistd.h> -#include "../common/utils.h" -#include "httpd-utils.h" - - -char* -br_readline(int socket) -{ - bc_string_t *rv = bc_string_new(); - char buffer[READLINE_BUFFER_SIZE]; - ssize_t len; - bool end = false; - - while ((len = read(socket, buffer, READLINE_BUFFER_SIZE)) > 0) { - if (!end) { - for (ssize_t i = 0; i < len; i++) { - if (buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\0') { - // we finished "recording", but still need to exhaust - // request data. - end = true; - break; - } - bc_string_append_c(rv, buffer[i]); - } - } - if (len < READLINE_BUFFER_SIZE) { - break; - } - } - - return bc_string_free(rv, false); -} - - -int -br_hextoi(const char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - return -1; -} - - -char* -br_urldecode(const char *str) -{ - bc_string_t *rv = bc_string_new(); - - for (size_t i = 0; i < strlen(str); i++) { - switch (str[i]) { - case '%': - if (i + 2 < strlen(str)) { - int p1 = br_hextoi(str[i + 1]) * 16; - int p2 = br_hextoi(str[i + 2]); - if (p1 >= 0 && p2 >= 0) { - bc_string_append_c(rv, p1 + p2); - i += 2; - continue; - } - } - bc_string_append_c(rv, '%'); - break; - case '+': - bc_string_append_c(rv, ' '); - break; - default: - bc_string_append_c(rv, str[i]); - } - } - - return bc_string_free(rv, false); -} - - -const char* -br_get_extension(const char *filename) -{ - const char *ext = NULL; - size_t i; - for (i = strlen(filename); i > 0; i--) { - if (filename[i] == '.') { - ext = filename + i + 1; - break; - } - if ((filename[i] == '/') || (filename[i] == '\\')) - return NULL; - } - if (i == 0) - return NULL; - return ext; -} diff --git a/src/blogc-runserver/httpd-utils.h b/src/blogc-runserver/httpd-utils.h deleted file mode 100644 index 06ad6e1..0000000 --- a/src/blogc-runserver/httpd-utils.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _HTTPD_UTILS_H -#define _HTTPD_UTILS_H - -#define READLINE_BUFFER_SIZE 2048 - -char* br_readline(int socket); -int br_hextoi(const char c); -char* br_urldecode(const char *str); -const char* br_get_extension(const char *filename); - -#endif /* _HTTPD_UTILS_H */ diff --git a/src/blogc-runserver/httpd.c b/src/blogc-runserver/httpd.c deleted file mode 100644 index fe98288..0000000 --- a/src/blogc-runserver/httpd.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <pthread.h> -#include "../common/error.h" -#include "../common/file.h" -#include "../common/utils.h" -#include "mime.h" -#include "httpd-utils.h" - -#define LISTEN_BACKLOG 100 - -typedef struct { - pthread_t thread; - bool initialized; -} thread_data_t; - -typedef struct { - size_t thread_id; - int socket; - char *ip; - const char *docroot; -} request_data_t; - - -static void -error(int socket, int status_code, const char *error) -{ - char *str = bc_strdup_printf( - "HTTP/1.0 %d %s\r\n" - "Content-Type: text/html\r\n" - "Content-Length: %zu\r\n" - "Connection: close\r\n" - "\r\n" - "<h1>%s</h1>\n", status_code, error, strlen(error) + 10, error); - size_t str_len = strlen(str); - if (str_len != write(socket, str, str_len)) { - fprintf(stderr, "warning: Failed to write full response header!\n"); - } - free(str); -} - - -static void* -handle_request(void *arg) -{ - request_data_t *req = arg; - size_t thread_id = req->thread_id; - int client_socket = req->socket; - char *ip = req->ip; - const char *docroot = req->docroot; - free(arg); - - char *conn_line = br_readline(client_socket); - if (conn_line == NULL || conn_line[0] == '\0') - goto point0; - - unsigned short status_code = 200; - - char **pieces = bc_str_split(conn_line, ' ', 3); - if (bc_strv_length(pieces) != 3) { - status_code = 400; - error(client_socket, 400, "Bad Request"); - goto point1; - } - - if (strcmp(pieces[0], "GET") != 0) { - status_code = 405; - error(client_socket, 405, "Method Not Allowed"); - goto point1; - } - - char **pieces2 = bc_str_split(pieces[1], '?', 2); - char *path = br_urldecode(pieces2[0]); - bc_strv_free(pieces2); - - if (path == NULL) { - status_code = 400; - error(client_socket, 400, "Bad Request"); - goto point2; - } - - char *abs_path = bc_strdup_printf("%s/%s", docroot, path); - char *real_path = realpath(abs_path, NULL); - free(abs_path); - - if (real_path == NULL) { - if (errno == ENOENT) { - status_code = 404; - error(client_socket, 404, "Not Found"); - } - else { - status_code = 500; - error(client_socket, 500, "Internal Server Error"); - } - goto point2; - } - - char *real_root = realpath(docroot, NULL); - if (real_root == NULL) { - status_code = 500; - error(client_socket, 500, "Internal Server Error"); - goto point3; - } - - if (0 != strncmp(real_root, real_path, strlen(real_root))) { - status_code = 404; - error(client_socket, 404, "Not Found"); - goto point4; - } - - struct stat st; - if (0 > stat(real_path, &st)) { - status_code = 404; - error(client_socket, 404, "Not Found"); - goto point4; - } - - bool add_slash = false; - - if (S_ISDIR(st.st_mode)) { - char *found = br_mime_guess_index(real_path); - - if (found == NULL) { - status_code = 403; - error(client_socket, 403, "Forbidden"); - goto point4; - } - - size_t path_len = strlen(path); - if (path_len > 0 && path[path_len - 1] != '/') - add_slash = true; - - free(real_path); - real_path = found; - } - - if (0 != access(real_path, F_OK)) { - status_code = 500; - error(client_socket, 500, "Internal Server Error"); - goto point4; - } - - if (add_slash) { - // production webservers usually returns 301 in such cases, but 302 is - // better for development/testing. - char *tmp = bc_strdup_printf( - "HTTP/1.0 302 Found\r\n" - "Location: %s/\r\n" - "Content-Length: 0\r\n" - "Connection: close\r\n" - "\r\n", path); - status_code = 302; - size_t tmp_len = strlen(tmp); - if (tmp_len != write(client_socket, tmp, tmp_len)) { - fprintf(stderr, "warning: Failed to write full response header!\n"); - } - free(tmp); - goto point4; - } - - size_t len; - bc_error_t *err = NULL; - char* contents = bc_file_get_contents(real_path, false, &len, &err); - if (err != NULL) { - status_code = 500; - error(client_socket, 500, "Internal Server Error"); - bc_error_free(err); - goto point4; - } - - char *out = bc_strdup_printf( - "HTTP/1.0 200 OK\r\n" - "Content-Type: %s\r\n" - "Content-Length: %zu\r\n" - "Connection: close\r\n" - "\r\n", br_mime_guess_content_type(real_path), len); - size_t out_len = strlen(out); - if (out_len != write(client_socket, out, out_len)) { - fprintf(stderr, "warning: Failed to write full response header!\n"); - } - free(out); - - if (len != write(client_socket, contents, len)) { - fprintf(stderr, "warning: Failed to write full response body!\n"); - } - free(contents); - -point4: - free(real_root); -point3: - free(real_path); -point2: - free(path); -point1: - fprintf(stderr, "[Thread-%zu] %s - - \"%s\" %d\n", thread_id + 1, - ip, conn_line, status_code); - free(conn_line); - bc_strv_free(pieces); -point0: - free(ip); - close(client_socket); - return NULL; -} - - -static char* -br_httpd_get_ip(int af, const struct sockaddr *addr) -{ - char host[INET6_ADDRSTRLEN]; - if (af == AF_INET6) { - struct sockaddr_in6 *a = (struct sockaddr_in6*) addr; - inet_ntop(af, &(a->sin6_addr), host, INET6_ADDRSTRLEN); - } - else { - struct sockaddr_in *a = (struct sockaddr_in*) addr; - inet_ntop(af, &(a->sin_addr), host, INET6_ADDRSTRLEN); - } - return bc_strdup(host); -} - - -static uint16_t -br_httpd_get_port(int af, const struct sockaddr *addr) -{ - in_port_t port = 0; - if (af == AF_INET6) { - struct sockaddr_in6 *a = (struct sockaddr_in6*) addr; - port = a->sin6_port; - } - else { - struct sockaddr_in *a = (struct sockaddr_in*) addr; - port = a->sin_port; - } - return ntohs(port); -} - - -int -br_httpd_run(const char *host, const char *port, const char *docroot, - size_t max_threads) -{ - int err; - struct addrinfo *result; - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_flags = AI_PASSIVE, - .ai_protocol = 0, - .ai_canonname = NULL, - .ai_addr = NULL, - .ai_next = NULL, - }; - if (0 != (err = getaddrinfo(host, port, &hints, &result))) { - fprintf(stderr, "Failed to get host:port info: %s\n", - gai_strerror(err)); - return 1; - } - - thread_data_t threads[max_threads]; - for (size_t i = 0; i < max_threads; i++) - threads[i].initialized = false; - - int rv = 0; - - struct addrinfo *rp; - int server_socket = 0; - - int ai_family = 0; - char *final_host = NULL; - uint16_t final_port = 0; - - for (rp = result; rp != NULL; rp = rp->ai_next) { - final_host = br_httpd_get_ip(rp->ai_family, rp->ai_addr); - final_port = br_httpd_get_port(rp->ai_family, rp->ai_addr); - server_socket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (server_socket == -1) { - if (rp->ai_next == NULL) { - fprintf(stderr, "Failed to open server socket (%s:%d): %s\n", - final_host, final_port, strerror(errno)); - rv = 1; - goto cleanup0; - } - continue; - } - int value = 1; - if (0 > setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &value, - sizeof(int))) - { - if (rp->ai_next == NULL) { - fprintf(stderr, "Failed to set socket option (%s:%d): %s\n", - final_host, final_port, strerror(errno)); - rv = 1; - goto cleanup; - } - close(server_socket); - continue; - } - if (0 == bind(server_socket, rp->ai_addr, rp->ai_addrlen)) { - ai_family = rp->ai_family; - break; - } - else { - if (rp->ai_next == NULL) { - fprintf(stderr, "Failed to bind to server socket (%s:%d): %s\n", - final_host, final_port, strerror(errno)); - rv = 1; - goto cleanup; - } - } - free(final_host); - close(server_socket); - } - - if (-1 == listen(server_socket, LISTEN_BACKLOG)) { - fprintf(stderr, "Failed to listen to server socket (%s:%d): %s\n", - final_host, final_port, strerror(errno)); - rv = 1; - goto cleanup; - } - - fprintf(stderr, " * Running on http://"); - if (ai_family == AF_INET6) - fprintf(stderr, "[%s]", final_host); - else - fprintf(stderr, "%s", final_host); - if (final_port != 80) - fprintf(stderr, ":%d", final_port); - fprintf(stderr, "/ (max threads: %zu)\n" - "\n" - "WARNING!!! This is a development server, DO NOT RUN IT IN PRODUCTION!\n" - "\n", max_threads); - - size_t current_thread = 0; - - while (1) { - struct sockaddr_in6 addr6; - struct sockaddr_in addr; - - socklen_t addrlen; - struct sockaddr *client_addr = NULL; - - if (ai_family == AF_INET6) { - addrlen = sizeof(addr6); - client_addr = (struct sockaddr*) &addr6; - } - else { - addrlen = sizeof(addr); - client_addr = (struct sockaddr*) &addr; - } - - int client_socket = accept(server_socket, client_addr, &addrlen); - if (client_socket == -1) { - fprintf(stderr, "Failed to accept connection: %s\n", strerror(errno)); - rv = 1; - goto cleanup; - } - - request_data_t *arg = malloc(sizeof(request_data_t)); - arg->thread_id = current_thread; - arg->socket = client_socket; - arg->ip = br_httpd_get_ip(ai_family, client_addr); - arg->docroot = docroot; - - if (threads[current_thread].initialized) { - if (pthread_join(threads[current_thread].thread, NULL) != 0) { - fprintf(stderr, "Failed to join thread\n"); - free(arg->ip); - free(arg); - rv = 1; - goto cleanup; - } - } - - if (pthread_create(&(threads[current_thread].thread), NULL, - handle_request, arg) != 0) - { - fprintf(stderr, "Failed to create thread\n"); - rv = 1; - goto cleanup; - } - - threads[current_thread++].initialized = true; - - if (current_thread >= max_threads) - current_thread = 0; - } - -cleanup: - close(server_socket); - -cleanup0: - free(final_host); - freeaddrinfo(result); - return rv; -} diff --git a/src/blogc-runserver/httpd.h b/src/blogc-runserver/httpd.h deleted file mode 100644 index b71a8d9..0000000 --- a/src/blogc-runserver/httpd.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _HTTPD_H -#define _HTTPD_H - -int br_httpd_run(const char *host, const char *port, const char *docroot, - size_t max_threads); - -#endif /* _HTTPD_H */ diff --git a/src/blogc-runserver/main.c b/src/blogc-runserver/main.c deleted file mode 100644 index 1c5be29..0000000 --- a/src/blogc-runserver/main.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include "../common/utils.h" -#include "httpd.h" - - -static void -print_help(const char *default_host, const char *default_port) -{ - printf( - "usage:\n" - " blogc-runserver [-h] [-v] [-t HOST] [-p PORT] [-m THREADS] DOCROOT\n" - " - A simple HTTP server to test blogc websites.\n" - "\n" - "positional arguments:\n" - " DOCROOT document root directory\n" - "\n" - "optional arguments:\n" - " -h show this help message and exit\n" - " -v show version and exit\n" - " -t HOST set server listen address (default: %s)\n" - " -p PORT set server listen port (default: %s)\n" - " -m THREADS set maximum number of threads to spawn (default: 20)\n", - default_host, default_port); -} - - -static void -print_usage(void) -{ - printf("usage: blogc-runserver [-h] [-v] [-t HOST] [-p PORT] [-m THREADS] DOCROOT\n"); -} - - -int -main(int argc, char **argv) -{ - struct sigaction new_action; - new_action.sa_handler = SIG_IGN; - sigemptyset(&new_action.sa_mask); - new_action.sa_flags = 0; - sigaction(SIGPIPE, &new_action, NULL); - - int rv = 0; - char *host = NULL; - char *port = NULL; - char *docroot = NULL; - size_t max_threads = 20; - char *ptr; - char *endptr; - - char *tmp_host = getenv("BLOGC_RUNSERVER_DEFAULT_HOST"); - char *default_host = bc_strdup(tmp_host != NULL ? tmp_host : "127.0.0.1"); - char *tmp_port = getenv("BLOGC_RUNSERVER_DEFAULT_PORT"); - char *default_port = bc_strdup(tmp_port != NULL ? tmp_port : "8080"); - - size_t args = 0; - - for (size_t i = 1; i < argc; i++) { - if (argv[i][0] == '-') { - switch (argv[i][1]) { - case 'h': - print_help(default_host, default_port); - goto cleanup; - case 'v': - printf("%s\n", PACKAGE_STRING); - goto cleanup; - case 't': - if (argv[i][2] != '\0') - host = bc_strdup(argv[i] + 2); - else - host = bc_strdup(argv[++i]); - break; - case 'p': - if (argv[i][2] != '\0') - port = bc_strdup(argv[i] + 2); - else - port = bc_strdup(argv[++i]); - break; - case 'm': - if (argv[i][2] != '\0') - ptr = argv[i] + 2; - else - ptr = argv[++i]; - max_threads = strtoul(ptr, &endptr, 10); - if (*ptr != '\0' && *endptr != '\0') - fprintf(stderr, "blogc-runserver: warning: invalid value " - "for -m argument: %s. using %zu instead\n", ptr, max_threads); - break; - default: - print_usage(); - fprintf(stderr, "blogc-runserver: error: invalid " - "argument: -%c\n", argv[i][1]); - rv = 1; - goto cleanup; - } - } - else { - if (args > 0) { - print_usage(); - fprintf(stderr, "blogc-runserver: error: only one positional " - "argument allowed\n"); - rv = 1; - goto cleanup; - } - args++; - docroot = bc_strdup(argv[i]); - } - } - - if (docroot == NULL) { - print_usage(); - fprintf(stderr, "blogc-runserver: error: document root directory " - "required\n"); - rv = 1; - goto cleanup; - } - - if (max_threads <= 0 || max_threads > 1000) { - print_usage(); - fprintf(stderr, "blogc-runserver: error: invalid value for -m. " - "Must be integer > 0 and <= 1000\n"); - rv = 1; - goto cleanup; - } - - rv = br_httpd_run( - host != NULL ? host : default_host, - port != NULL ? port : default_port, - docroot, max_threads); - -cleanup: - free(default_host); - free(default_port); - free(host); - free(port); - free(docroot); - - return rv; -} diff --git a/src/blogc-runserver/mime.c b/src/blogc-runserver/mime.c deleted file mode 100644 index 636c496..0000000 --- a/src/blogc-runserver/mime.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include "../common/utils.h" -#include "httpd-utils.h" - - -// mime types with index should be in the begin of the list. first NULL -// index aborts the lookup, for optimization -static const struct content_type_map { - const char *mimetype; - const char *extension; - const char *index; -} content_types[] = { - - // with index - {"text/html", "html", "index.html"}, - {"text/html", "htm", "index.htm"}, - {"text/html", "shtml", "index.shtml"}, - {"text/xml", "xml", "index.xml"}, - {"text/plain", "txt", "index.txt"}, - {"application/xhtml+xml", "xhtml", "index.xhtml"}, - - // without index - {"text/css", "css", NULL}, - {"image/gif", "gif", NULL}, - {"image/jpeg", "jpeg", NULL}, - {"image/jpeg", "jpg", NULL}, - {"application/javascript", "js", NULL}, - {"application/atom+xml", "atom", NULL}, - {"application/rss+xml", "rss", NULL}, - {"text/mathml", "mml", NULL}, - {"text/vnd.sun.j2me.app-descriptor", "jad", NULL}, - {"text/vnd.wap.wml", "wml", NULL}, - {"text/x-component", "htc", NULL}, - {"image/png", "png", NULL}, - {"image/tiff", "tif", NULL}, - {"image/tiff", "tiff", NULL}, - {"image/vnd.wap.wbmp", "wbmp", NULL}, - {"image/x-icon", "ico", NULL}, - {"image/x-jng", "jng", NULL}, - {"image/x-ms-bmp", "bmp", NULL}, - {"image/svg+xml", "svg", NULL}, - {"image/svg+xml", "svgz", NULL}, - {"image/webp", "webp", NULL}, - {"application/font-woff", "woff", NULL}, - {"application/java-archive", "jar", NULL}, - {"application/java-archive", "war", NULL}, - {"application/java-archive", "ear", NULL}, - {"application/json", "json", NULL}, - {"application/mac-binhex40", "hqx", NULL}, - {"application/msword", "doc", NULL}, - {"application/pdf", "pdf", NULL}, - {"application/postscript", "ps", NULL}, - {"application/postscript", "eps", NULL}, - {"application/postscript", "ai", NULL}, - {"application/rtf", "rtf", NULL}, - {"application/vnd.apple.mpegurl", "m3u8", NULL}, - {"application/vnd.ms-excel", "xls", NULL}, - {"application/vnd.ms-fontobject", "eot", NULL}, - {"application/vnd.ms-powerpoint", "ppt", NULL}, - {"application/vnd.wap.wmlc", "wmlc", NULL}, - {"application/vnd.google-earth.kml+xml", "kml", NULL}, - {"application/vnd.google-earth.kmz", "kmz", NULL}, - {"application/x-7z-compressed", "7z", NULL}, - {"application/x-cocoa", "cco", NULL}, - {"application/x-java-archive-diff", "jardiff", NULL}, - {"application/x-java-jnlp-file", "jnlp", NULL}, - {"application/x-makeself", "run", NULL}, - {"application/x-perl", "pl", NULL}, - {"application/x-perl", "pm", NULL}, - {"application/x-pilot", "prc", NULL}, - {"application/x-pilot", "pdb", NULL}, - {"application/x-rar-compressed", "rar", NULL}, - {"application/x-redhat-package-manager", "rpm", NULL}, - {"application/x-sea", "sea", NULL}, - {"application/x-shockwave-flash", "swf", NULL}, - {"application/x-stuffit", "sit", NULL}, - {"application/x-tcl", "tcl", NULL}, - {"application/x-tcl", "tk", NULL}, - {"application/x-x509-ca-cert", "der", NULL}, - {"application/x-x509-ca-cert", "pem", NULL}, - {"application/x-x509-ca-cert", "crt", NULL}, - {"application/x-xpinstall", "xpi", NULL}, - {"application/xspf+xml", "xspf", NULL}, - {"application/zip", "zip", NULL}, - {"application/octet-stream", "bin", NULL}, - {"application/octet-stream", "exe", NULL}, - {"application/octet-stream", "dll", NULL}, - {"application/octet-stream", "deb", NULL}, - {"application/octet-stream", "dmg", NULL}, - {"application/octet-stream", "iso", NULL}, - {"application/octet-stream", "img", NULL}, - {"application/octet-stream", "msi", NULL}, - {"application/octet-stream", "msp", NULL}, - {"application/octet-stream", "msm", NULL}, - {"application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx", NULL}, - {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx", NULL}, - {"application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx", NULL}, - {"audio/midi", "mid", NULL}, - {"audio/midi", "midi", NULL}, - {"audio/midi", "kar", NULL}, - {"audio/mpeg", "mp3", NULL}, - {"audio/ogg", "ogg", NULL}, - {"audio/x-m4a", "m4a", NULL}, - {"audio/x-realaudio", "ra", NULL}, - {"video/3gpp", "3gpp", NULL}, - {"video/3gpp", "3gp", NULL}, - {"video/mp2t", "ts", NULL}, - {"video/mp4", "mp4", NULL}, - {"video/mpeg", "mpeg", NULL}, - {"video/mpeg", "mpg", NULL}, - {"video/quicktime", "mov", NULL}, - {"video/webm", "webm", NULL}, - {"video/x-flv", "flv", NULL}, - {"video/x-m4v", "m4v", NULL}, - {"video/x-mng", "mng", NULL}, - {"video/x-ms-asf", "asx", NULL}, - {"video/x-ms-asf", "asf", NULL}, - {"video/x-ms-wmv", "wmv", NULL}, - {"video/x-msvideo", "avi", NULL}, - {NULL, NULL, NULL} -}; - - -const char* -br_mime_guess_content_type(const char *filename) -{ - const char *extension = br_get_extension(filename); - if (extension == NULL) - goto default_type; - for (size_t i = 0; content_types[i].extension != NULL; i++) { - if (0 == strcmp(content_types[i].extension, extension)) { - return content_types[i].mimetype; - } - } - -default_type: - return "application/octet-stream"; -} - - -char* -br_mime_guess_index(const char *path) -{ - char *found = NULL; - for (size_t i = 0; content_types[i].index != NULL; i++) { - char *f = bc_strdup_printf("%s/%s", path, content_types[i].index); - if (0 == access(f, F_OK)) { - found = f; - break; - } - free(f); - } - return found; -} diff --git a/src/blogc-runserver/mime.h b/src/blogc-runserver/mime.h deleted file mode 100644 index b9fb013..0000000 --- a/src/blogc-runserver/mime.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MIME_H -#define _MIME_H - -const char* br_mime_guess_content_type(const char *filename); -char* br_mime_guess_index(const char *path); - -#endif /* _MIME_H */ |