1 |
#include "freehttpd.h" |
#include "freehttpd.h" |
2 |
|
#include "http_error.h" |
3 |
#include "log.h" |
#include "log.h" |
4 |
|
#include "protocol.h" |
5 |
#include "request.h" |
#include "request.h" |
6 |
#include "response.h" |
#include "response.h" |
7 |
|
|
26 |
int sockfd; |
int sockfd; |
27 |
magic_t magic; |
magic_t magic; |
28 |
freehttpd_config_t *config; |
freehttpd_config_t *config; |
29 |
|
freehttpd_errdoc_tbl_t *errdoc_tbl; |
30 |
}; |
}; |
31 |
|
|
32 |
static freehttpd_config_t * |
static freehttpd_config_t * |
68 |
return NULL; |
return NULL; |
69 |
|
|
70 |
freehttpd->sockfd = -1; |
freehttpd->sockfd = -1; |
|
freehttpd->config = freehttpd_config_init (); |
|
71 |
freehttpd->magic = magic; |
freehttpd->magic = magic; |
72 |
|
freehttpd->config = freehttpd_config_init (); |
73 |
|
freehttpd->errdoc_tbl = freehttpd_error_document_tbl_init (); |
74 |
|
|
75 |
|
freehttpd_error_document_load_defaults (freehttpd->errdoc_tbl); |
76 |
return freehttpd; |
return freehttpd; |
77 |
} |
} |
78 |
|
|
128 |
if (freehttpd == NULL) |
if (freehttpd == NULL) |
129 |
return; |
return; |
130 |
|
|
131 |
|
freehttpd_error_document_tbl_free (freehttpd->errdoc_tbl); |
132 |
freehttpd_config_free (freehttpd->config); |
freehttpd_config_free (freehttpd->config); |
133 |
free (freehttpd); |
free (freehttpd); |
134 |
} |
} |
186 |
} |
} |
187 |
|
|
188 |
static ecode_t |
static ecode_t |
189 |
freehttpd_send_error (FILE *stream, int sockfd, freehttpd_status_t status) |
freehttpd_send_error (freehttpd_t *freehttpd, FILE *stream, int sockfd, |
190 |
|
freehttpd_status_t status, const char *version) |
191 |
{ |
{ |
192 |
freehttpd_response_t *response = freehttpd_response_init ("1.1", 3, status); |
freehttpd_response_t *response = freehttpd_response_init ( |
193 |
|
stream, version == NULL ? HTTP1_1 : version, 3, status); |
194 |
|
ecode_t ret = E_OK; |
195 |
|
|
196 |
if (response == NULL) |
if (response == NULL) |
197 |
return E_LIBC_MALLOC; |
return E_LIBC_MALLOC; |
199 |
if (stream == NULL) |
if (stream == NULL) |
200 |
stream = fdopen (sockfd, "w"); |
stream = fdopen (sockfd, "w"); |
201 |
|
|
202 |
|
if (stream == NULL) |
203 |
|
{ |
204 |
|
freehttpd_response_free (response); |
205 |
|
return E_LIBC_FDOPEN; |
206 |
|
} |
207 |
|
|
208 |
freehttpd_response_add_default_headers (response); |
freehttpd_response_add_default_headers (response); |
|
freehttpd_response_add_header (response, "Content-Type", |
|
|
"text/html; charset=\"utf-8\"", 12, 26); |
|
209 |
|
|
210 |
response->body = NULL; |
const freehttpd_errdoc_t *doc |
211 |
(void) (asprintf (&response->body, |
= freehttpd_error_document_get (freehttpd->errdoc_tbl, status); |
|
"<center><h1>%d %s</h1><hr><p>freehttpd</p></center>\r\n", |
|
|
response->status.code, response->status.text) |
|
|
+ 1); |
|
212 |
|
|
213 |
response->body_length = strlen (response->body); |
if (doc == NULL) |
214 |
|
{ |
215 |
|
freehttpd_response_add_header (response, "Content-Length", 0, "0"); |
216 |
|
freehttpd_response_head_send (response); |
217 |
|
freehttpd_response_begin_end (response); |
218 |
|
return E_OK; |
219 |
|
} |
220 |
|
|
221 |
char *len = NULL; |
freehttpd_response_add_header (response, "Content-Type", 0, |
222 |
(void) (asprintf (&len, "%lu", response->body_length) + 1); |
"text/html; charset=\"utf-8\""); |
223 |
|
freehttpd_response_add_header (response, "Content-Length", 0, "%lu", |
224 |
|
doc->document_length); |
225 |
|
|
226 |
freehttpd_response_add_header (response, "Content-Length", len, 14, |
ret = freehttpd_response_head_send (response); |
227 |
strlen (len)); |
|
228 |
|
if (ret != E_OK) |
229 |
|
log_err (LOG_ERR "failed to send error response headers: %i\n", ret); |
230 |
|
|
231 |
ecode_t ret = freehttpd_response_send (response, stream); |
ret = freehttpd_response_begin_body (response); |
232 |
|
|
233 |
if (ret != E_OK) |
if (ret != E_OK) |
234 |
log_err (LOG_ERR "failed to send error response: %i\n", ret); |
log_err (LOG_ERR "failed to start sending response: %i\n", ret); |
235 |
|
|
236 |
|
if (freehttpd_response_write (response, doc->document, 1, |
237 |
|
doc->document_length) |
238 |
|
!= doc->document_length) |
239 |
|
log_err (LOG_ERR "failed to write error response: %i\n", ret); |
240 |
|
|
|
fflush (stream); |
|
|
free (len); |
|
241 |
freehttpd_response_free (response); |
freehttpd_response_free (response); |
242 |
return ret; |
return ret; |
243 |
} |
} |
262 |
va_end (ap); |
va_end (ap); |
263 |
} |
} |
264 |
|
|
265 |
|
/* |
266 |
static ecode_t |
static ecode_t |
267 |
freehttpd_respond_dindex (freehttpd_t *freehttpd, freehttpd_request_t *request, |
freehttpd_respond_dindex (freehttpd_t *freehttpd, freehttpd_request_t *request, |
268 |
freehttpd_response_t *response, FILE *stream, |
freehttpd_response_t *response, FILE *stream, |
269 |
const char *rpath) |
const char *rpath) |
270 |
{ |
{ |
271 |
freehttpd_response_set_status (response, FREEHTTPD_STATUS_OK); |
freehttpd_response_set_status (response, FREEHTTPD_STATUS_OK); |
272 |
ecode_t code = freehttpd_response_send (response, stream); |
ecode_t code = freehttpd_response_head_send (response); |
273 |
|
|
274 |
if (code != E_OK) |
if (code != E_OK) |
275 |
return code; |
return code; |
408 |
closedir (dir); |
closedir (dir); |
409 |
return E_OK; |
return E_OK; |
410 |
} |
} |
411 |
|
*/ |
412 |
|
|
413 |
static ecode_t |
static ecode_t |
414 |
|
freehttpd_respond_http1x (freehttpd_t *freehttpd, freehttpd_request_t *request, |
415 |
|
freehttpd_response_t *response) |
416 |
|
{ |
417 |
|
return freehttpd_send_error (freehttpd, response->stream, 0, |
418 |
|
FREEHTTPD_STATUS_NOT_IMPLEMENTED, |
419 |
|
request->version); |
420 |
|
// return E_OK; |
421 |
|
} |
422 |
|
|
423 |
|
/* |
424 |
|
static ecode_t |
425 |
freehttpd_respond (freehttpd_t *freehttpd, freehttpd_request_t *request, |
freehttpd_respond (freehttpd_t *freehttpd, freehttpd_request_t *request, |
426 |
freehttpd_response_t *response, FILE *stream) |
freehttpd_response_t *response, FILE *stream) |
427 |
{ |
{ |
518 |
content_type = "application/javascript"; |
content_type = "application/javascript"; |
519 |
else |
else |
520 |
{ |
{ |
521 |
magic_descriptor (freehttpd->magic, fileno (file)); |
content_type = magic_descriptor (freehttpd->magic, fileno (file)); |
522 |
|
|
523 |
if (content_type == NULL) |
if (content_type == NULL) |
524 |
content_type = "application/octet-stream"; |
content_type = "application/octet-stream"; |
536 |
} |
} |
537 |
|
|
538 |
freehttpd_response_set_status (response, status); |
freehttpd_response_set_status (response, status); |
539 |
ecode_t code = freehttpd_response_send (response, stream); |
ecode_t code = freehttpd_response_head_send (response); |
540 |
|
|
541 |
if (code != E_OK) |
if (code != E_OK) |
542 |
{ |
{ |
605 |
freehttpd_response_set_status (response, status); |
freehttpd_response_set_status (response, status); |
606 |
|
|
607 |
if (status != FREEHTTPD_STATUS_OK) |
if (status != FREEHTTPD_STATUS_OK) |
608 |
freehttpd_send_error (stream, fileno (stream), status); |
freehttpd_send_error (stream, 0, status, request->version); |
609 |
|
|
610 |
free (rpath); |
free (rpath); |
611 |
free (fs_path); |
free (fs_path); |
612 |
return E_OK; |
return E_OK; |
613 |
} |
} |
614 |
|
*/ |
615 |
|
|
616 |
static ecode_t |
static ecode_t |
617 |
freehttpd_loop (freehttpd_t *freehttpd) |
freehttpd_loop (freehttpd_t *freehttpd) |
634 |
if (code != E_OK) |
if (code != E_OK) |
635 |
{ |
{ |
636 |
log_err (LOG_ERR "failed to parse request: %i\n", code); |
log_err (LOG_ERR "failed to parse request: %i\n", code); |
637 |
freehttpd_send_error (NULL, client_sockfd, |
freehttpd_send_error (freehttpd, NULL, client_sockfd, |
638 |
FREEHTTPD_STATUS_BAD_REQUEST); |
FREEHTTPD_STATUS_BAD_REQUEST, |
639 |
|
HTTP1_1); |
640 |
|
continue; |
641 |
|
} |
642 |
|
|
643 |
|
FILE *stream = fdopen (client_sockfd, "w"); |
644 |
|
|
645 |
|
if (stream == NULL) |
646 |
|
{ |
647 |
|
log_err (LOG_ERR "failed to open stream\n"); |
648 |
|
freehttpd_send_error ( |
649 |
|
freehttpd, NULL, client_sockfd, |
650 |
|
FREEHTTPD_STATUS_INTERNAL_SERVER_ERROR, |
651 |
|
request->version); |
652 |
|
freehttpd_request_free (request); |
653 |
|
close (client_sockfd); |
654 |
continue; |
continue; |
655 |
} |
} |
656 |
|
|
657 |
freehttpd_response_t *response = freehttpd_response_init ( |
freehttpd_response_t *response = freehttpd_response_init ( |
658 |
request->version, request->version_length, FREEHTTPD_STATUS_OK); |
stream, request->version, request->version_length, |
659 |
|
FREEHTTPD_STATUS_OK); |
660 |
|
|
661 |
if (response == NULL) |
if (response == NULL) |
662 |
{ |
{ |
663 |
log_err (LOG_ERR "failed to init response\n"); |
log_err (LOG_ERR "failed to init response\n"); |
664 |
freehttpd_send_error ( |
freehttpd_send_error ( |
665 |
NULL, client_sockfd, |
freehttpd, NULL, client_sockfd, |
666 |
FREEHTTPD_STATUS_INTERNAL_SERVER_ERROR); |
FREEHTTPD_STATUS_INTERNAL_SERVER_ERROR, |
667 |
|
request->version); |
668 |
freehttpd_request_free (request); |
freehttpd_request_free (request); |
669 |
close (client_sockfd); |
close (client_sockfd); |
670 |
continue; |
continue; |
671 |
} |
} |
672 |
|
|
673 |
FILE *stream = fdopen (client_sockfd, "w"); |
code = freehttpd_respond_http1x (freehttpd, request, response); |
|
|
|
|
code = freehttpd_respond (freehttpd, request, response, stream); |
|
674 |
|
|
675 |
log_msg (LOG_INFO "%s %s HTTP/%s - %d %s\n", request->method, |
log_msg (LOG_INFO "%s %s HTTP/%s - %d %s\n", request->method, |
676 |
request->uri, request->version, response->status.code, |
request->uri, request->version, response->status.code, |