static void do_file_response ( struct HTTPRequest *req, /* HTTP request */ FILE *out, /* output fd */ char *docroot /* docroot path */ ) { struct FileInfo *info = NULL; dbg( "req=%p, out=%p, docroot=%p\n", req, out, docroot ); info = get_fileinfo( docroot, req->path ); if( 0 == info->ok ) { free_fileinfo( info ); not_found( req, out ); return ; } output_common_header_fields( req, out, "200 OK" ); fprintf( out, "Content-Length: %ld\r\n", info->size ); fprintf( out, "Content-Type: %s\r\n", guess_content_type( info ) ); fprintf( out, "\r\n" ); outputBodyFields( info, req, out ); fflush( out ); free_fileinfo( info ); }
bool file_valid_extension(zathura_t* zathura, const char* path) { if (zathura == NULL || path == NULL || zathura->plugins.manager == NULL) { return false; } const gchar* content_type = guess_content_type(path); if (content_type == NULL) { return false; } zathura_plugin_t* plugin = zathura_plugin_manager_get_plugin(zathura->plugins.manager, content_type); g_free((void*)content_type); return (plugin == NULL) ? false : true; }
void send_file(evhtp_request_t* req, char* path) { struct stat st; unsigned char data[1024]; int fd; int n; evbuf_t* buf = NULL; if (stat(path, &st) < 0 || S_ISDIR(st.st_mode)) goto file_error; fd = open(path, O_RDONLY); if (fd < 0) goto file_error; buf = evbuffer_new(); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", guess_content_type(path), 0, 0)); evhtp_send_reply_chunk_start(req, EVHTP_RES_OK); do { n = read(fd, data, sizeof(data)); evbuffer_add(buf, data, n); evhtp_send_reply_chunk(req, buf); evbuffer_drain(buf, -1); } while (n > 0); close(fd); evhtp_send_reply_chunk_end(req); evbuffer_free(buf); return; file_error: evbuffer_add_printf(req->buffer_out, "ERROR:%s", path); evhtp_send_reply(req, EVHTP_RES_OK); }
static void do_file_response(struct HTTPRequest *req, FILE *out, char *docroot) { struct FileInfo *info; info = get_fileinfo(docroot, req->path); if (!info->ok) { free_fileinfo(info); not_found(req, out); return; } output_common_header_fields(req, out, "200 OK"); fprintf(out, "Content-Length: %ld\r\n", info->size); fprintf(out, "Content-Type: %s\r\n", guess_content_type(info)); fprintf(out, "\r\n"); if (strcmp(req->method, "HEAD") != 0) { int fd; char buf[BLOCK_BUF_SIZE]; ssize_t n; fd = open(info->path, O_RDONLY); if (fd < 0) { log_exit("failed to open %s: %s", info->path, strerror(errno)); } while (1) { n = read(fd, buf, BLOCK_BUF_SIZE); if (n < 0) { log_exit("failed to read %s: %s", info->path, strerror(errno)); } if (n == 0) { break; } if (fwrite(buf, n, 1, out) < 1) { log_exit("failed to write to socket: %s", strerror(errno)); } } close(fd); } fflush(out); free_fileinfo(info); }
static void send_document_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = NULL; const char *uri = evhttp_request_get_uri(req); char *whole_path = NULL; int fd = -1, fsize; printf("Got a GET request for <%s>\n", uri); fsize = encode_request_to_file_path(uri, &whole_path); if (!fsize) { goto err; } evb = evbuffer_new(); const char *type = guess_content_type(whole_path); if ((fd = open(whole_path, O_RDONLY)) < 0) { perror("open"); goto err; } evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", type); evbuffer_add_file(evb, fd, 0, fsize); evhttp_send_reply(req, 200, "OK", evb); goto done; err: evhttp_send_error(req, 404, "Document was not found"); if (fd>=0) { close(fd); } done: if (whole_path) { free(whole_path); } if (evb) { evbuffer_free(evb); } }
static void http_document_request_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = NULL; struct http *http = (struct http *) arg; const char *docroot = http->docroot; const char *uri = evhttp_request_get_uri(req); struct evhttp_uri *decoded = NULL; const char *path; char *decoded_path; char *whole_path = NULL; size_t len; int fd = -1; struct stat st; if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) { evhttp_send_error(req, HTTP_BADREQUEST, 0); return; } printf("GET: %s\n", uri); /* Decode the URI */ decoded = evhttp_uri_parse(uri); if (!decoded) { evhttp_send_error(req, HTTP_BADREQUEST, 0); return; } /* Let's see what path the user asked for. */ path = evhttp_uri_get_path(decoded); if (!path) path = "/"; /* We need to decode it, to see what path the user really wanted. */ decoded_path = evhttp_uridecode(path, 0, NULL); if (decoded_path == NULL) goto err; /* Don't allow any ".."s in the path, to avoid exposing stuff outside * of the docroot. This test is both overzealous and underzealous: * it forbids aceptable paths like "/this/one..here", but it doesn't * do anything to prevent symlink following." */ if (strstr(decoded_path, "..")) goto err; len = strlen(decoded_path) + strlen(docroot) + 2; if (!(whole_path = malloc(len))) { goto err; } snprintf(whole_path, len, "%s/%s", docroot, decoded_path); if (stat(whole_path, &st) < 0) { goto err; } /* This holds the content we're sending. */ evb = evbuffer_new(); if (S_ISDIR(st.st_mode)) { /* TODO: send index.html if the request is for a directory */ goto err; } else { /* Otherwise it's a file; add it to the buffer to get * sent via sendfile */ const char *type = guess_content_type(decoded_path); if ((fd = open(whole_path, O_RDONLY)) < 0) { goto err; } if (fstat(fd, &st) < 0) { /* Make sure the length still matches, now that we * opened the file :/ */ goto err; } evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", type); /* TODO: does this read the whole thing into memory?? well, we are only going to be * serving small files out of the static content directory, so its probably OK. */ evbuffer_add_file(evb, fd, 0, st.st_size); } evhttp_send_reply(req, 200, "OK", evb); goto done; err: evhttp_send_error(req, 404, "Document was not found"); if (fd >= 0) close(fd); done: if (decoded) evhttp_uri_free(decoded); if (decoded_path) free(decoded_path); if (whole_path) free(whole_path); if (evb) evbuffer_free(evb); }
static void static_list_request_cb(struct evhttp_request *req, void *arg) { struct evbuffer *evb = NULL; struct evhttp_uri *decoded = NULL; const char *path; char *decoded_path; int fd = -1; struct stat st; char uri_root[512] = {0}; struct evhttp_bound_socket *handle = (struct evhttp_bound_socket *)arg; size_t len; char *whole_path = NULL; const char *uri = evhttp_request_get_uri(req); get_uri_root(handle, uri_root, sizeof(uri_root)); decoded = evhttp_uri_parse(uri); if (decoded == NULL) { LOG(LOG_ERROR, "%s", "evhttp_decode_uri error"); evhttp_send_error(req, HTTP_BADREQUEST, 0); exit(1); } path = evhttp_uri_get_path(decoded); if (!path) path = "/"; decoded_path = evhttp_uridecode(path, 0, NULL); if (decoded_path == NULL) goto err; if (strstr(decoded_path, "..")) goto err; len = strlen(decoded_path)+strlen(docroot)+2; if (!(whole_path = malloc(len))) { perror("malloc"); goto err; } evutil_snprintf(whole_path, len, "%s/%s", docroot, decoded_path); if (stat(whole_path, &st)<0) { goto err; } evb = evbuffer_new(); if (S_ISDIR(st.st_mode)) { DIR *d; struct dirent *ent; const char *trailing_slash = ""; if (!strlen(path) || path[strlen(path)-1] != '/') trailing_slash = "/"; if (!(d = opendir(whole_path))) goto err; evbuffer_add_printf(evb, "<html>\n <head>\n" " <title>%s</title>\n" " <base href='%s%s%s'>\n" " </head>\n" " <body>\n" " <h1>%s</h1>\n" " <ul>\n", decoded_path, /* XXX html-escape this. */ uri_root, path, /* XXX html-escape this? */ trailing_slash, decoded_path /* XXX html-escape this */); while((ent = readdir(d))) { const char *name = ent->d_name; evbuffer_add_printf(evb, " <li><a href=\"%s\">%s</a>\n", name, name); evbuffer_add_printf(evb, "</ul></body></html>\n"); } closedir(d); evhttp_add_header(evhttp_request_get_output_headers(req), "Content-type", "text/html"); } else { const char *type = guess_content_type(decoded_path); if ((fd = open(whole_path, O_RDONLY)) < 0) { perror("open"); goto err; } if (fstat(fd, &st)<0) { /* Make sure the length still matches, now that we * opened the file :/ */ perror("fstat"); goto err; } evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", type); evbuffer_add_file(evb, fd, 0, st.st_size); } evhttp_send_reply(req, HTTP_OK, "OK", evb); goto done; err: evhttp_send_error(req, HTTP_NOTFOUND, "Document was not found"); if (fd>=0) close(fd); done: if (decoded) evhttp_uri_free(decoded); if (decoded_path) free(decoded_path); if (whole_path) free(whole_path); if (evb) evbuffer_free(evb); }
/** * Send a file to the client. * * @param req The request. * @param filepath The path to the file (in UNIX space). * @param sb The result of calling 'stat' on the file. */ static int send_file(FILE *stream, req_t *req, const char *filepath, struct stat *sb) { // regular file, send it char *buf = g_malloc(BUFFER_SIZE); ssize_t nb; int result = 0; FILE *file = fopen(filepath, "rb"); if (!file) { switch (errno) { case ENOENT: send_error(stream, 404, "Not Found", "The resource %s could not be found.", req_path(req)); break; case EACCES: send_error(stream, 401, "Forbidden", "The resource %s could not be read.", req_path(req)); break; default: send_error(stream, 500, "Internal Server Error", "%s: %s", req_path(req), strerror(errno)); break; } // the error should have been picked up earlier (calling 'stat'), so // return with error return -1; } fprintf(stream, "HTTP/1.0 200 OK\r\n"); const char *ctype = guess_content_type(filepath); if (ctype != NULL) { fprintf(stream, "Content-Type: %s\r\n", ctype); } size_t length = sb->st_size; struct tm *mod_time = gmtime(&(sb->st_mtime)); fprintf(stream, "Content-Length: %zd\r\n", length); char TIME_BUF[512]; strftime(TIME_BUF, 512, "%a, %d %b %Y %H:%M:%S %Z", mod_time); fprintf(stream, "Last-Modified: %s\r\n", TIME_BUF); fprintf(stream, "\r\n"); size_t total_bytes = 0; while ((nb = fread(buf, 1, BUFFER_SIZE, file)) > 0) { if (total_bytes + nb > length) { fprintf(stderr, "%s: file size changed\n", filepath); nb = length - total_bytes; result = -1; break; } size_t written = 0; while (written < nb) { size_t wr = fwrite(buf + written, 1, nb - written, stream); if (wr > 0) { written += wr; } else { // fwrite returns 0 for error // too late to send an error to the client to perror("output"); result = -1; break; } } total_bytes += nb; } if (!feof(file)) { perror(filepath); result = -1; } fclose(file); // TODO send stat data return result; }
static void test_foobar_null() { const char *type = guess_content_type("foo.wombat"); g_assert_null(type); }
static void test_double_extension() { const char *type = guess_content_type("index.html.jpg"); g_assert_cmpstr(type, ==, "image/jpeg"); }
static void test_html_upcase() { const char *type = guess_content_type("INDEX.HTML"); g_assert_cmpstr(type, ==, "text/html"); }
static void test_htm() { const char *type = guess_content_type("index.htm"); g_assert_cmpstr(type, ==, "text/html"); }