↑ 1 #include <stdio.h>
↑ 2 #include <stdlib.h>
↑ 3 #include <fcntl.h>
↑ 4 #include <errno.h>
↑ 5 #include <unistd.h>
↑ 6 #include "config.h"
↑ 7 #include "client.h"
↑ 8 #include "server.h"
↑ 9 #include "rh_string.h"
↑ 10 #include "handler.h"
↑ 11 #include "http_request.h"
↑ 12 #include "rh_chunk.h"
↑ 13 #include "http_range.h"
↑ 14 #include "log.h"
↑ 15
↑ 16 /*
↑ 17 *
↑ 18 * file
↑ 19 *
↑ 20 *
↑ 21 * main thing which deals with regular files.
↑ 22 *
↑ 23 *
↑ 24 */
↑ 25
↑ 26 static void file_close (void *arg)
↑ 27 {
↑ 28 close ( (int)arg );
↑ 29 }
↑ 30
↑ 31 static int handle_range (http_request_t *request, int file_fd)
↑ 32 {
↑ 33 struct http_range *range;
↑ 34 struct http_range_entry *entry;
↑ 35 http_header_entry_t *content_range;
↑ 36
↑ 37 range = HTTP_HEADER_KEY_GET_DATA(&request->header_in, RANGE);
↑ 38
↑ 39 if (range->queue_count == 1) {
↑ 40 size_t size = 0;
↑ 41 off_t offset = 0;
↑ 42
↑ 43 entry = SIMPLEQ_FIRST(&range->queue);
↑ 44
↑ 45 size = request->st->stbuf.st_size;
↑ 46
↑ 47 if (entry->have_left && entry->left >= size)
↑ 48 goto error_416;
↑ 49
↑ 50 if (entry->have_right && entry->right >= size)
↑ 51 goto error_416;
↑ 52
↑ 53
↑ 54 if (entry->have_left && entry->have_right) {
↑ 55 offset = entry->left;
↑ 56 size = 1 + (entry->right - entry->left);
↑ 57 } else
↑ 58 if (entry->have_left) {
↑ 59 offset = entry->left;
↑ 60 size -= offset;
↑ 61 } else
↑ 62 if (entry->have_right) {
↑ 63 offset = size - entry->right;
↑ 64 size = size - offset;
↑ 65
↑ 66 } else {
↑ 67 goto error_416;
↑ 68 }
↑ 69
↑ 70 content_range = HTTP_HEADER_KEY_USE ( &request->header_out,
↑ 71 CONTENT_RANGE);
↑ 72
↑ 73 if (0 != rh_buffer_sprintf (&content_range->value,
↑ 74 "bytes %llu-%llu/%llu",
↑ 75 offset,
↑ 76 offset + size - 1,
↑ 77 request->st->stbuf.st_size ))
↑ 78 {
↑ 79 goto error_errno;
↑ 80 }
↑ 81
↑ 82 if (0 != rh_chunk_append_file (&request->chunk_content,
↑ 83 file_fd, offset, size,
↑ 84 file_close, (void*)file_fd) )
↑ 85 {
↑ 86 goto error_errno;
↑ 87 }
↑ 88
↑ 89 } else {
↑ 90 request->header_out.status = 500;
↑ 91 return HANDLER_FAILURE;
↑ 92 }
↑ 93
↑ 94 request->header_out.status = 206;
↑ 95
↑ 96
↑ 97 return HANDLER_SUCCESS;
↑ 98
↑ 99 error_416:
↑100 request->header_out.status = 416;
↑101 return HANDLER_FAILURE;
↑102
↑103 error_errno:
↑104 http_header_set_errno_status (&request->header_out,errno);
↑105 return HANDLER_FAILURE;
↑106 }
↑107
↑108
↑109
↑110
↑111
↑112 DECLARE_HANDLER_FUNCTION (file,exec)
↑113 {
↑114 http_request_t *request;
↑115 const rh_buffer_t *content_type = NULL;
↑116
↑117 #ifdef RHTTPD_DUMP_HANDLER_CALL
↑118 printf ("%s(%p)\n", __FUNCTION__, (void*)handler);
↑119 #endif
↑120
↑121 request = handler->request;
↑122
↑123 if (0 != request->header_out.status)
↑124 return HANDLER_FAILURE;
↑125
↑126 if (NULL == request->st)
↑127 return HANDLER_FAILURE;
↑128
↑129 if (request->st->error)
↑130 return HANDLER_FAILURE;
↑131
↑132 if (!RH_STAT_ISREG(request->st)) {
↑133 request->header_out.status = 403;
↑134 return HANDLER_FAILURE;
↑135 }
↑136
↑137
↑138 /*
↑139 *
↑140 * conditional requests
↑141 *
↑142 *
↑143 */
↑144
↑145
↑146 /* If-Match: * | etag */
↑147 if (http_header_if_match (&request->header_in, &request->header_out))
↑148 goto send_content;
↑149
↑150 /*
↑151 * if-unmodified-since: date
↑152 *
↑153 * if resource.mtime <= if-modified-since -> 304
↑154 *
↑155 */
↑156
↑157 /* if-modified-since: date
↑158 *
↑159 * if resource.mtime >= if-modified-since -> 304
↑160 *
↑161 */
↑162 if (!http_header_is_modified(&request->header_in, &request->st->gmtime))
↑163 goto write_304;
↑164
↑165 /* If-None-Match: etag */
↑166 if (http_header_if_none_match(&request->header_in,&request->header_out))
↑167 goto write_304;
↑168
↑169 send_content:
↑170 /* send the file */
↑171 request->header_out.status = 200;
↑172
↑173 if ( HTTP_METHOD_GET != request->header_in.method ||
↑174 0 == request->st->stbuf.st_size)
↑175 {
↑176 http_header_key_set_content_length (
↑177 &request->header_out,
↑178 request->st->stbuf.st_size);
↑179 } else {
↑180 int file_fd;
↑181
↑182 file_fd = open (request->st->path.data, O_RDONLY);
↑183 if (-1 == file_fd)
↑184 goto error_out_errno;
↑185
↑186 if (!http_header_have_range (&request->header_in)) {
↑187 if (0 != rh_chunk_append_file (&request->chunk_content,
↑188 file_fd, 0, request->st->stbuf.st_size,
↑189 file_close, (void*)file_fd) )
↑190 {
↑191 close (file_fd);
↑192 goto error_out_errno;
↑193 }
↑194 } else {
↑195 if (0 != handle_range(request, file_fd)) {
↑196 close (file_fd);
↑197 return HANDLER_FAILURE;
↑198 }
↑199 }
↑200 }
↑201
↑202 HTTP_HEADER_KEY_SET_CONST_BUFFER (
↑203 &request->header_out,
↑204 LAST_MODIFIED,
↑205 &request->st->gmtime);
↑206
↑207 if (MIMETYPE_EXISTS(CONTENT, &request->st->mime)) {
↑208 content_type = MIMETYPE_VALUE(CONTENT, &request->st->mime);
↑209 } else {
↑210 const config_value_t *config_value;
↑211
↑212 config_value = CONFIG_POP_VALUE(request->client->server->config,
↑213 DEFAULT_TYPE);
↑214 if (config_value) {
↑215 if (config_value->value.used)
↑216 content_type = &config_value->value;
↑217 config_push_value (config_value);
↑218 }
↑219 }
↑220
↑221 if (content_type) {
↑222 HTTP_HEADER_KEY_SET_CONST_BUFFER (
↑223 &request->header_out,
↑224 CONTENT_TYPE,
↑225 content_type);
↑226 }
↑227
↑228 return HANDLER_SUCCESS;
↑229
↑230 write_304:
↑231 request->header_out.status = 304;
↑232 return HANDLER_SUCCESS;
↑233
↑234
↑235 error_out_errno:
↑236 http_header_set_errno_status (&request->header_out,request->st->error);
↑237 return HANDLER_FAILURE;
↑238 }
↑239
↑240
↑241 DECLARE_HANDLER_BEGIN (file, CONTENT)
↑242 .DECLARE_HANDLER_NULL (file, setup),
↑243 .DECLARE_HANDLER_NULL (file, init),
↑244 .DECLARE_HANDLER_NULL (file, init_global),
↑245 .DECLARE_HANDLER_NULL (file, free),
↑246 .DECLARE_HANDLER_NULL (file, free_global),
↑247 .DECLARE_HANDLER_SYMBOL (file, exec),
↑248 DECLARE_HANDLER_END
syntax highlighted by Code2HTML, v. 0.9.1