Annotation of embedaddon/lighttpd/src/connections.c, revision 1.1.1.3
1.1.1.3 ! misho 1: #include "first.h"
! 2:
1.1 misho 3: #include "buffer.h"
4: #include "server.h"
5: #include "log.h"
6: #include "connections.h"
7: #include "fdevent.h"
8:
1.1.1.3 ! misho 9: #include "configfile.h"
1.1 misho 10: #include "request.h"
11: #include "response.h"
12: #include "network.h"
13: #include "http_chunk.h"
14: #include "stat_cache.h"
15: #include "joblist.h"
16:
17: #include "plugin.h"
18:
19: #include "inet_ntop_cache.h"
20:
21: #include <sys/stat.h>
22:
23: #include <stdlib.h>
24: #include <stdio.h>
25: #include <unistd.h>
26: #include <errno.h>
27: #include <string.h>
28: #include <fcntl.h>
29: #include <assert.h>
30:
31: #ifdef USE_OPENSSL
32: # include <openssl/ssl.h>
33: # include <openssl/err.h>
34: #endif
35:
36: #ifdef HAVE_SYS_FILIO_H
37: # include <sys/filio.h>
38: #endif
39:
40: #include "sys-socket.h"
41:
42: typedef struct {
43: PLUGIN_DATA;
44: } plugin_data;
45:
46: static connection *connections_get_new_connection(server *srv) {
47: connections *conns = srv->conns;
48: size_t i;
49:
50: if (conns->size == 0) {
51: conns->size = 128;
52: conns->ptr = NULL;
53: conns->ptr = malloc(sizeof(*conns->ptr) * conns->size);
1.1.1.3 ! misho 54: force_assert(NULL != conns->ptr);
1.1 misho 55: for (i = 0; i < conns->size; i++) {
56: conns->ptr[i] = connection_init(srv);
57: }
58: } else if (conns->size == conns->used) {
59: conns->size += 128;
60: conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
1.1.1.3 ! misho 61: force_assert(NULL != conns->ptr);
1.1 misho 62:
63: for (i = conns->used; i < conns->size; i++) {
64: conns->ptr[i] = connection_init(srv);
65: }
66: }
67:
68: connection_reset(srv, conns->ptr[conns->used]);
69: #if 0
70: fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
71: for (i = 0; i < conns->used + 1; i++) {
72: fprintf(stderr, "%d ", conns->ptr[i]->fd);
73: }
74: fprintf(stderr, "\n");
75: #endif
76:
77: conns->ptr[conns->used]->ndx = conns->used;
78: return conns->ptr[conns->used++];
79: }
80:
81: static int connection_del(server *srv, connection *con) {
82: size_t i;
83: connections *conns = srv->conns;
84: connection *temp;
85:
86: if (con == NULL) return -1;
87:
88: if (-1 == con->ndx) return -1;
89:
90: buffer_reset(con->uri.authority);
91: buffer_reset(con->uri.path);
92: buffer_reset(con->uri.query);
93: buffer_reset(con->request.orig_uri);
94:
95: i = con->ndx;
96:
97: /* not last element */
98:
99: if (i != conns->used - 1) {
100: temp = conns->ptr[i];
101: conns->ptr[i] = conns->ptr[conns->used - 1];
102: conns->ptr[conns->used - 1] = temp;
103:
104: conns->ptr[i]->ndx = i;
105: conns->ptr[conns->used - 1]->ndx = -1;
106: }
107:
108: conns->used--;
109:
110: con->ndx = -1;
111: #if 0
112: fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
113: for (i = 0; i < conns->used; i++) {
114: fprintf(stderr, "%d ", conns->ptr[i]->fd);
115: }
116: fprintf(stderr, "\n");
117: #endif
118: return 0;
119: }
120:
1.1.1.3 ! misho 121: static int connection_close(server *srv, connection *con) {
1.1 misho 122: #ifdef USE_OPENSSL
123: server_socket *srv_sock = con->srv_socket;
124: if (srv_sock->is_ssl) {
125: if (con->ssl) SSL_free(con->ssl);
126: con->ssl = NULL;
127: }
128: #endif
129:
130: fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
131: fdevent_unregister(srv->ev, con->fd);
132: #ifdef __WIN32
133: if (closesocket(con->fd)) {
134: log_error_write(srv, __FILE__, __LINE__, "sds",
135: "(warning) close:", con->fd, strerror(errno));
136: }
137: #else
138: if (close(con->fd)) {
139: log_error_write(srv, __FILE__, __LINE__, "sds",
140: "(warning) close:", con->fd, strerror(errno));
141: }
142: #endif
1.1.1.3 ! misho 143: con->fd = -1;
1.1 misho 144:
145: srv->cur_fds--;
146: #if 0
147: log_error_write(srv, __FILE__, __LINE__, "sd",
148: "closed()", con->fd);
149: #endif
150:
151: connection_del(srv, con);
152: connection_set_state(srv, con, CON_STATE_CONNECT);
153:
154: return 0;
155: }
156:
1.1.1.3 ! misho 157: static void connection_handle_close_state(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.
! 162: */
! 163: int len;
! 164: char buf[1024];
1.1 misho 165:
1.1.1.3 ! misho 166: len = read(con->fd, buf, sizeof(buf));
! 167: if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {
! 168: con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
1.1 misho 169: }
170:
1.1.1.3 ! misho 171: if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) {
! 172: connection_close(srv, con);
1.1 misho 173:
1.1.1.3 ! misho 174: if (srv->srvconf.log_state_handling) {
! 175: log_error_write(srv, __FILE__, __LINE__, "sd",
! 176: "connection closed for fd", con->fd);
1.1 misho 177: }
178: }
179: }
180:
1.1.1.3 ! misho 181: static void connection_handle_shutdown(server *srv, connection *con) {
! 182: int r;
1.1 misho 183:
1.1.1.3 ! misho 184: #ifdef USE_OPENSSL
! 185: server_socket *srv_sock = con->srv_socket;
! 186: if (srv_sock->is_ssl) {
! 187: int ret, ssl_r;
! 188: unsigned long err;
! 189: ERR_clear_error();
! 190: switch ((ret = SSL_shutdown(con->ssl))) {
! 191: case 1:
! 192: /* ok */
! 193: break;
! 194: case 0:
! 195: /* wait for fd-event
1.1 misho 196: *
1.1.1.3 ! misho 197: * FIXME: wait for fdevent and call SSL_shutdown again
1.1 misho 198: *
199: */
1.1.1.3 ! misho 200: ERR_clear_error();
! 201: if (-1 != (ret = SSL_shutdown(con->ssl))) break;
1.1 misho 202:
1.1.1.3 ! misho 203: /* fall through */
! 204: default:
1.1 misho 205:
1.1.1.3 ! misho 206: switch ((ssl_r = SSL_get_error(con->ssl, ret))) {
! 207: case SSL_ERROR_ZERO_RETURN:
! 208: break;
! 209: case SSL_ERROR_WANT_WRITE:
! 210: /*con->is_writable = -1;*//*(no effect; shutdown() called below)*/
! 211: case SSL_ERROR_WANT_READ:
! 212: break;
! 213: case SSL_ERROR_SYSCALL:
! 214: /* perhaps we have error waiting in our error-queue */
! 215: if (0 != (err = ERR_get_error())) {
! 216: do {
! 217: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 218: ssl_r, ret,
! 219: ERR_error_string(err, NULL));
! 220: } while((err = ERR_get_error()));
! 221: } else if (errno != 0) { /* ssl bug (see lighttpd ticket #2213): sometimes errno == 0 */
! 222: switch(errno) {
! 223: case EPIPE:
! 224: case ECONNRESET:
! 225: break;
! 226: default:
! 227: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
! 228: ssl_r, ret, errno,
! 229: strerror(errno));
! 230: break;
! 231: }
! 232: }
1.1 misho 233:
1.1.1.3 ! misho 234: break;
! 235: default:
! 236: while((err = ERR_get_error())) {
! 237: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 238: ssl_r, ret,
! 239: ERR_error_string(err, NULL));
1.1 misho 240: }
1.1.1.3 ! misho 241:
! 242: break;
1.1 misho 243: }
244: }
1.1.1.3 ! misho 245: ERR_clear_error();
! 246: }
! 247: #endif
1.1 misho 248:
1.1.1.3 ! misho 249: switch(r = plugins_call_handle_connection_close(srv, con)) {
! 250: case HANDLER_GO_ON:
! 251: case HANDLER_FINISHED:
! 252: break;
! 253: default:
! 254: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
! 255: break;
! 256: }
! 257:
! 258: srv->con_closed++;
! 259: connection_reset(srv, con);
1.1 misho 260:
1.1.1.3 ! misho 261: /* close the connection */
! 262: if ((0 == shutdown(con->fd, SHUT_WR))) {
! 263: con->close_timeout_ts = srv->cur_ts;
! 264: connection_set_state(srv, con, CON_STATE_CLOSE);
1.1 misho 265:
1.1.1.3 ! misho 266: if (srv->srvconf.log_state_handling) {
! 267: log_error_write(srv, __FILE__, __LINE__, "sd",
! 268: "shutdown for fd", con->fd);
! 269: }
1.1 misho 270: } else {
1.1.1.3 ! misho 271: connection_close(srv, con);
1.1 misho 272: }
273: }
274:
1.1.1.3 ! misho 275: static void connection_handle_response_end_state(server *srv, connection *con) {
! 276: /* log the request */
! 277: /* (even if error, connection dropped, still write to access log if http_status) */
! 278: if (con->http_status) {
! 279: plugins_call_handle_request_done(srv, con);
1.1 misho 280: }
281:
1.1.1.3 ! misho 282: if (con->state != CON_STATE_ERROR) srv->con_written++;
1.1 misho 283:
1.1.1.3 ! misho 284: if ((con->request.content_length
! 285: && (off_t)con->request.content_length > con->request_content_queue->bytes_in)
! 286: || con->state == CON_STATE_ERROR) {
! 287: /* request body is present and has not been read completely */
! 288: con->keep_alive = 0;
1.1 misho 289: }
290:
1.1.1.3 ! misho 291: if (con->keep_alive) {
! 292: connection_reset(srv, con);
! 293: #if 0
! 294: con->request_start = srv->cur_ts;
! 295: con->read_idle_ts = srv->cur_ts;
! 296: #endif
! 297: connection_set_state(srv, con, CON_STATE_REQUEST_START);
1.1 misho 298: } else {
1.1.1.3 ! misho 299: connection_handle_shutdown(srv, con);
1.1 misho 300: }
1.1.1.3 ! misho 301: }
1.1 misho 302:
1.1.1.3 ! misho 303: static void connection_handle_errdoc_init(server *srv, connection *con) {
! 304: /* modules that produce headers required with error response should
! 305: * typically also produce an error document. Make an exception for
! 306: * mod_auth WWW-Authenticate response header. */
! 307: buffer *www_auth = NULL;
! 308: if (401 == con->http_status) {
! 309: data_string *ds = (data_string *)array_get_element(con->response.headers, "WWW-Authenticate");
! 310: if (NULL != ds) {
! 311: www_auth = buffer_init_buffer(ds->value);
1.1 misho 312: }
313: }
314:
1.1.1.3 ! misho 315: con->response.transfer_encoding = 0;
! 316: buffer_reset(con->physical.path);
! 317: array_reset(con->response.headers);
! 318: chunkqueue_reset(con->write_queue);
1.1 misho 319:
1.1.1.3 ! misho 320: if (NULL != www_auth) {
! 321: response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(www_auth));
! 322: buffer_free(www_auth);
! 323: }
1.1 misho 324: }
325:
326: static int connection_handle_write_prepare(server *srv, connection *con) {
327: if (con->mode == DIRECT) {
328: /* static files */
329: switch(con->request.http_method) {
330: case HTTP_METHOD_GET:
331: case HTTP_METHOD_POST:
332: case HTTP_METHOD_HEAD:
333: break;
334: case HTTP_METHOD_OPTIONS:
335: /*
336: * 400 is coming from the request-parser BEFORE uri.path is set
337: * 403 is from the response handler when noone else catched it
338: *
339: * */
1.1.1.3 ! misho 340: if ((!con->http_status || con->http_status == 200) && !buffer_string_is_empty(con->uri.path) &&
1.1 misho 341: con->uri.path->ptr[0] != '*') {
342: response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
343:
344: con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
345: con->parsed_response &= ~HTTP_CONTENT_LENGTH;
346:
347: con->http_status = 200;
348: con->file_finished = 1;
349:
350: chunkqueue_reset(con->write_queue);
351: }
352: break;
353: default:
354: if (0 == con->http_status) {
355: con->http_status = 501;
356: }
357: break;
358: }
359: }
360:
361: if (con->http_status == 0) {
362: con->http_status = 403;
363: }
364:
365: switch(con->http_status) {
366: case 204: /* class: header only */
367: case 205:
368: case 304:
369: /* disable chunked encoding again as we have no body */
370: con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
371: con->parsed_response &= ~HTTP_CONTENT_LENGTH;
372: chunkqueue_reset(con->write_queue);
373:
374: con->file_finished = 1;
375: break;
376: default: /* class: header + body */
377: if (con->mode != DIRECT) break;
378:
379: /* only custom body for 4xx and 5xx */
380: if (con->http_status < 400 || con->http_status >= 600) break;
381:
382: con->file_finished = 0;
383:
1.1.1.3 ! misho 384: connection_handle_errdoc_init(srv, con);
1.1 misho 385:
386: /* try to send static errorfile */
1.1.1.3 ! misho 387: if (!buffer_string_is_empty(con->conf.errorfile_prefix)) {
1.1 misho 388: stat_cache_entry *sce = NULL;
389:
1.1.1.3 ! misho 390: buffer_copy_buffer(con->physical.path, con->conf.errorfile_prefix);
! 391: buffer_append_int(con->physical.path, con->http_status);
1.1 misho 392: buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
393:
1.1.1.3 ! misho 394: if (0 == http_chunk_append_file(srv, con, con->physical.path)) {
1.1 misho 395: con->file_finished = 1;
1.1.1.3 ! misho 396: if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
! 397: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
! 398: }
1.1 misho 399: }
400: }
401:
402: if (!con->file_finished) {
403: buffer *b;
404:
405: buffer_reset(con->physical.path);
406:
407: con->file_finished = 1;
1.1.1.3 ! misho 408: b = buffer_init();
1.1 misho 409:
410: /* build default error-page */
411: buffer_copy_string_len(b, CONST_STR_LEN(
412: "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
413: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
414: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
415: "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
416: " <head>\n"
417: " <title>"));
1.1.1.3 ! misho 418: buffer_append_int(b, con->http_status);
1.1 misho 419: buffer_append_string_len(b, CONST_STR_LEN(" - "));
420: buffer_append_string(b, get_http_status_name(con->http_status));
421:
422: buffer_append_string_len(b, CONST_STR_LEN(
423: "</title>\n"
424: " </head>\n"
425: " <body>\n"
426: " <h1>"));
1.1.1.3 ! misho 427: buffer_append_int(b, con->http_status);
1.1 misho 428: buffer_append_string_len(b, CONST_STR_LEN(" - "));
429: buffer_append_string(b, get_http_status_name(con->http_status));
430:
431: buffer_append_string_len(b, CONST_STR_LEN("</h1>\n"
432: " </body>\n"
433: "</html>\n"
434: ));
435:
1.1.1.3 ! misho 436: (void)http_chunk_append_buffer(srv, con, b);
! 437: buffer_free(b);
! 438:
1.1 misho 439: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
440: }
441: break;
442: }
443:
444: if (con->file_finished) {
445: /* we have all the content and chunked encoding is not used, set a content-length */
446:
447: if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
448: (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
449: off_t qlen = chunkqueue_length(con->write_queue);
450:
451: /**
452: * The Content-Length header only can be sent if we have content:
453: * - HEAD doesn't have a content-body (but have a content-length)
454: * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
455: *
456: * Otherwise generate a Content-Length header as chunked encoding is not
457: * available
458: */
459: if ((con->http_status >= 100 && con->http_status < 200) ||
460: con->http_status == 204 ||
461: con->http_status == 304) {
462: data_string *ds;
463: /* no Content-Body, no Content-Length */
464: if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) {
465: buffer_reset(ds->value); /* Headers with empty values are ignored for output */
466: }
467: } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) {
468: /* qlen = 0 is important for Redirects (301, ...) as they MAY have
469: * a content. Browsers are waiting for a Content otherwise
470: */
1.1.1.3 ! misho 471: buffer_copy_int(srv->tmp_buf, qlen);
1.1 misho 472:
473: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
474: }
475: }
476: } else {
477: /**
478: * the file isn't finished yet, but we have all headers
479: *
480: * to get keep-alive we either need:
481: * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
482: * - Transfer-Encoding: chunked (HTTP/1.1)
483: */
484:
485: if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) &&
486: ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
1.1.1.3 ! misho 487: if (con->request.http_version == HTTP_VERSION_1_1) {
! 488: off_t qlen = chunkqueue_length(con->write_queue);
! 489: con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
! 490: if (qlen) {
! 491: /* create initial Transfer-Encoding: chunked segment */
! 492: buffer *b = srv->tmp_chunk_len;
! 493: buffer_string_set_length(b, 0);
! 494: buffer_append_uint_hex(b, (uintmax_t)qlen);
! 495: buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
! 496: chunkqueue_prepend_buffer(con->write_queue, b);
! 497: chunkqueue_append_mem(con->write_queue, CONST_STR_LEN("\r\n"));
! 498: }
! 499: } else {
! 500: con->keep_alive = 0;
! 501: }
1.1 misho 502: }
503:
504: /**
505: * if the backend sent a Connection: close, follow the wish
506: *
507: * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
508: * will close the connection. That's fine. We can always decide the close
509: * the connection
510: *
511: * FIXME: to be nice we should remove the Connection: ...
512: */
513: if (con->parsed_response & HTTP_CONNECTION) {
514: /* a subrequest disable keep-alive although the client wanted it */
515: if (con->keep_alive && !con->response.keep_alive) {
516: con->keep_alive = 0;
517: }
518: }
519: }
520:
521: if (con->request.http_method == HTTP_METHOD_HEAD) {
522: /**
523: * a HEAD request has the same as a GET
524: * without the content
525: */
526: con->file_finished = 1;
527:
528: chunkqueue_reset(con->write_queue);
529: con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
530: }
531:
532: http_response_write_header(srv, con);
533:
534: return 0;
535: }
536:
537: static int connection_handle_write(server *srv, connection *con) {
538: switch(network_write_chunkqueue(srv, con, con->write_queue, MAX_WRITE_LIMIT)) {
539: case 0:
540: con->write_request_ts = srv->cur_ts;
541: if (con->file_finished) {
542: connection_set_state(srv, con, CON_STATE_RESPONSE_END);
543: }
544: break;
545: case -1: /* error on our side */
546: log_error_write(srv, __FILE__, __LINE__, "sd",
547: "connection closed: write failed on fd", con->fd);
548: connection_set_state(srv, con, CON_STATE_ERROR);
549: break;
550: case -2: /* remote close */
551: connection_set_state(srv, con, CON_STATE_ERROR);
552: break;
553: case 1:
554: con->write_request_ts = srv->cur_ts;
555: con->is_writable = 0;
556:
557: /* not finished yet -> WRITE */
558: break;
559: }
560:
561: return 0;
562: }
563:
564:
565:
566: connection *connection_init(server *srv) {
567: connection *con;
568:
569: UNUSED(srv);
570:
571: con = calloc(1, sizeof(*con));
1.1.1.3 ! misho 572: force_assert(NULL != con);
1.1 misho 573:
574: con->fd = 0;
575: con->ndx = -1;
576: con->fde_ndx = -1;
577: con->bytes_written = 0;
578: con->bytes_read = 0;
579: con->bytes_header = 0;
580: con->loops_per_request = 0;
581:
582: #define CLEAN(x) \
583: con->x = buffer_init();
584:
585: CLEAN(request.uri);
586: CLEAN(request.request_line);
587: CLEAN(request.request);
588: CLEAN(request.pathinfo);
589:
590: CLEAN(request.orig_uri);
591:
592: CLEAN(uri.scheme);
593: CLEAN(uri.authority);
594: CLEAN(uri.path);
595: CLEAN(uri.path_raw);
596: CLEAN(uri.query);
597:
598: CLEAN(physical.doc_root);
599: CLEAN(physical.path);
600: CLEAN(physical.basedir);
601: CLEAN(physical.rel_path);
602: CLEAN(physical.etag);
603: CLEAN(parse_request);
604:
605: CLEAN(server_name);
606: CLEAN(dst_addr_buf);
607: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
608: CLEAN(tlsext_server_name);
609: #endif
610:
611: #undef CLEAN
612: con->write_queue = chunkqueue_init();
613: con->read_queue = chunkqueue_init();
614: con->request_content_queue = chunkqueue_init();
615:
616: con->request.headers = array_init();
617: con->response.headers = array_init();
618: con->environment = array_init();
619:
620: /* init plugin specific connection structures */
621:
622: con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
1.1.1.3 ! misho 623: force_assert(NULL != con->plugin_ctx);
1.1 misho 624:
625: con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
1.1.1.3 ! misho 626: force_assert(NULL != con->cond_cache);
1.1 misho 627: config_setup_connection(srv, con);
628:
629: return con;
630: }
631:
632: void connections_free(server *srv) {
633: connections *conns = srv->conns;
634: size_t i;
635:
636: for (i = 0; i < conns->size; i++) {
637: connection *con = conns->ptr[i];
638:
639: connection_reset(srv, con);
640:
641: chunkqueue_free(con->write_queue);
642: chunkqueue_free(con->read_queue);
643: chunkqueue_free(con->request_content_queue);
644: array_free(con->request.headers);
645: array_free(con->response.headers);
646: array_free(con->environment);
647:
648: #define CLEAN(x) \
649: buffer_free(con->x);
650:
651: CLEAN(request.uri);
652: CLEAN(request.request_line);
653: CLEAN(request.request);
654: CLEAN(request.pathinfo);
655:
656: CLEAN(request.orig_uri);
657:
658: CLEAN(uri.scheme);
659: CLEAN(uri.authority);
660: CLEAN(uri.path);
661: CLEAN(uri.path_raw);
662: CLEAN(uri.query);
663:
664: CLEAN(physical.doc_root);
665: CLEAN(physical.path);
666: CLEAN(physical.basedir);
667: CLEAN(physical.etag);
668: CLEAN(physical.rel_path);
669: CLEAN(parse_request);
670:
671: CLEAN(server_name);
672: CLEAN(dst_addr_buf);
673: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
674: CLEAN(tlsext_server_name);
675: #endif
676: #undef CLEAN
677: free(con->plugin_ctx);
678: free(con->cond_cache);
679:
680: free(con);
681: }
682:
683: free(conns->ptr);
684: }
685:
686:
687: int connection_reset(server *srv, connection *con) {
688: size_t i;
689:
690: plugins_call_connection_reset(srv, con);
691:
692: con->is_readable = 1;
693: con->is_writable = 1;
694: con->http_status = 0;
695: con->file_finished = 0;
696: con->file_started = 0;
697: con->got_response = 0;
698:
699: con->parsed_response = 0;
700:
701: con->bytes_written = 0;
702: con->bytes_written_cur_second = 0;
703: con->bytes_read = 0;
704: con->bytes_header = 0;
705: con->loops_per_request = 0;
706:
707: con->request.http_method = HTTP_METHOD_UNSET;
708: con->request.http_version = HTTP_VERSION_UNSET;
709:
710: con->request.http_if_modified_since = NULL;
711: con->request.http_if_none_match = NULL;
712:
713: con->response.keep_alive = 0;
714: con->response.content_length = -1;
715: con->response.transfer_encoding = 0;
716:
717: con->mode = DIRECT;
718:
719: #define CLEAN(x) \
720: if (con->x) buffer_reset(con->x);
721:
722: CLEAN(request.uri);
723: CLEAN(request.request_line);
724: CLEAN(request.pathinfo);
725: CLEAN(request.request);
726:
727: /* CLEAN(request.orig_uri); */
728:
729: CLEAN(uri.scheme);
730: /* CLEAN(uri.authority); */
731: /* CLEAN(uri.path); */
732: CLEAN(uri.path_raw);
733: /* CLEAN(uri.query); */
734:
735: CLEAN(physical.doc_root);
736: CLEAN(physical.path);
737: CLEAN(physical.basedir);
738: CLEAN(physical.rel_path);
739: CLEAN(physical.etag);
740:
741: CLEAN(parse_request);
742:
743: CLEAN(server_name);
744: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
745: CLEAN(tlsext_server_name);
746: #endif
747: #undef CLEAN
748:
749: #define CLEAN(x) \
750: if (con->x) con->x->used = 0;
751:
752: #undef CLEAN
753:
754: #define CLEAN(x) \
755: con->request.x = NULL;
756:
757: CLEAN(http_host);
758: CLEAN(http_range);
759: CLEAN(http_content_type);
760: #undef CLEAN
761: con->request.content_length = 0;
762:
763: array_reset(con->request.headers);
764: array_reset(con->response.headers);
765: array_reset(con->environment);
766:
767: chunkqueue_reset(con->write_queue);
768: chunkqueue_reset(con->request_content_queue);
769:
770: /* the plugins should cleanup themself */
771: for (i = 0; i < srv->plugins.used; i++) {
772: plugin *p = ((plugin **)(srv->plugins.ptr))[i];
773: plugin_data *pd = p->data;
774:
775: if (!pd) continue;
776:
777: if (con->plugin_ctx[pd->id] != NULL) {
778: log_error_write(srv, __FILE__, __LINE__, "sb", "missing cleanup in", p->name);
779: }
780:
781: con->plugin_ctx[pd->id] = NULL;
782: }
783:
784: /* The cond_cache gets reset in response.c */
785: /* config_cond_cache_reset(srv, con); */
786:
787: con->header_len = 0;
1.1.1.3 ! misho 788: con->error_handler_saved_status = 0;
! 789: /*con->error_handler_saved_method = HTTP_METHOD_UNSET;*/
! 790: /*(error_handler_saved_method value is not valid unless error_handler_saved_status is set)*/
1.1 misho 791:
792: config_setup_connection(srv, con);
793:
794: return 0;
795: }
796:
797: /**
798: * handle all header and content read
799: *
800: * we get called by the state-engine and by the fdevent-handler
801: */
802: static int connection_handle_read_state(server *srv, connection *con) {
803: chunk *c, *last_chunk;
804: off_t last_offset;
805: chunkqueue *cq = con->read_queue;
806: int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
1.1.1.3 ! misho 807: /* when in CON_STATE_READ: about to receive first byte for a request: */
! 808: int is_request_start = chunkqueue_is_empty(cq);
1.1 misho 809:
810: if (con->is_readable) {
811: con->read_idle_ts = srv->cur_ts;
812:
813: switch(connection_handle_read(srv, con)) {
814: case -1:
815: return -1;
816: case -2:
817: is_closed = 1;
818: break;
819: default:
820: break;
821: }
822: }
823:
1.1.1.3 ! misho 824: chunkqueue_remove_finished_chunks(cq);
1.1 misho 825:
826: /* we might have got several packets at once
827: */
828:
1.1.1.3 ! misho 829: /* update request_start timestamp when first byte of
! 830: * next request is received on a keep-alive connection */
! 831: if (con->request_count > 1 && is_request_start) {
! 832: con->request_start = srv->cur_ts;
! 833: if (con->conf.high_precision_timestamps)
! 834: log_clock_gettime_realtime(&con->request_start_hp);
! 835: }
! 836:
1.1 misho 837: /* if there is a \r\n\r\n in the chunkqueue
838: *
839: * scan the chunk-queue twice
840: * 1. to find the \r\n\r\n
841: * 2. to copy the header-packet
842: *
843: */
844:
845: last_chunk = NULL;
846: last_offset = 0;
847:
848: for (c = cq->first; c; c = c->next) {
849: size_t i;
1.1.1.3 ! misho 850: size_t len = buffer_string_length(c->mem) - c->offset;
! 851: const char *b = c->mem->ptr + c->offset;
1.1 misho 852:
1.1.1.3 ! misho 853: for (i = 0; i < len; ++i) {
! 854: char ch = b[i];
1.1 misho 855:
856: if ('\r' == ch) {
857: /* chec if \n\r\n follows */
858: size_t j = i+1;
859: chunk *cc = c;
860: const char header_end[] = "\r\n\r\n";
861: int header_end_match_pos = 1;
862:
863: for ( ; cc; cc = cc->next, j = 0 ) {
1.1.1.3 ! misho 864: size_t bblen = buffer_string_length(cc->mem) - cc->offset;
! 865: const char *bb = cc->mem->ptr + cc->offset;
1.1 misho 866:
1.1.1.3 ! misho 867: for ( ; j < bblen; j++) {
! 868: ch = bb[j];
1.1 misho 869:
870: if (ch == header_end[header_end_match_pos]) {
871: header_end_match_pos++;
872: if (4 == header_end_match_pos) {
873: last_chunk = cc;
874: last_offset = j+1;
875: goto found_header_end;
876: }
877: } else {
878: goto reset_search;
879: }
880: }
881: }
882: }
883: reset_search: ;
884: }
885: }
886: found_header_end:
887:
888: /* found */
889: if (last_chunk) {
890: buffer_reset(con->request.request);
891:
892: for (c = cq->first; c; c = c->next) {
1.1.1.3 ! misho 893: size_t len = buffer_string_length(c->mem) - c->offset;
1.1 misho 894:
895: if (c == last_chunk) {
1.1.1.3 ! misho 896: len = last_offset;
1.1 misho 897: }
898:
1.1.1.3 ! misho 899: buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, len);
! 900: c->offset += len;
! 901: cq->bytes_out += len;
1.1 misho 902:
1.1.1.3 ! misho 903: if (c == last_chunk) break;
1.1 misho 904: }
905:
906: connection_set_state(srv, con, CON_STATE_REQUEST_END);
907: } else if (chunkqueue_length(cq) > 64 * 1024) {
908: log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
909:
910: con->http_status = 414; /* Request-URI too large */
911: con->keep_alive = 0;
912: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1.1.1.3 ! misho 913: } else if (is_closed) {
! 914: /* the connection got closed and we didn't got enough data to leave CON_STATE_READ;
! 915: * the only way is to leave here */
! 916: connection_set_state(srv, con, CON_STATE_ERROR);
1.1 misho 917: }
918:
919: chunkqueue_remove_finished_chunks(cq);
920:
921: return 0;
922: }
923:
924: static handler_t connection_handle_fdevent(server *srv, void *context, int revents) {
925: connection *con = context;
926:
927: joblist_append(srv, con);
928:
929: if (con->srv_socket->is_ssl) {
930: /* ssl may read and write for both reads and writes */
931: if (revents & (FDEVENT_IN | FDEVENT_OUT)) {
932: con->is_readable = 1;
933: con->is_writable = 1;
934: }
935: } else {
936: if (revents & FDEVENT_IN) {
937: con->is_readable = 1;
938: }
939: if (revents & FDEVENT_OUT) {
940: con->is_writable = 1;
941: /* we don't need the event twice */
942: }
943: }
944:
945:
946: if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
947: /* looks like an error */
948:
949: /* FIXME: revents = 0x19 still means that we should read from the queue */
950: if (revents & FDEVENT_HUP) {
951: if (con->state == CON_STATE_CLOSE) {
952: con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
953: } else {
954: /* sigio reports the wrong event here
955: *
956: * there was no HUP at all
957: */
958: #ifdef USE_LINUX_SIGIO
959: if (srv->ev->in_sigio == 1) {
960: log_error_write(srv, __FILE__, __LINE__, "sd",
961: "connection closed: poll() -> HUP", con->fd);
962: } else {
963: connection_set_state(srv, con, CON_STATE_ERROR);
964: }
965: #else
966: connection_set_state(srv, con, CON_STATE_ERROR);
967: #endif
968:
969: }
970: } else if (revents & FDEVENT_ERR) {
971: /* error, connection reset, whatever... we don't want to spam the logfile */
972: #if 0
973: log_error_write(srv, __FILE__, __LINE__, "sd",
974: "connection closed: poll() -> ERR", con->fd);
975: #endif
976: connection_set_state(srv, con, CON_STATE_ERROR);
977: } else {
978: log_error_write(srv, __FILE__, __LINE__, "sd",
979: "connection closed: poll() -> ???", revents);
980: }
981: }
982:
1.1.1.3 ! misho 983: if (con->state == CON_STATE_READ) {
1.1 misho 984: connection_handle_read_state(srv, con);
985: }
986:
987: if (con->state == CON_STATE_WRITE &&
988: !chunkqueue_is_empty(con->write_queue) &&
989: con->is_writable) {
990:
991: if (-1 == connection_handle_write(srv, con)) {
992: connection_set_state(srv, con, CON_STATE_ERROR);
993:
994: log_error_write(srv, __FILE__, __LINE__, "ds",
995: con->fd,
996: "handle write failed.");
997: }
998: }
999:
1000: if (con->state == CON_STATE_CLOSE) {
1001: /* flush the read buffers */
1002: int len;
1003: char buf[1024];
1004:
1005: len = read(con->fd, buf, sizeof(buf));
1006: if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {
1007: con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
1008: }
1009: }
1010:
1011: return HANDLER_FINISHED;
1012: }
1013:
1014:
1015: connection *connection_accept(server *srv, server_socket *srv_socket) {
1016: /* accept everything */
1017:
1018: /* search an empty place */
1019: int cnt;
1020: sock_addr cnt_addr;
1021: socklen_t cnt_len;
1022: /* accept it and register the fd */
1023:
1024: /**
1025: * check if we can still open a new connections
1026: *
1027: * see #1216
1028: */
1029:
1030: if (srv->conns->used >= srv->max_conns) {
1031: return NULL;
1032: }
1033:
1034: cnt_len = sizeof(cnt_addr);
1035:
1036: if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
1037: switch (errno) {
1038: case EAGAIN:
1039: #if EWOULDBLOCK != EAGAIN
1040: case EWOULDBLOCK:
1041: #endif
1042: case EINTR:
1043: /* we were stopped _before_ we had a connection */
1044: case ECONNABORTED: /* this is a FreeBSD thingy */
1045: /* we were stopped _after_ we had a connection */
1046: break;
1047: case EMFILE:
1048: /* out of fds */
1049: break;
1050: default:
1051: log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
1052: }
1053: return NULL;
1054: } else {
1.1.1.3 ! misho 1055: if (cnt_addr.plain.sa_family != AF_UNIX) {
! 1056: network_accept_tcp_nagle_disable(cnt);
! 1057: }
! 1058: return connection_accepted(srv, srv_socket, &cnt_addr, cnt);
! 1059: }
! 1060: }
! 1061:
! 1062: connection *connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt) {
1.1 misho 1063: connection *con;
1064:
1065: srv->cur_fds++;
1066:
1067: /* ok, we have the connection, register it */
1068: #if 0
1069: log_error_write(srv, __FILE__, __LINE__, "sd",
1070: "appected()", cnt);
1071: #endif
1072: srv->con_opened++;
1073:
1074: con = connections_get_new_connection(srv);
1075:
1076: con->fd = cnt;
1077: con->fde_ndx = -1;
1078: fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
1079:
1080: connection_set_state(srv, con, CON_STATE_REQUEST_START);
1081:
1082: con->connection_start = srv->cur_ts;
1.1.1.3 ! misho 1083: con->dst_addr = *cnt_addr;
1.1 misho 1084: buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
1085: con->srv_socket = srv_socket;
1086:
1087: if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
1088: log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
1089: return NULL;
1090: }
1091: #ifdef USE_OPENSSL
1092: /* connect FD to SSL */
1093: if (srv_socket->is_ssl) {
1094: if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
1095: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
1096: ERR_error_string(ERR_get_error(), NULL));
1097:
1098: return NULL;
1099: }
1100:
1101: con->renegotiations = 0;
1102: SSL_set_app_data(con->ssl, con);
1103: SSL_set_accept_state(con->ssl);
1104:
1105: if (1 != (SSL_set_fd(con->ssl, cnt))) {
1106: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
1107: ERR_error_string(ERR_get_error(), NULL));
1108: return NULL;
1109: }
1110: }
1111: #endif
1112: return con;
1113: }
1114:
1115:
1116: int connection_state_machine(server *srv, connection *con) {
1117: int done = 0, r;
1118:
1119: if (srv->srvconf.log_state_handling) {
1120: log_error_write(srv, __FILE__, __LINE__, "sds",
1121: "state at start",
1122: con->fd,
1123: connection_get_state(con->state));
1124: }
1125:
1126: while (done == 0) {
1127: size_t ostate = con->state;
1128:
1.1.1.3 ! misho 1129: if (srv->srvconf.log_state_handling) {
! 1130: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1131: "state for fd", con->fd, connection_get_state(con->state));
! 1132: }
! 1133:
1.1 misho 1134: switch (con->state) {
1135: case CON_STATE_REQUEST_START: /* transient */
1136: con->request_start = srv->cur_ts;
1137: con->read_idle_ts = srv->cur_ts;
1.1.1.3 ! misho 1138: if (con->conf.high_precision_timestamps)
! 1139: log_clock_gettime_realtime(&con->request_start_hp);
1.1 misho 1140:
1141: con->request_count++;
1142: con->loops_per_request = 0;
1143:
1144: connection_set_state(srv, con, CON_STATE_READ);
1145:
1146: break;
1147: case CON_STATE_REQUEST_END: /* transient */
1148: buffer_reset(con->uri.authority);
1149: buffer_reset(con->uri.path);
1150: buffer_reset(con->uri.query);
1151: buffer_reset(con->request.orig_uri);
1152:
1153: if (http_request_parse(srv, con)) {
1154: /* we have to read some data from the POST request */
1155:
1156: connection_set_state(srv, con, CON_STATE_READ_POST);
1157:
1158: break;
1159: }
1160:
1161: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1162:
1163: break;
1.1.1.3 ! misho 1164: case CON_STATE_READ_POST:
1.1 misho 1165: case CON_STATE_HANDLE_REQUEST:
1166: /*
1167: * the request is parsed
1168: *
1169: * decided what to do with the request
1170: * -
1171: *
1172: *
1173: */
1174:
1175: switch (r = http_response_prepare(srv, con)) {
1.1.1.3 ! misho 1176: case HANDLER_WAIT_FOR_EVENT:
! 1177: if (!con->file_finished && (!con->file_started || 0 == con->conf.stream_response_body)) {
! 1178: break; /* come back here */
! 1179: }
! 1180: /* response headers received from backend; fall through to start response */
1.1 misho 1181: case HANDLER_FINISHED:
1.1.1.3 ! misho 1182: if (con->error_handler_saved_status > 0) {
! 1183: con->request.http_method = con->error_handler_saved_method;
! 1184: }
1.1 misho 1185: if (con->mode == DIRECT) {
1.1.1.3 ! misho 1186: if (con->error_handler_saved_status) {
! 1187: if (con->error_handler_saved_status > 0) {
! 1188: con->http_status = con->error_handler_saved_status;
! 1189: } else if (con->http_status == 404 || con->http_status == 403) {
! 1190: /* error-handler-404 is a 404 */
! 1191: con->http_status = -con->error_handler_saved_status;
! 1192: } else {
! 1193: /* error-handler-404 is back and has generated content */
! 1194: /* if Status: was set, take it otherwise use 200 */
! 1195: }
! 1196: } else if (con->http_status >= 400) {
! 1197: buffer *error_handler = NULL;
! 1198: if (!buffer_string_is_empty(con->conf.error_handler)) {
! 1199: error_handler = con->conf.error_handler;
! 1200: } else if ((con->http_status == 404 || con->http_status == 403)
! 1201: && !buffer_string_is_empty(con->conf.error_handler_404)) {
! 1202: error_handler = con->conf.error_handler_404;
! 1203: }
1.1 misho 1204:
1.1.1.3 ! misho 1205: if (error_handler) {
! 1206: /* call error-handler */
1.1 misho 1207:
1.1.1.3 ! misho 1208: /* set REDIRECT_STATUS to save current HTTP status code
! 1209: * for access by dynamic handlers
! 1210: * https://redmine.lighttpd.net/issues/1828 */
! 1211: data_string *ds;
! 1212: if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
! 1213: ds = data_string_init();
1.1 misho 1214: }
1.1.1.3 ! misho 1215: buffer_copy_string_len(ds->key, CONST_STR_LEN("REDIRECT_STATUS"));
! 1216: buffer_append_int(ds->value, con->http_status);
! 1217: array_insert_unique(con->environment, (data_unset *)ds);
! 1218:
! 1219: if (error_handler == con->conf.error_handler) {
! 1220: plugins_call_connection_reset(srv, con);
! 1221:
! 1222: if (con->request.content_length) {
! 1223: if ((off_t)con->request.content_length != chunkqueue_length(con->request_content_queue)) {
! 1224: con->keep_alive = 0;
! 1225: }
! 1226: con->request.content_length = 0;
! 1227: chunkqueue_reset(con->request_content_queue);
! 1228: }
1.1 misho 1229:
1.1.1.3 ! misho 1230: con->is_writable = 1;
! 1231: con->file_finished = 0;
! 1232: con->file_started = 0;
! 1233: con->got_response = 0;
! 1234: con->parsed_response = 0;
! 1235: con->response.keep_alive = 0;
! 1236: con->response.content_length = -1;
! 1237: con->response.transfer_encoding = 0;
! 1238:
! 1239: con->error_handler_saved_status = con->http_status;
! 1240: con->error_handler_saved_method = con->request.http_method;
! 1241:
! 1242: con->request.http_method = HTTP_METHOD_GET;
! 1243: } else { /*(preserve behavior for server.error-handler-404)*/
! 1244: con->error_handler_saved_status = -con->http_status; /*(negative to flag old behavior)*/
! 1245: }
1.1 misho 1246:
1.1.1.3 ! misho 1247: buffer_copy_buffer(con->request.uri, error_handler);
! 1248: connection_handle_errdoc_init(srv, con);
! 1249: con->http_status = 0; /*(after connection_handle_errdoc_init())*/
1.1 misho 1250:
1251: done = -1;
1252: break;
1253: }
1254: }
1255: }
1256: if (con->http_status == 0) con->http_status = 200;
1257:
1258: /* we have something to send, go on */
1259: connection_set_state(srv, con, CON_STATE_RESPONSE_START);
1260: break;
1261: case HANDLER_WAIT_FOR_FD:
1262: srv->want_fds++;
1263:
1264: fdwaitqueue_append(srv, con);
1265:
1266: break;
1267: case HANDLER_COMEBACK:
1268: done = -1;
1269: break;
1270: case HANDLER_ERROR:
1271: /* something went wrong */
1272: connection_set_state(srv, con, CON_STATE_ERROR);
1273: break;
1274: default:
1275: log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
1276: break;
1277: }
1278:
1279: break;
1280: case CON_STATE_RESPONSE_START:
1281: /*
1282: * the decision is done
1283: * - create the HTTP-Response-Header
1284: *
1285: */
1286:
1287: if (-1 == connection_handle_write_prepare(srv, con)) {
1288: connection_set_state(srv, con, CON_STATE_ERROR);
1289:
1290: break;
1291: }
1292:
1293: connection_set_state(srv, con, CON_STATE_WRITE);
1294: break;
1295: case CON_STATE_RESPONSE_END: /* transient */
1.1.1.3 ! misho 1296: case CON_STATE_ERROR: /* transient */
! 1297: connection_handle_response_end_state(srv, con);
1.1 misho 1298: break;
1299: case CON_STATE_CONNECT:
1300: chunkqueue_reset(con->read_queue);
1301:
1302: con->request_count = 0;
1303:
1304: break;
1305: case CON_STATE_CLOSE:
1.1.1.3 ! misho 1306: connection_handle_close_state(srv, con);
1.1 misho 1307: break;
1308: case CON_STATE_READ:
1309: connection_handle_read_state(srv, con);
1310: break;
1311: case CON_STATE_WRITE:
1.1.1.3 ! misho 1312: do {
! 1313: /* only try to write if we have something in the queue */
! 1314: if (!chunkqueue_is_empty(con->write_queue)) {
! 1315: if (con->is_writable) {
! 1316: if (-1 == connection_handle_write(srv, con)) {
! 1317: log_error_write(srv, __FILE__, __LINE__, "ds",
! 1318: con->fd,
! 1319: "handle write failed.");
! 1320: connection_set_state(srv, con, CON_STATE_ERROR);
! 1321: break;
! 1322: }
! 1323: if (con->state != CON_STATE_WRITE) break;
! 1324: }
! 1325: } else if (con->file_finished) {
! 1326: connection_set_state(srv, con, CON_STATE_RESPONSE_END);
! 1327: break;
1.1 misho 1328: }
1329:
1.1.1.3 ! misho 1330: if (con->mode != DIRECT && !con->file_finished) {
! 1331: switch(r = plugins_call_handle_subrequest(srv, con)) {
! 1332: case HANDLER_WAIT_FOR_EVENT:
! 1333: case HANDLER_FINISHED:
! 1334: case HANDLER_GO_ON:
1.1 misho 1335: break;
1.1.1.3 ! misho 1336: case HANDLER_WAIT_FOR_FD:
! 1337: srv->want_fds++;
! 1338: fdwaitqueue_append(srv, con);
1.1 misho 1339: break;
1.1.1.3 ! misho 1340: case HANDLER_COMEBACK:
1.1 misho 1341: default:
1.1.1.3 ! misho 1342: log_error_write(srv, __FILE__, __LINE__, "sdd", "unexpected subrequest handler ret-value: ", con->fd, r);
! 1343: /* fall through */
! 1344: case HANDLER_ERROR:
! 1345: connection_set_state(srv, con, CON_STATE_ERROR);
1.1 misho 1346: break;
1347: }
1348: }
1.1.1.3 ! misho 1349: } while (con->state == CON_STATE_WRITE && (!chunkqueue_is_empty(con->write_queue) ? con->is_writable : con->file_finished));
1.1 misho 1350:
1351: break;
1352: default:
1353: log_error_write(srv, __FILE__, __LINE__, "sdd",
1354: "unknown state:", con->fd, con->state);
1355:
1356: break;
1357: }
1358:
1359: if (done == -1) {
1360: done = 0;
1361: } else if (ostate == con->state) {
1362: done = 1;
1363: }
1364: }
1365:
1366: if (srv->srvconf.log_state_handling) {
1367: log_error_write(srv, __FILE__, __LINE__, "sds",
1368: "state at exit:",
1369: con->fd,
1370: connection_get_state(con->state));
1371: }
1372:
1.1.1.3 ! misho 1373: r = 0;
1.1 misho 1374: switch(con->state) {
1375: case CON_STATE_READ:
1376: case CON_STATE_CLOSE:
1.1.1.3 ! misho 1377: r = FDEVENT_IN;
1.1 misho 1378: break;
1379: case CON_STATE_WRITE:
1380: /* request write-fdevent only if we really need it
1381: * - if we have data to write
1382: * - if the socket is not writable yet
1383: */
1384: if (!chunkqueue_is_empty(con->write_queue) &&
1385: (con->is_writable == 0) &&
1386: (con->traffic_limit_reached == 0)) {
1.1.1.3 ! misho 1387: r |= FDEVENT_OUT;
! 1388: }
! 1389: /* fall through */
! 1390: case CON_STATE_READ_POST:
! 1391: if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN) {
! 1392: r |= FDEVENT_IN;
1.1 misho 1393: }
1394: break;
1395: default:
1396: break;
1.1.1.3 ! misho 1397: }
! 1398: if (-1 != con->fd) {
! 1399: const int events = fdevent_event_get_interest(srv->ev, con->fd);
! 1400: if (con->is_readable < 0) {
! 1401: con->is_readable = 0;
! 1402: r |= FDEVENT_IN;
! 1403: }
! 1404: if (con->is_writable < 0) {
! 1405: con->is_writable = 0;
! 1406: r |= FDEVENT_OUT;
! 1407: }
! 1408: if (r != events) {
! 1409: /* update timestamps when enabling interest in events */
! 1410: if ((r & FDEVENT_IN) && !(events & FDEVENT_IN)) {
! 1411: con->read_idle_ts = srv->cur_ts;
! 1412: }
! 1413: if ((r & FDEVENT_OUT) && !(events & FDEVENT_OUT)) {
! 1414: con->write_request_ts = srv->cur_ts;
! 1415: }
! 1416: fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, r);
! 1417: }
1.1 misho 1418: }
1419:
1420: return 0;
1421: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>