6 #include "connections.h"
9 #include "configfile.h"
13 #include "http_chunk.h"
14 #include "stat_cache.h"
19 #include "inet_ntop_cache.h"
28 #ifdef HAVE_SYS_FILIO_H
29 # include <sys/filio.h>
32 #include "sys-socket.h"
38 static connection
*connections_get_new_connection(server
*srv
) {
39 connections
*conns
= srv
->conns
;
42 if (conns
->size
== 0) {
43 conns
->size
= srv
->max_conns
>= 128 ? 128 : srv
->max_conns
> 16 ? 16 : srv
->max_conns
;
45 conns
->ptr
= malloc(sizeof(*conns
->ptr
) * conns
->size
);
46 force_assert(NULL
!= conns
->ptr
);
47 for (i
= 0; i
< conns
->size
; i
++) {
48 conns
->ptr
[i
] = connection_init(srv
);
50 } else if (conns
->size
== conns
->used
) {
51 conns
->size
+= srv
->max_conns
>= 128 ? 128 : 16;
52 conns
->ptr
= realloc(conns
->ptr
, sizeof(*conns
->ptr
) * conns
->size
);
53 force_assert(NULL
!= conns
->ptr
);
55 for (i
= conns
->used
; i
< conns
->size
; i
++) {
56 conns
->ptr
[i
] = connection_init(srv
);
60 connection_reset(srv
, conns
->ptr
[conns
->used
]);
62 fprintf(stderr
, "%s.%d: add: ", __FILE__
, __LINE__
);
63 for (i
= 0; i
< conns
->used
+ 1; i
++) {
64 fprintf(stderr
, "%d ", conns
->ptr
[i
]->fd
);
66 fprintf(stderr
, "\n");
69 conns
->ptr
[conns
->used
]->ndx
= conns
->used
;
70 return conns
->ptr
[conns
->used
++];
73 static int connection_del(server
*srv
, connection
*con
) {
75 connections
*conns
= srv
->conns
;
78 if (con
== NULL
) return -1;
80 if (-1 == con
->ndx
) return -1;
82 buffer_reset(con
->uri
.authority
);
83 buffer_reset(con
->uri
.path
);
84 buffer_reset(con
->uri
.query
);
85 buffer_reset(con
->request
.orig_uri
);
89 /* not last element */
91 if (i
!= conns
->used
- 1) {
93 conns
->ptr
[i
] = conns
->ptr
[conns
->used
- 1];
94 conns
->ptr
[conns
->used
- 1] = temp
;
96 conns
->ptr
[i
]->ndx
= i
;
97 conns
->ptr
[conns
->used
- 1]->ndx
= -1;
104 fprintf(stderr
, "%s.%d: del: (%d)", __FILE__
, __LINE__
, conns
->used
);
105 for (i
= 0; i
< conns
->used
; i
++) {
106 fprintf(stderr
, "%d ", conns
->ptr
[i
]->fd
);
108 fprintf(stderr
, "\n");
113 static int connection_close(server
*srv
, connection
*con
) {
114 if (con
->fd
< 0) con
->fd
= -con
->fd
;
116 plugins_call_handle_connection_close(srv
, con
);
118 fdevent_event_del(srv
->ev
, &(con
->fde_ndx
), con
->fd
);
119 fdevent_unregister(srv
->ev
, con
->fd
);
121 if (closesocket(con
->fd
)) {
122 log_error_write(srv
, __FILE__
, __LINE__
, "sds",
123 "(warning) close:", con
->fd
, strerror(errno
));
126 if (close(con
->fd
)) {
127 log_error_write(srv
, __FILE__
, __LINE__
, "sds",
128 "(warning) close:", con
->fd
, strerror(errno
));
135 if (srv
->srvconf
.log_state_handling
) {
136 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
137 "connection closed for fd", con
->fd
);
141 /* plugins should have cleaned themselves up */
142 for (size_t i
= 0; i
< srv
->plugins
.used
; ++i
) {
143 plugin
*p
= ((plugin
**)(srv
->plugins
.ptr
))[i
];
144 plugin_data
*pd
= p
->data
;
145 if (!pd
|| NULL
== con
->plugin_ctx
[pd
->id
]) continue;
146 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
147 "missing cleanup in", p
->name
);
148 con
->plugin_ctx
[pd
->id
] = NULL
;
151 connection_del(srv
, con
);
152 connection_set_state(srv
, con
, CON_STATE_CONNECT
);
157 static void connection_read_for_eos(server
*srv
, connection
*con
) {
158 /* we have to do the linger_on_close stuff regardless
159 * of con->keep_alive; even non-keepalive sockets may
160 * still have unread data, and closing before reading
161 * it will make the client not see all our output.
167 len
= read(con
->fd
, buf
, sizeof(buf
));
168 } while (len
> 0 || (len
< 0 && errno
== EINTR
));
170 if (len
< 0 && errno
== EAGAIN
) return;
171 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
172 if (len
< 0 && errno
== EWOULDBLOCK
) return;
175 /* 0 == len || (len < 0 && (errno is a non-recoverable error)) */
176 con
->close_timeout_ts
= srv
->cur_ts
- (HTTP_LINGER_TIMEOUT
+1);
179 static void connection_handle_close_state(server
*srv
, connection
*con
) {
180 connection_read_for_eos(srv
, con
);
182 if (srv
->cur_ts
- con
->close_timeout_ts
> HTTP_LINGER_TIMEOUT
) {
183 connection_close(srv
, con
);
187 static void connection_handle_shutdown(server
*srv
, connection
*con
) {
188 plugins_call_handle_connection_shut_wr(srv
, con
);
191 connection_reset(srv
, con
);
193 /* close the connection */
194 if (con
->fd
>= 0 && 0 == shutdown(con
->fd
, SHUT_WR
)) {
195 con
->close_timeout_ts
= srv
->cur_ts
;
196 connection_set_state(srv
, con
, CON_STATE_CLOSE
);
198 if (srv
->srvconf
.log_state_handling
) {
199 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
200 "shutdown for fd", con
->fd
);
203 connection_close(srv
, con
);
207 static void connection_handle_response_end_state(server
*srv
, connection
*con
) {
208 /* log the request */
209 /* (even if error, connection dropped, still write to access log if http_status) */
210 if (con
->http_status
) {
211 plugins_call_handle_request_done(srv
, con
);
214 if (con
->state
!= CON_STATE_ERROR
) srv
->con_written
++;
216 if (con
->request
.content_length
!= con
->request_content_queue
->bytes_in
217 || con
->state
== CON_STATE_ERROR
) {
218 /* request body is present and has not been read completely */
222 if (con
->keep_alive
) {
223 connection_reset(srv
, con
);
225 con
->request_start
= srv
->cur_ts
;
226 con
->read_idle_ts
= srv
->cur_ts
;
228 connection_set_state(srv
, con
, CON_STATE_REQUEST_START
);
230 connection_handle_shutdown(srv
, con
);
234 static void connection_handle_errdoc_init(server
*srv
, connection
*con
) {
235 /* modules that produce headers required with error response should
236 * typically also produce an error document. Make an exception for
237 * mod_auth WWW-Authenticate response header. */
238 buffer
*www_auth
= NULL
;
239 if (401 == con
->http_status
) {
240 data_string
*ds
= (data_string
*)array_get_element(con
->response
.headers
, "WWW-Authenticate");
242 www_auth
= buffer_init_buffer(ds
->value
);
246 con
->response
.transfer_encoding
= 0;
247 buffer_reset(con
->physical
.path
);
248 array_reset(con
->response
.headers
);
249 chunkqueue_reset(con
->write_queue
);
251 if (NULL
!= www_auth
) {
252 response_header_insert(srv
, con
, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(www_auth
));
253 buffer_free(www_auth
);
257 static int connection_handle_write_prepare(server
*srv
, connection
*con
) {
258 if (con
->mode
== DIRECT
) {
260 switch(con
->request
.http_method
) {
261 case HTTP_METHOD_GET
:
262 case HTTP_METHOD_POST
:
263 case HTTP_METHOD_HEAD
:
265 case HTTP_METHOD_OPTIONS
:
267 * 400 is coming from the request-parser BEFORE uri.path is set
268 * 403 is from the response handler when noone else catched it
271 if ((!con
->http_status
|| con
->http_status
== 200) && !buffer_string_is_empty(con
->uri
.path
) &&
272 con
->uri
.path
->ptr
[0] != '*') {
273 response_header_insert(srv
, con
, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
275 con
->response
.transfer_encoding
&= ~HTTP_TRANSFER_ENCODING_CHUNKED
;
276 con
->parsed_response
&= ~HTTP_CONTENT_LENGTH
;
278 con
->http_status
= 200;
279 con
->file_finished
= 1;
281 chunkqueue_reset(con
->write_queue
);
285 if (0 == con
->http_status
) {
286 con
->http_status
= 501;
292 if (con
->http_status
== 0) {
293 con
->http_status
= 403;
296 switch(con
->http_status
) {
297 case 204: /* class: header only */
300 /* disable chunked encoding again as we have no body */
301 con
->response
.transfer_encoding
&= ~HTTP_TRANSFER_ENCODING_CHUNKED
;
302 con
->parsed_response
&= ~HTTP_CONTENT_LENGTH
;
303 chunkqueue_reset(con
->write_queue
);
305 con
->file_finished
= 1;
307 default: /* class: header + body */
308 /* only custom body for 4xx and 5xx */
309 if (con
->http_status
< 400 || con
->http_status
>= 600) break;
311 if (con
->mode
!= DIRECT
&& (!con
->conf
.error_intercept
|| con
->error_handler_saved_status
)) break;
313 con
->file_finished
= 0;
315 connection_handle_errdoc_init(srv
, con
);
317 /* try to send static errorfile */
318 if (!buffer_string_is_empty(con
->conf
.errorfile_prefix
)) {
319 stat_cache_entry
*sce
= NULL
;
321 buffer_copy_buffer(con
->physical
.path
, con
->conf
.errorfile_prefix
);
322 buffer_append_int(con
->physical
.path
, con
->http_status
);
323 buffer_append_string_len(con
->physical
.path
, CONST_STR_LEN(".html"));
325 if (0 == http_chunk_append_file(srv
, con
, con
->physical
.path
)) {
326 con
->file_finished
= 1;
327 if (HANDLER_ERROR
!= stat_cache_get_entry(srv
, con
, con
->physical
.path
, &sce
)) {
328 response_header_overwrite(srv
, con
, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce
->content_type
));
333 if (!con
->file_finished
) {
336 buffer_reset(con
->physical
.path
);
338 con
->file_finished
= 1;
341 /* build default error-page */
342 buffer_copy_string_len(b
, CONST_STR_LEN(
343 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
344 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
345 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
346 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
349 buffer_append_int(b
, con
->http_status
);
350 buffer_append_string_len(b
, CONST_STR_LEN(" - "));
351 buffer_append_string(b
, get_http_status_name(con
->http_status
));
353 buffer_append_string_len(b
, CONST_STR_LEN(
358 buffer_append_int(b
, con
->http_status
);
359 buffer_append_string_len(b
, CONST_STR_LEN(" - "));
360 buffer_append_string(b
, get_http_status_name(con
->http_status
));
362 buffer_append_string_len(b
, CONST_STR_LEN("</h1>\n"
367 (void)http_chunk_append_buffer(srv
, con
, b
);
370 response_header_overwrite(srv
, con
, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
375 /* Allow filter plugins to change response headers before they are written. */
376 switch(plugins_call_handle_response_start(srv
, con
)) {
378 case HANDLER_FINISHED
:
381 log_error_write(srv
, __FILE__
, __LINE__
, "s", "response_start plugin failed");
385 if (con
->file_finished
) {
386 /* we have all the content and chunked encoding is not used, set a content-length */
388 if (!(con
->parsed_response
& (HTTP_CONTENT_LENGTH
|HTTP_TRANSFER_ENCODING
))) {
389 off_t qlen
= chunkqueue_length(con
->write_queue
);
392 * The Content-Length header only can be sent if we have content:
393 * - HEAD doesn't have a content-body (but have a content-length)
394 * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
396 * Otherwise generate a Content-Length header as chunked encoding is not
399 if ((con
->http_status
>= 100 && con
->http_status
< 200) ||
400 con
->http_status
== 204 ||
401 con
->http_status
== 304) {
403 /* no Content-Body, no Content-Length */
404 if (NULL
!= (ds
= (data_string
*) array_get_element(con
->response
.headers
, "Content-Length"))) {
405 buffer_reset(ds
->value
); /* Headers with empty values are ignored for output */
407 } else if (qlen
> 0 || con
->request
.http_method
!= HTTP_METHOD_HEAD
) {
408 /* qlen = 0 is important for Redirects (301, ...) as they MAY have
409 * a content. Browsers are waiting for a Content otherwise
411 buffer_copy_int(srv
->tmp_buf
, qlen
);
413 response_header_overwrite(srv
, con
, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv
->tmp_buf
));
418 * the file isn't finished yet, but we have all headers
420 * to get keep-alive we either need:
421 * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
422 * - Transfer-Encoding: chunked (HTTP/1.1)
423 * - Upgrade: ... (lighttpd then acts as transparent proxy)
426 if (!(con
->parsed_response
& (HTTP_CONTENT_LENGTH
|HTTP_TRANSFER_ENCODING
|HTTP_UPGRADE
))) {
427 if (con
->request
.http_version
== HTTP_VERSION_1_1
) {
428 off_t qlen
= chunkqueue_length(con
->write_queue
);
429 con
->response
.transfer_encoding
= HTTP_TRANSFER_ENCODING_CHUNKED
;
431 /* create initial Transfer-Encoding: chunked segment */
432 buffer
*b
= srv
->tmp_chunk_len
;
433 buffer_string_set_length(b
, 0);
434 buffer_append_uint_hex(b
, (uintmax_t)qlen
);
435 buffer_append_string_len(b
, CONST_STR_LEN("\r\n"));
436 chunkqueue_prepend_buffer(con
->write_queue
, b
);
437 chunkqueue_append_mem(con
->write_queue
, CONST_STR_LEN("\r\n"));
439 response_header_append(srv
, con
, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
446 * if the backend sent a Connection: close, follow the wish
448 * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
449 * will close the connection. That's fine. We can always decide the close
452 * FIXME: to be nice we should remove the Connection: ...
454 if (con
->parsed_response
& HTTP_CONNECTION
) {
455 /* a subrequest disable keep-alive although the client wanted it */
456 if (con
->keep_alive
&& !con
->response
.keep_alive
) {
462 if (con
->request
.http_method
== HTTP_METHOD_HEAD
) {
464 * a HEAD request has the same as a GET
465 * without the content
467 con
->file_finished
= 1;
469 chunkqueue_reset(con
->write_queue
);
470 con
->response
.transfer_encoding
&= ~HTTP_TRANSFER_ENCODING_CHUNKED
;
471 if (con
->parsed_response
& HTTP_TRANSFER_ENCODING
) {
473 if (NULL
!= (ds
= (data_string
*) array_get_element(con
->response
.headers
, "Transfer-Encoding"))) {
474 buffer_reset(ds
->value
); /* Headers with empty values are ignored for output */
479 http_response_write_header(srv
, con
);
484 static int connection_handle_write(server
*srv
, connection
*con
) {
485 switch(connection_write_chunkqueue(srv
, con
, con
->write_queue
, MAX_WRITE_LIMIT
)) {
487 con
->write_request_ts
= srv
->cur_ts
;
488 if (con
->file_finished
) {
489 connection_set_state(srv
, con
, CON_STATE_RESPONSE_END
);
492 case -1: /* error on our side */
493 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
494 "connection closed: write failed on fd", con
->fd
);
495 connection_set_state(srv
, con
, CON_STATE_ERROR
);
497 case -2: /* remote close */
498 connection_set_state(srv
, con
, CON_STATE_ERROR
);
501 con
->write_request_ts
= srv
->cur_ts
;
502 con
->is_writable
= 0;
504 /* not finished yet -> WRITE */
513 connection
*connection_init(server
*srv
) {
518 con
= calloc(1, sizeof(*con
));
519 force_assert(NULL
!= con
);
524 con
->bytes_written
= 0;
526 con
->bytes_header
= 0;
527 con
->loops_per_request
= 0;
530 con->x = buffer_init();
533 CLEAN(request
.request_line
);
534 CLEAN(request
.request
);
535 CLEAN(request
.pathinfo
);
537 CLEAN(request
.orig_uri
);
540 CLEAN(uri
.authority
);
545 CLEAN(physical
.doc_root
);
546 CLEAN(physical
.path
);
547 CLEAN(physical
.basedir
);
548 CLEAN(physical
.rel_path
);
549 CLEAN(physical
.etag
);
550 CLEAN(parse_request
);
557 con
->write_queue
= chunkqueue_init();
558 con
->read_queue
= chunkqueue_init();
559 con
->request_content_queue
= chunkqueue_init();
561 con
->request
.headers
= array_init();
562 con
->response
.headers
= array_init();
563 con
->environment
= array_init();
565 /* init plugin specific connection structures */
567 con
->plugin_ctx
= calloc(1, (srv
->plugins
.used
+ 1) * sizeof(void *));
568 force_assert(NULL
!= con
->plugin_ctx
);
570 con
->cond_cache
= calloc(srv
->config_context
->used
, sizeof(cond_cache_t
));
571 force_assert(NULL
!= con
->cond_cache
);
572 config_setup_connection(srv
, con
);
577 void connections_free(server
*srv
) {
578 connections
*conns
= srv
->conns
;
581 if (NULL
== conns
) return;
583 for (i
= 0; i
< conns
->size
; i
++) {
584 connection
*con
= conns
->ptr
[i
];
586 connection_reset(srv
, con
);
588 chunkqueue_free(con
->write_queue
);
589 chunkqueue_free(con
->read_queue
);
590 chunkqueue_free(con
->request_content_queue
);
591 array_free(con
->request
.headers
);
592 array_free(con
->response
.headers
);
593 array_free(con
->environment
);
599 CLEAN(request
.request_line
);
600 CLEAN(request
.request
);
601 CLEAN(request
.pathinfo
);
603 CLEAN(request
.orig_uri
);
606 CLEAN(uri
.authority
);
611 CLEAN(physical
.doc_root
);
612 CLEAN(physical
.path
);
613 CLEAN(physical
.basedir
);
614 CLEAN(physical
.etag
);
615 CLEAN(physical
.rel_path
);
616 CLEAN(parse_request
);
622 free(con
->plugin_ctx
);
623 free(con
->cond_cache
);
634 int connection_reset(server
*srv
, connection
*con
) {
635 plugins_call_connection_reset(srv
, con
);
637 connection_response_reset(srv
, con
);
638 con
->is_readable
= 1;
640 con
->bytes_written
= 0;
641 con
->bytes_written_cur_second
= 0;
643 con
->bytes_header
= 0;
644 con
->loops_per_request
= 0;
646 con
->request
.http_method
= HTTP_METHOD_UNSET
;
647 con
->request
.http_version
= HTTP_VERSION_UNSET
;
649 con
->request
.http_if_modified_since
= NULL
;
650 con
->request
.http_if_none_match
= NULL
;
653 if (con->x) buffer_reset(con->x);
656 CLEAN(request
.request_line
);
657 CLEAN(request
.pathinfo
);
658 CLEAN(request
.request
);
660 /* CLEAN(request.orig_uri); */
663 /* CLEAN(uri.authority); */
664 /* CLEAN(uri.path); */
666 /* CLEAN(uri.query); */
668 CLEAN(parse_request
);
671 /*CLEAN(proto);*//* set to default in connection_accepted() */
675 if (con->x) con->x->used = 0;
680 con->request.x = NULL;
684 CLEAN(http_content_type
);
686 con
->request
.content_length
= 0;
687 con
->request
.te_chunked
= 0;
689 array_reset(con
->request
.headers
);
690 array_reset(con
->environment
);
692 chunkqueue_reset(con
->request_content_queue
);
694 /* The cond_cache gets reset in response.c */
695 /* config_cond_cache_reset(srv, con); */
698 con
->error_handler_saved_status
= 0;
699 /*con->error_handler_saved_method = HTTP_METHOD_UNSET;*/
700 /*(error_handler_saved_method value is not valid unless error_handler_saved_status is set)*/
702 config_setup_connection(srv
, con
);
708 * handle all header and content read
710 * we get called by the state-engine and by the fdevent-handler
712 static int connection_handle_read_state(server
*srv
, connection
*con
) {
713 chunk
*c
, *last_chunk
;
715 chunkqueue
*cq
= con
->read_queue
;
716 int is_closed
= 0; /* the connection got closed, if we don't have a complete header, -> error */
717 /* when in CON_STATE_READ: about to receive first byte for a request: */
718 int is_request_start
= chunkqueue_is_empty(cq
);
720 if (con
->is_readable
) {
721 con
->read_idle_ts
= srv
->cur_ts
;
723 switch(con
->network_read(srv
, con
, con
->read_queue
, MAX_READ_LIMIT
)) {
725 connection_set_state(srv
, con
, CON_STATE_ERROR
);
735 chunkqueue_remove_finished_chunks(cq
);
737 /* we might have got several packets at once
740 /* update request_start timestamp when first byte of
741 * next request is received on a keep-alive connection */
742 if (con
->request_count
> 1 && is_request_start
) {
743 con
->request_start
= srv
->cur_ts
;
744 if (con
->conf
.high_precision_timestamps
)
745 log_clock_gettime_realtime(&con
->request_start_hp
);
748 /* if there is a \r\n\r\n in the chunkqueue
750 * scan the chunk-queue twice
751 * 1. to find the \r\n\r\n
752 * 2. to copy the header-packet
759 for (c
= cq
->first
; c
; c
= c
->next
) {
761 size_t len
= buffer_string_length(c
->mem
) - c
->offset
;
762 const char *b
= c
->mem
->ptr
+ c
->offset
;
764 for (i
= 0; i
< len
; ++i
) {
768 /* chec if \n\r\n follows */
771 const char header_end
[] = "\r\n\r\n";
772 int header_end_match_pos
= 1;
774 for ( ; cc
; cc
= cc
->next
, j
= 0 ) {
775 size_t bblen
= buffer_string_length(cc
->mem
) - cc
->offset
;
776 const char *bb
= cc
->mem
->ptr
+ cc
->offset
;
778 for ( ; j
< bblen
; j
++) {
781 if (ch
== header_end
[header_end_match_pos
]) {
782 header_end_match_pos
++;
783 if (4 == header_end_match_pos
) {
786 goto found_header_end
;
793 } else if ('\n' == ch
) {
794 /* check if \n follows */
796 if (b
[i
+1] == '\n') {
800 } /* else goto reset_search; */
802 for (chunk
*cc
= c
->next
; cc
; cc
= cc
->next
) {
803 size_t bblen
= buffer_string_length(cc
->mem
) - cc
->offset
;
804 const char *bb
= cc
->mem
->ptr
+ cc
->offset
;
805 if (0 == bblen
) continue;
809 goto found_header_end
;
823 buffer_reset(con
->request
.request
);
825 for (c
= cq
->first
; c
; c
= c
->next
) {
826 size_t len
= buffer_string_length(c
->mem
) - c
->offset
;
828 if (c
== last_chunk
) {
832 buffer_append_string_len(con
->request
.request
, c
->mem
->ptr
+ c
->offset
, len
);
834 cq
->bytes_out
+= len
;
836 if (c
== last_chunk
) break;
839 connection_set_state(srv
, con
, CON_STATE_REQUEST_END
);
840 } else if (is_closed
) {
841 /* the connection got closed and we didn't got enough data to leave CON_STATE_READ;
842 * the only way is to leave here */
843 connection_set_state(srv
, con
, CON_STATE_ERROR
);
846 if ((last_chunk
? buffer_string_length(con
->request
.request
) : (size_t)chunkqueue_length(cq
))
847 > srv
->srvconf
.max_request_field_size
) {
848 log_error_write(srv
, __FILE__
, __LINE__
, "s", "oversized request-header -> sending Status 431");
849 con
->http_status
= 431; /* Request Header Fields Too Large */
851 connection_set_state(srv
, con
, CON_STATE_HANDLE_REQUEST
);
854 chunkqueue_remove_finished_chunks(cq
);
859 static handler_t
connection_handle_fdevent(server
*srv
, void *context
, int revents
) {
860 connection
*con
= context
;
862 joblist_append(srv
, con
);
864 if (con
->srv_socket
->is_ssl
) {
865 /* ssl may read and write for both reads and writes */
866 if (revents
& (FDEVENT_IN
| FDEVENT_OUT
)) {
867 con
->is_readable
= 1;
868 con
->is_writable
= 1;
871 if (revents
& FDEVENT_IN
) {
872 con
->is_readable
= 1;
874 if (revents
& FDEVENT_OUT
) {
875 con
->is_writable
= 1;
876 /* we don't need the event twice */
881 if (con
->state
== CON_STATE_READ
) {
882 connection_handle_read_state(srv
, con
);
885 if (con
->state
== CON_STATE_WRITE
&&
886 !chunkqueue_is_empty(con
->write_queue
) &&
889 if (-1 == connection_handle_write(srv
, con
)) {
890 connection_set_state(srv
, con
, CON_STATE_ERROR
);
892 log_error_write(srv
, __FILE__
, __LINE__
, "ds",
894 "handle write failed.");
898 if (con
->state
== CON_STATE_CLOSE
) {
899 /* flush the read buffers */
900 connection_read_for_eos(srv
, con
);
904 /* attempt (above) to read data in kernel socket buffers
905 * prior to handling FDEVENT_HUP and FDEVENT_ERR */
907 if ((revents
& ~(FDEVENT_IN
| FDEVENT_OUT
)) && con
->state
!= CON_STATE_ERROR
) {
908 if (con
->state
== CON_STATE_CLOSE
) {
909 con
->close_timeout_ts
= srv
->cur_ts
- (HTTP_LINGER_TIMEOUT
+1);
910 } else if (revents
& FDEVENT_HUP
) {
911 if (fdevent_is_tcp_half_closed(con
->fd
)) {
914 connection_set_state(srv
, con
, CON_STATE_ERROR
);
916 } else if (revents
& FDEVENT_ERR
) { /* error, connection reset */
917 connection_set_state(srv
, con
, CON_STATE_ERROR
);
919 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
920 "connection closed: poll() -> ???", revents
);
924 return HANDLER_FINISHED
;
928 connection
*connection_accept(server
*srv
, server_socket
*srv_socket
) {
931 size_t cnt_len
= sizeof(cnt_addr
); /*(size_t intentional; not socklen_t)*/
934 * check if we can still open a new connections
939 if (srv
->conns
->used
>= srv
->max_conns
) {
943 cnt
= fdevent_accept_listenfd(srv_socket
->fd
, (struct sockaddr
*) &cnt_addr
, &cnt_len
);
947 #if EWOULDBLOCK != EAGAIN
951 /* we were stopped _before_ we had a connection */
952 case ECONNABORTED
: /* this is a FreeBSD thingy */
953 /* we were stopped _after_ we had a connection */
959 log_error_write(srv
, __FILE__
, __LINE__
, "ssd", "accept failed:", strerror(errno
), errno
);
963 if (sock_addr_get_family(&cnt_addr
) != AF_UNIX
) {
964 network_accept_tcp_nagle_disable(cnt
);
966 return connection_accepted(srv
, srv_socket
, &cnt_addr
, cnt
);
971 /* 0: everything ok, -1: error, -2: con closed */
972 static int connection_read_cq(server
*srv
, connection
*con
, chunkqueue
*cq
, off_t max_bytes
) {
977 force_assert(cq
== con
->read_queue
); /*(code transform assumption; minimize diff)*/
978 force_assert(max_bytes
== MAX_READ_LIMIT
); /*(code transform assumption; minimize diff)*/
980 /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
981 * us more than 4kb is available
982 * if FIONREAD doesn't signal a big chunk we fill the previous buffer
983 * if it has >= 1kb free
985 if (0 != fdevent_ioctl_fionread(con
->fd
, S_IFSOCK
, &toread
) || toread
<= 4096) {
988 else if (toread
> MAX_READ_LIMIT
) {
989 toread
= MAX_READ_LIMIT
;
991 chunkqueue_get_memory(con
->read_queue
, &mem
, &mem_len
, 0, toread
);
994 len
= recv(con
->fd
, mem
, mem_len
, 0);
996 len
= read(con
->fd
, mem
, mem_len
);
999 chunkqueue_use_memory(con
->read_queue
, len
> 0 ? len
: 0);
1002 con
->is_readable
= 0;
1004 #if defined(__WIN32)
1006 int lastError
= WSAGetLastError();
1007 switch (lastError
) {
1011 /* we have been interrupted before we could read */
1012 con
->is_readable
= 1;
1015 /* suppress logging for this error, expected for keep-alive */
1018 log_error_write(srv
, __FILE__
, __LINE__
, "sd", "connection closed - recv failed: ", lastError
);
1027 /* we have been interrupted before we could read */
1028 con
->is_readable
= 1;
1031 /* suppress logging for this error, expected for keep-alive */
1034 log_error_write(srv
, __FILE__
, __LINE__
, "ssd", "connection closed - read failed: ", strerror(errno
), errno
);
1037 #endif /* __WIN32 */
1039 connection_set_state(srv
, con
, CON_STATE_ERROR
);
1042 } else if (len
== 0) {
1043 con
->is_readable
= 0;
1044 /* the other end close the connection -> KEEP-ALIVE */
1049 } else if (len
!= (ssize_t
) mem_len
) {
1050 /* we got less then expected, wait for the next fd-event */
1052 con
->is_readable
= 0;
1055 con
->bytes_read
+= len
;
1060 static int connection_write_cq(server
*srv
, connection
*con
, chunkqueue
*cq
, off_t max_bytes
) {
1061 return srv
->network_backend_write(srv
, con
->fd
, cq
, max_bytes
);
1065 connection
*connection_accepted(server
*srv
, server_socket
*srv_socket
, sock_addr
*cnt_addr
, int cnt
) {
1070 /* ok, we have the connection, register it */
1072 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
1077 con
= connections_get_new_connection(srv
);
1081 fdevent_register(srv
->ev
, con
->fd
, connection_handle_fdevent
, con
);
1082 con
->network_read
= connection_read_cq
;
1083 con
->network_write
= connection_write_cq
;
1085 connection_set_state(srv
, con
, CON_STATE_REQUEST_START
);
1087 con
->connection_start
= srv
->cur_ts
;
1088 con
->dst_addr
= *cnt_addr
;
1089 buffer_copy_string(con
->dst_addr_buf
, inet_ntop_cache_get_ip(srv
, &(con
->dst_addr
)));
1090 con
->srv_socket
= srv_socket
;
1092 config_cond_cache_reset(srv
, con
);
1093 con
->conditional_is_valid
[COMP_SERVER_SOCKET
] = 1;
1094 con
->conditional_is_valid
[COMP_HTTP_REMOTE_IP
] = 1;
1096 if (-1 == fdevent_fcntl_set_nb_cloexec_sock(srv
->ev
, con
->fd
)) {
1097 log_error_write(srv
, __FILE__
, __LINE__
, "ss", "fcntl failed: ", strerror(errno
));
1098 connection_close(srv
, con
);
1101 buffer_copy_string_len(con
->proto
, CONST_STR_LEN("http"));
1102 if (HANDLER_GO_ON
!= plugins_call_handle_connection_accept(srv
, con
)) {
1103 connection_close(srv
, con
);
1110 int connection_state_machine(server
*srv
, connection
*con
) {
1113 if (srv
->srvconf
.log_state_handling
) {
1114 log_error_write(srv
, __FILE__
, __LINE__
, "sds",
1117 connection_get_state(con
->state
));
1121 size_t ostate
= con
->state
;
1123 if (srv
->srvconf
.log_state_handling
) {
1124 log_error_write(srv
, __FILE__
, __LINE__
, "sds",
1125 "state for fd", con
->fd
, connection_get_state(con
->state
));
1128 switch (con
->state
) {
1129 case CON_STATE_REQUEST_START
: /* transient */
1130 con
->request_start
= srv
->cur_ts
;
1131 con
->read_idle_ts
= srv
->cur_ts
;
1132 if (con
->conf
.high_precision_timestamps
)
1133 log_clock_gettime_realtime(&con
->request_start_hp
);
1135 con
->request_count
++;
1136 con
->loops_per_request
= 0;
1138 connection_set_state(srv
, con
, CON_STATE_READ
);
1141 case CON_STATE_REQUEST_END
: /* transient */
1142 buffer_reset(con
->uri
.authority
);
1143 buffer_reset(con
->uri
.path
);
1144 buffer_reset(con
->uri
.query
);
1145 buffer_reset(con
->request
.orig_uri
);
1147 if (http_request_parse(srv
, con
)) {
1148 /* we have to read some data from the POST request */
1150 connection_set_state(srv
, con
, CON_STATE_READ_POST
);
1155 connection_set_state(srv
, con
, CON_STATE_HANDLE_REQUEST
);
1158 case CON_STATE_READ_POST
:
1159 case CON_STATE_HANDLE_REQUEST
:
1161 * the request is parsed
1163 * decided what to do with the request
1169 switch (r
= http_response_prepare(srv
, con
)) {
1170 case HANDLER_WAIT_FOR_EVENT
:
1171 if (!con
->file_finished
&& (!con
->file_started
|| 0 == con
->conf
.stream_response_body
)) {
1172 break; /* come back here */
1174 /* response headers received from backend; fall through to start response */
1176 case HANDLER_FINISHED
:
1177 if (con
->error_handler_saved_status
> 0) {
1178 con
->request
.http_method
= con
->error_handler_saved_method
;
1180 if (con
->mode
== DIRECT
|| con
->conf
.error_intercept
) {
1181 if (con
->error_handler_saved_status
) {
1182 if (con
->error_handler_saved_status
> 0) {
1183 con
->http_status
= con
->error_handler_saved_status
;
1184 } else if (con
->http_status
== 404 || con
->http_status
== 403) {
1185 /* error-handler-404 is a 404 */
1186 con
->http_status
= -con
->error_handler_saved_status
;
1188 /* error-handler-404 is back and has generated content */
1189 /* if Status: was set, take it otherwise use 200 */
1191 } else if (con
->http_status
>= 400) {
1192 buffer
*error_handler
= NULL
;
1193 if (!buffer_string_is_empty(con
->conf
.error_handler
)) {
1194 error_handler
= con
->conf
.error_handler
;
1195 } else if ((con
->http_status
== 404 || con
->http_status
== 403)
1196 && !buffer_string_is_empty(con
->conf
.error_handler_404
)) {
1197 error_handler
= con
->conf
.error_handler_404
;
1200 if (error_handler
) {
1201 /* call error-handler */
1203 /* set REDIRECT_STATUS to save current HTTP status code
1204 * for access by dynamic handlers
1205 * https://redmine.lighttpd.net/issues/1828 */
1207 if (NULL
== (ds
= (data_string
*)array_get_unused_element(con
->environment
, TYPE_STRING
))) {
1208 ds
= data_string_init();
1210 buffer_copy_string_len(ds
->key
, CONST_STR_LEN("REDIRECT_STATUS"));
1211 buffer_append_int(ds
->value
, con
->http_status
);
1212 array_insert_unique(con
->environment
, (data_unset
*)ds
);
1214 if (error_handler
== con
->conf
.error_handler
) {
1215 plugins_call_connection_reset(srv
, con
);
1217 if (con
->request
.content_length
) {
1218 if (con
->request
.content_length
!= con
->request_content_queue
->bytes_in
) {
1219 con
->keep_alive
= 0;
1221 con
->request
.content_length
= 0;
1222 chunkqueue_reset(con
->request_content_queue
);
1225 con
->is_writable
= 1;
1226 con
->file_finished
= 0;
1227 con
->file_started
= 0;
1228 con
->parsed_response
= 0;
1229 con
->response
.keep_alive
= 0;
1230 con
->response
.content_length
= -1;
1231 con
->response
.transfer_encoding
= 0;
1233 con
->error_handler_saved_status
= con
->http_status
;
1234 con
->error_handler_saved_method
= con
->request
.http_method
;
1236 con
->request
.http_method
= HTTP_METHOD_GET
;
1237 } else { /*(preserve behavior for server.error-handler-404)*/
1238 con
->error_handler_saved_status
= -con
->http_status
; /*(negative to flag old behavior)*/
1241 buffer_copy_buffer(con
->request
.uri
, error_handler
);
1242 connection_handle_errdoc_init(srv
, con
);
1243 con
->http_status
= 0; /*(after connection_handle_errdoc_init())*/
1250 if (con
->http_status
== 0) con
->http_status
= 200;
1252 /* we have something to send, go on */
1253 connection_set_state(srv
, con
, CON_STATE_RESPONSE_START
);
1255 case HANDLER_WAIT_FOR_FD
:
1258 fdwaitqueue_append(srv
, con
);
1261 case HANDLER_COMEBACK
:
1265 /* something went wrong */
1266 connection_set_state(srv
, con
, CON_STATE_ERROR
);
1269 log_error_write(srv
, __FILE__
, __LINE__
, "sdd", "unknown ret-value: ", con
->fd
, r
);
1273 if (con
->state
== CON_STATE_HANDLE_REQUEST
&& ostate
== CON_STATE_READ_POST
) {
1274 ostate
= CON_STATE_HANDLE_REQUEST
;
1277 case CON_STATE_RESPONSE_START
:
1279 * the decision is done
1280 * - create the HTTP-Response-Header
1284 if (-1 == connection_handle_write_prepare(srv
, con
)) {
1285 connection_set_state(srv
, con
, CON_STATE_ERROR
);
1290 connection_set_state(srv
, con
, CON_STATE_WRITE
);
1292 case CON_STATE_RESPONSE_END
: /* transient */
1293 case CON_STATE_ERROR
: /* transient */
1294 connection_handle_response_end_state(srv
, con
);
1296 case CON_STATE_CONNECT
:
1297 chunkqueue_reset(con
->read_queue
);
1299 con
->request_count
= 0;
1302 case CON_STATE_CLOSE
:
1303 connection_handle_close_state(srv
, con
);
1305 case CON_STATE_READ
:
1306 connection_handle_read_state(srv
, con
);
1308 case CON_STATE_WRITE
:
1310 /* only try to write if we have something in the queue */
1311 if (!chunkqueue_is_empty(con
->write_queue
)) {
1312 if (con
->is_writable
) {
1313 if (-1 == connection_handle_write(srv
, con
)) {
1314 log_error_write(srv
, __FILE__
, __LINE__
, "ds",
1316 "handle write failed.");
1317 connection_set_state(srv
, con
, CON_STATE_ERROR
);
1320 if (con
->state
!= CON_STATE_WRITE
) break;
1322 } else if (con
->file_finished
) {
1323 connection_set_state(srv
, con
, CON_STATE_RESPONSE_END
);
1327 if (con
->mode
!= DIRECT
&& !con
->file_finished
) {
1328 switch(r
= plugins_call_handle_subrequest(srv
, con
)) {
1329 case HANDLER_WAIT_FOR_EVENT
:
1330 case HANDLER_FINISHED
:
1333 case HANDLER_WAIT_FOR_FD
:
1335 fdwaitqueue_append(srv
, con
);
1337 case HANDLER_COMEBACK
:
1339 log_error_write(srv
, __FILE__
, __LINE__
, "sdd", "unexpected subrequest handler ret-value: ", con
->fd
, r
);
1342 connection_set_state(srv
, con
, CON_STATE_ERROR
);
1346 } while (con
->state
== CON_STATE_WRITE
&& (!chunkqueue_is_empty(con
->write_queue
) ? con
->is_writable
: con
->file_finished
));
1350 log_error_write(srv
, __FILE__
, __LINE__
, "sdd",
1351 "unknown state:", con
->fd
, con
->state
);
1358 } else if (ostate
== con
->state
) {
1363 if (srv
->srvconf
.log_state_handling
) {
1364 log_error_write(srv
, __FILE__
, __LINE__
, "sds",
1367 connection_get_state(con
->state
));
1371 switch(con
->state
) {
1372 case CON_STATE_READ
:
1373 case CON_STATE_CLOSE
:
1376 case CON_STATE_WRITE
:
1377 /* request write-fdevent only if we really need it
1378 * - if we have data to write
1379 * - if the socket is not writable yet
1381 if (!chunkqueue_is_empty(con
->write_queue
) &&
1382 (con
->is_writable
== 0) &&
1383 (con
->traffic_limit_reached
== 0)) {
1387 case CON_STATE_READ_POST
:
1388 if (con
->conf
.stream_request_body
& FDEVENT_STREAM_REQUEST_POLLIN
) {
1396 const int events
= fdevent_event_get_interest(srv
->ev
, con
->fd
);
1397 if (con
->is_readable
< 0) {
1398 con
->is_readable
= 0;
1401 if (con
->is_writable
< 0) {
1402 con
->is_writable
= 0;
1406 /* update timestamps when enabling interest in events */
1407 if ((r
& FDEVENT_IN
) && !(events
& FDEVENT_IN
)) {
1408 con
->read_idle_ts
= srv
->cur_ts
;
1410 if ((r
& FDEVENT_OUT
) && !(events
& FDEVENT_OUT
)) {
1411 con
->write_request_ts
= srv
->cur_ts
;
1413 fdevent_event_set(srv
->ev
, &con
->fde_ndx
, con
->fd
, r
);