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