1 /* $OpenBSD: server_file.c,v 1.6 2014/07/16 10:25:28 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/time.h> 22 #include <sys/stat.h> 23 #include <sys/socket.h> 24 #include <sys/un.h> 25 #include <sys/tree.h> 26 #include <sys/hash.h> 27 28 #include <net/if.h> 29 #include <netinet/in_systm.h> 30 #include <netinet/in.h> 31 #include <netinet/ip.h> 32 #include <netinet/tcp.h> 33 #include <arpa/inet.h> 34 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <stdio.h> 41 #include <err.h> 42 #include <event.h> 43 44 #include <openssl/ssl.h> 45 46 #include "httpd.h" 47 #include "http.h" 48 49 void server_file_error(struct bufferevent *, short, void *); 50 51 int 52 server_file(struct httpd *env, struct client *clt) 53 { 54 struct http_descriptor *desc = clt->clt_desc; 55 struct server *srv = clt->clt_server; 56 struct media_type *media; 57 const char *errstr = NULL; 58 int fd = -1, ret; 59 char path[MAXPATHLEN]; 60 struct stat st; 61 62 /* 63 * XXX This is not ready XXX 64 * XXX Don't expect anything from this code yet, 65 */ 66 67 strlcpy(path, "/htdocs", sizeof(path)); 68 if (desc->http_path[0] != '/') 69 strlcat(path, "/", sizeof(path)); 70 strlcat(path, desc->http_path, sizeof(path)); 71 if (desc->http_path[strlen(desc->http_path) - 1] == '/') 72 strlcat(path, "index.html", sizeof(path)); 73 74 if (access(path, R_OK) == -1) { 75 strlcpy(path, desc->http_path, sizeof(path)); 76 switch (errno) { 77 case EACCES: 78 server_abort_http(clt, 403, path); 79 break; 80 case ENOENT: 81 server_abort_http(clt, 404, path); 82 break; 83 default: 84 server_abort_http(clt, 500, path); 85 break; 86 } 87 return (-1); 88 } 89 90 if ((fd = open(path, O_RDONLY)) == -1 || fstat(fd, &st) == -1) 91 goto fail; 92 93 /* File descriptor is opened, decrement inflight counter */ 94 server_inflight_dec(clt, __func__); 95 96 media = media_find(env->sc_mediatypes, path); 97 ret = server_response_http(clt, 200, media, st.st_size); 98 switch (ret) { 99 case -1: 100 goto fail; 101 case 0: 102 /* Connection is already finished */ 103 close(fd); 104 return (0); 105 default: 106 break; 107 } 108 109 clt->clt_fd = fd; 110 if (clt->clt_file != NULL) 111 bufferevent_free(clt->clt_file); 112 113 clt->clt_file = bufferevent_new(clt->clt_fd, server_read, 114 server_write, server_file_error, clt); 115 if (clt->clt_file == NULL) { 116 errstr = "failed to allocate file buffer event"; 117 goto fail; 118 } 119 120 bufferevent_settimeout(clt->clt_file, 121 srv->srv_conf.timeout.tv_sec, srv->srv_conf.timeout.tv_sec); 122 bufferevent_enable(clt->clt_file, EV_READ); 123 bufferevent_disable(clt->clt_bev, EV_READ); 124 125 return (0); 126 fail: 127 if (errstr == NULL) 128 errstr = strerror(errno); 129 server_abort_http(clt, 500, errstr); 130 return (-1); 131 } 132 133 void 134 server_file_error(struct bufferevent *bev, short error, void *arg) 135 { 136 struct client *clt = arg; 137 struct evbuffer *dst; 138 139 if (error & EVBUFFER_TIMEOUT) { 140 server_close(clt, "buffer event timeout"); 141 return; 142 } 143 if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) { 144 bufferevent_disable(bev, EV_READ); 145 146 clt->clt_done = 1; 147 148 dst = EVBUFFER_OUTPUT(clt->clt_bev); 149 if (EVBUFFER_LENGTH(dst)) { 150 /* Finish writing all data first */ 151 bufferevent_enable(clt->clt_bev, EV_WRITE); 152 return; 153 } 154 155 if (clt->clt_persist) { 156 /* Close input file and wait for next HTTP request */ 157 if (clt->clt_fd != -1) 158 close(clt->clt_fd); 159 clt->clt_fd = -1; 160 clt->clt_toread = TOREAD_HTTP_HEADER; 161 server_reset_http(clt); 162 bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); 163 return; 164 } 165 server_close(clt, "done"); 166 return; 167 } 168 if (error & EVBUFFER_ERROR && errno == EFBIG) { 169 bufferevent_enable(bev, EV_READ); 170 return; 171 } 172 server_close(clt, "buffer event error"); 173 return; 174 } 175