Annotation of embedaddon/lighttpd/src/connections.c, revision 1.1
1.1 ! misho 1: #include "buffer.h"
! 2: #include "server.h"
! 3: #include "log.h"
! 4: #include "connections.h"
! 5: #include "fdevent.h"
! 6:
! 7: #include "request.h"
! 8: #include "response.h"
! 9: #include "network.h"
! 10: #include "http_chunk.h"
! 11: #include "stat_cache.h"
! 12: #include "joblist.h"
! 13:
! 14: #include "plugin.h"
! 15:
! 16: #include "inet_ntop_cache.h"
! 17:
! 18: #include <sys/stat.h>
! 19:
! 20: #include <stdlib.h>
! 21: #include <stdio.h>
! 22: #include <unistd.h>
! 23: #include <errno.h>
! 24: #include <string.h>
! 25: #include <fcntl.h>
! 26: #include <assert.h>
! 27:
! 28: #ifdef USE_OPENSSL
! 29: # include <openssl/ssl.h>
! 30: # include <openssl/err.h>
! 31: #endif
! 32:
! 33: #ifdef HAVE_SYS_FILIO_H
! 34: # include <sys/filio.h>
! 35: #endif
! 36:
! 37: #include "sys-socket.h"
! 38:
! 39: typedef struct {
! 40: PLUGIN_DATA;
! 41: } plugin_data;
! 42:
! 43: static connection *connections_get_new_connection(server *srv) {
! 44: connections *conns = srv->conns;
! 45: size_t i;
! 46:
! 47: if (conns->size == 0) {
! 48: conns->size = 128;
! 49: conns->ptr = NULL;
! 50: conns->ptr = malloc(sizeof(*conns->ptr) * conns->size);
! 51: for (i = 0; i < conns->size; i++) {
! 52: conns->ptr[i] = connection_init(srv);
! 53: }
! 54: } else if (conns->size == conns->used) {
! 55: conns->size += 128;
! 56: conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
! 57:
! 58: for (i = conns->used; i < conns->size; i++) {
! 59: conns->ptr[i] = connection_init(srv);
! 60: }
! 61: }
! 62:
! 63: connection_reset(srv, conns->ptr[conns->used]);
! 64: #if 0
! 65: fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
! 66: for (i = 0; i < conns->used + 1; i++) {
! 67: fprintf(stderr, "%d ", conns->ptr[i]->fd);
! 68: }
! 69: fprintf(stderr, "\n");
! 70: #endif
! 71:
! 72: conns->ptr[conns->used]->ndx = conns->used;
! 73: return conns->ptr[conns->used++];
! 74: }
! 75:
! 76: static int connection_del(server *srv, connection *con) {
! 77: size_t i;
! 78: connections *conns = srv->conns;
! 79: connection *temp;
! 80:
! 81: if (con == NULL) return -1;
! 82:
! 83: if (-1 == con->ndx) return -1;
! 84:
! 85: buffer_reset(con->uri.authority);
! 86: buffer_reset(con->uri.path);
! 87: buffer_reset(con->uri.query);
! 88: buffer_reset(con->request.orig_uri);
! 89:
! 90: i = con->ndx;
! 91:
! 92: /* not last element */
! 93:
! 94: if (i != conns->used - 1) {
! 95: temp = conns->ptr[i];
! 96: conns->ptr[i] = conns->ptr[conns->used - 1];
! 97: conns->ptr[conns->used - 1] = temp;
! 98:
! 99: conns->ptr[i]->ndx = i;
! 100: conns->ptr[conns->used - 1]->ndx = -1;
! 101: }
! 102:
! 103: conns->used--;
! 104:
! 105: con->ndx = -1;
! 106: #if 0
! 107: fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
! 108: for (i = 0; i < conns->used; i++) {
! 109: fprintf(stderr, "%d ", conns->ptr[i]->fd);
! 110: }
! 111: fprintf(stderr, "\n");
! 112: #endif
! 113: return 0;
! 114: }
! 115:
! 116: int connection_close(server *srv, connection *con) {
! 117: #ifdef USE_OPENSSL
! 118: server_socket *srv_sock = con->srv_socket;
! 119: #endif
! 120:
! 121: #ifdef USE_OPENSSL
! 122: if (srv_sock->is_ssl) {
! 123: if (con->ssl) SSL_free(con->ssl);
! 124: con->ssl = NULL;
! 125: }
! 126: #endif
! 127:
! 128: fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
! 129: fdevent_unregister(srv->ev, con->fd);
! 130: #ifdef __WIN32
! 131: if (closesocket(con->fd)) {
! 132: log_error_write(srv, __FILE__, __LINE__, "sds",
! 133: "(warning) close:", con->fd, strerror(errno));
! 134: }
! 135: #else
! 136: if (close(con->fd)) {
! 137: log_error_write(srv, __FILE__, __LINE__, "sds",
! 138: "(warning) close:", con->fd, strerror(errno));
! 139: }
! 140: #endif
! 141:
! 142: srv->cur_fds--;
! 143: #if 0
! 144: log_error_write(srv, __FILE__, __LINE__, "sd",
! 145: "closed()", con->fd);
! 146: #endif
! 147:
! 148: connection_del(srv, con);
! 149: connection_set_state(srv, con, CON_STATE_CONNECT);
! 150:
! 151: return 0;
! 152: }
! 153:
! 154: #if 0
! 155: static void dump_packet(const unsigned char *data, size_t len) {
! 156: size_t i, j;
! 157:
! 158: if (len == 0) return;
! 159:
! 160: for (i = 0; i < len; i++) {
! 161: if (i % 16 == 0) fprintf(stderr, " ");
! 162:
! 163: fprintf(stderr, "%02x ", data[i]);
! 164:
! 165: if ((i + 1) % 16 == 0) {
! 166: fprintf(stderr, " ");
! 167: for (j = 0; j <= i % 16; j++) {
! 168: unsigned char c;
! 169:
! 170: if (i-15+j >= len) break;
! 171:
! 172: c = data[i-15+j];
! 173:
! 174: fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
! 175: }
! 176:
! 177: fprintf(stderr, "\n");
! 178: }
! 179: }
! 180:
! 181: if (len % 16 != 0) {
! 182: for (j = i % 16; j < 16; j++) {
! 183: fprintf(stderr, " ");
! 184: }
! 185:
! 186: fprintf(stderr, " ");
! 187: for (j = i & ~0xf; j < len; j++) {
! 188: unsigned char c;
! 189:
! 190: c = data[j];
! 191: fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
! 192: }
! 193: fprintf(stderr, "\n");
! 194: }
! 195: }
! 196: #endif
! 197:
! 198: static int connection_handle_read_ssl(server *srv, connection *con) {
! 199: #ifdef USE_OPENSSL
! 200: int r, ssl_err, len, count = 0, read_offset, toread;
! 201: buffer *b = NULL;
! 202:
! 203: if (!con->srv_socket->is_ssl) return -1;
! 204:
! 205: ERR_clear_error();
! 206: do {
! 207: if (NULL != con->read_queue->last) {
! 208: b = con->read_queue->last->mem;
! 209: }
! 210:
! 211: if (NULL == b || b->size - b->used < 1024) {
! 212: b = chunkqueue_get_append_buffer(con->read_queue);
! 213: len = SSL_pending(con->ssl);
! 214: if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */
! 215: buffer_prepare_copy(b, len + 1);
! 216:
! 217: /* overwrite everything with 0 */
! 218: memset(b->ptr, 0, b->size);
! 219: }
! 220:
! 221: read_offset = (b->used > 0) ? b->used - 1 : 0;
! 222: toread = b->size - 1 - read_offset;
! 223:
! 224: len = SSL_read(con->ssl, b->ptr + read_offset, toread);
! 225:
! 226: if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
! 227: log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
! 228: connection_set_state(srv, con, CON_STATE_ERROR);
! 229: return -1;
! 230: }
! 231:
! 232: if (len > 0) {
! 233: if (b->used > 0) b->used--;
! 234: b->used += len;
! 235: b->ptr[b->used++] = '\0';
! 236:
! 237: con->bytes_read += len;
! 238:
! 239: count += len;
! 240: }
! 241: } while (len == toread && count < MAX_READ_LIMIT);
! 242:
! 243:
! 244: if (len < 0) {
! 245: int oerrno = errno;
! 246: switch ((r = SSL_get_error(con->ssl, len))) {
! 247: case SSL_ERROR_WANT_READ:
! 248: case SSL_ERROR_WANT_WRITE:
! 249: con->is_readable = 0;
! 250:
! 251: /* the manual says we have to call SSL_read with the same arguments next time.
! 252: * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
! 253: */
! 254:
! 255: return 0;
! 256: case SSL_ERROR_SYSCALL:
! 257: /**
! 258: * man SSL_get_error()
! 259: *
! 260: * SSL_ERROR_SYSCALL
! 261: * Some I/O error occurred. The OpenSSL error queue may contain more
! 262: * information on the error. If the error queue is empty (i.e.
! 263: * ERR_get_error() returns 0), ret can be used to find out more about
! 264: * the error: If ret == 0, an EOF was observed that violates the
! 265: * protocol. If ret == -1, the underlying BIO reported an I/O error
! 266: * (for socket I/O on Unix systems, consult errno for details).
! 267: *
! 268: */
! 269: while((ssl_err = ERR_get_error())) {
! 270: /* get all errors from the error-queue */
! 271: log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
! 272: r, ERR_error_string(ssl_err, NULL));
! 273: }
! 274:
! 275: switch(oerrno) {
! 276: default:
! 277: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
! 278: len, r, oerrno,
! 279: strerror(oerrno));
! 280: break;
! 281: }
! 282:
! 283: break;
! 284: case SSL_ERROR_ZERO_RETURN:
! 285: /* clean shutdown on the remote side */
! 286:
! 287: if (r == 0) {
! 288: /* FIXME: later */
! 289: }
! 290:
! 291: /* fall thourgh */
! 292: default:
! 293: while((ssl_err = ERR_get_error())) {
! 294: switch (ERR_GET_REASON(ssl_err)) {
! 295: case SSL_R_SSL_HANDSHAKE_FAILURE:
! 296: case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
! 297: case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
! 298: case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
! 299: if (!con->conf.log_ssl_noise) continue;
! 300: break;
! 301: default:
! 302: break;
! 303: }
! 304: /* get all errors from the error-queue */
! 305: log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
! 306: r, ERR_error_string(ssl_err, NULL));
! 307: }
! 308: break;
! 309: }
! 310:
! 311: connection_set_state(srv, con, CON_STATE_ERROR);
! 312:
! 313: return -1;
! 314: } else if (len == 0) {
! 315: con->is_readable = 0;
! 316: /* the other end close the connection -> KEEP-ALIVE */
! 317:
! 318: return -2;
! 319: } else {
! 320: joblist_append(srv, con);
! 321: }
! 322:
! 323: return 0;
! 324: #else
! 325: UNUSED(srv);
! 326: UNUSED(con);
! 327: return -1;
! 328: #endif
! 329: }
! 330:
! 331: /* 0: everything ok, -1: error, -2: con closed */
! 332: static int connection_handle_read(server *srv, connection *con) {
! 333: int len;
! 334: buffer *b;
! 335: int toread, read_offset;
! 336:
! 337: if (con->srv_socket->is_ssl) {
! 338: return connection_handle_read_ssl(srv, con);
! 339: }
! 340:
! 341: b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL;
! 342:
! 343: /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
! 344: * us more than 4kb is available
! 345: * if FIONREAD doesn't signal a big chunk we fill the previous buffer
! 346: * if it has >= 1kb free
! 347: */
! 348: #if defined(__WIN32)
! 349: if (NULL == b || b->size - b->used < 1024) {
! 350: b = chunkqueue_get_append_buffer(con->read_queue);
! 351: buffer_prepare_copy(b, 4 * 1024);
! 352: }
! 353:
! 354: read_offset = (b->used == 0) ? 0 : b->used - 1;
! 355: len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0);
! 356: #else
! 357: if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
! 358: if (NULL == b || b->size - b->used < 1024) {
! 359: b = chunkqueue_get_append_buffer(con->read_queue);
! 360: buffer_prepare_copy(b, 4 * 1024);
! 361: }
! 362: } else {
! 363: if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
! 364: b = chunkqueue_get_append_buffer(con->read_queue);
! 365: buffer_prepare_copy(b, toread + 1);
! 366: }
! 367:
! 368: read_offset = (b->used == 0) ? 0 : b->used - 1;
! 369: len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset);
! 370: #endif
! 371:
! 372: if (len < 0) {
! 373: con->is_readable = 0;
! 374:
! 375: if (errno == EAGAIN) return 0;
! 376: if (errno == EINTR) {
! 377: /* we have been interrupted before we could read */
! 378: con->is_readable = 1;
! 379: return 0;
! 380: }
! 381:
! 382: if (errno != ECONNRESET) {
! 383: /* expected for keep-alive */
! 384: log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
! 385: }
! 386:
! 387: connection_set_state(srv, con, CON_STATE_ERROR);
! 388:
! 389: return -1;
! 390: } else if (len == 0) {
! 391: con->is_readable = 0;
! 392: /* the other end close the connection -> KEEP-ALIVE */
! 393:
! 394: /* pipelining */
! 395:
! 396: return -2;
! 397: } else if ((size_t)len < b->size - 1) {
! 398: /* we got less then expected, wait for the next fd-event */
! 399:
! 400: con->is_readable = 0;
! 401: }
! 402:
! 403: if (b->used > 0) b->used--;
! 404: b->used += len;
! 405: b->ptr[b->used++] = '\0';
! 406:
! 407: con->bytes_read += len;
! 408: #if 0
! 409: dump_packet(b->ptr, len);
! 410: #endif
! 411:
! 412: return 0;
! 413: }
! 414:
! 415: static int connection_handle_write_prepare(server *srv, connection *con) {
! 416: if (con->mode == DIRECT) {
! 417: /* static files */
! 418: switch(con->request.http_method) {
! 419: case HTTP_METHOD_GET:
! 420: case HTTP_METHOD_POST:
! 421: case HTTP_METHOD_HEAD:
! 422: break;
! 423: case HTTP_METHOD_OPTIONS:
! 424: /*
! 425: * 400 is coming from the request-parser BEFORE uri.path is set
! 426: * 403 is from the response handler when noone else catched it
! 427: *
! 428: * */
! 429: if ((!con->http_status || con->http_status == 200) && con->uri.path->used &&
! 430: con->uri.path->ptr[0] != '*') {
! 431: response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
! 432:
! 433: con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
! 434: con->parsed_response &= ~HTTP_CONTENT_LENGTH;
! 435:
! 436: con->http_status = 200;
! 437: con->file_finished = 1;
! 438:
! 439: chunkqueue_reset(con->write_queue);
! 440: }
! 441: break;
! 442: default:
! 443: if (0 == con->http_status) {
! 444: con->http_status = 501;
! 445: }
! 446: break;
! 447: }
! 448: }
! 449:
! 450: if (con->http_status == 0) {
! 451: con->http_status = 403;
! 452: }
! 453:
! 454: switch(con->http_status) {
! 455: case 204: /* class: header only */
! 456: case 205:
! 457: case 304:
! 458: /* disable chunked encoding again as we have no body */
! 459: con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
! 460: con->parsed_response &= ~HTTP_CONTENT_LENGTH;
! 461: chunkqueue_reset(con->write_queue);
! 462:
! 463: con->file_finished = 1;
! 464: break;
! 465: default: /* class: header + body */
! 466: if (con->mode != DIRECT) break;
! 467:
! 468: /* only custom body for 4xx and 5xx */
! 469: if (con->http_status < 400 || con->http_status >= 600) break;
! 470:
! 471: con->file_finished = 0;
! 472:
! 473: buffer_reset(con->physical.path);
! 474:
! 475: /* try to send static errorfile */
! 476: if (!buffer_is_empty(con->conf.errorfile_prefix)) {
! 477: stat_cache_entry *sce = NULL;
! 478:
! 479: buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
! 480: buffer_append_long(con->physical.path, con->http_status);
! 481: buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
! 482:
! 483: if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
! 484: con->file_finished = 1;
! 485:
! 486: http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
! 487: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
! 488: }
! 489: }
! 490:
! 491: if (!con->file_finished) {
! 492: buffer *b;
! 493:
! 494: buffer_reset(con->physical.path);
! 495:
! 496: con->file_finished = 1;
! 497: b = chunkqueue_get_append_buffer(con->write_queue);
! 498:
! 499: /* build default error-page */
! 500: buffer_copy_string_len(b, CONST_STR_LEN(
! 501: "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
! 502: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
! 503: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
! 504: "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
! 505: " <head>\n"
! 506: " <title>"));
! 507: buffer_append_long(b, con->http_status);
! 508: buffer_append_string_len(b, CONST_STR_LEN(" - "));
! 509: buffer_append_string(b, get_http_status_name(con->http_status));
! 510:
! 511: buffer_append_string_len(b, CONST_STR_LEN(
! 512: "</title>\n"
! 513: " </head>\n"
! 514: " <body>\n"
! 515: " <h1>"));
! 516: buffer_append_long(b, con->http_status);
! 517: buffer_append_string_len(b, CONST_STR_LEN(" - "));
! 518: buffer_append_string(b, get_http_status_name(con->http_status));
! 519:
! 520: buffer_append_string_len(b, CONST_STR_LEN("</h1>\n"
! 521: " </body>\n"
! 522: "</html>\n"
! 523: ));
! 524:
! 525: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
! 526: }
! 527: break;
! 528: }
! 529:
! 530: if (con->file_finished) {
! 531: /* we have all the content and chunked encoding is not used, set a content-length */
! 532:
! 533: if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
! 534: (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
! 535: off_t qlen = chunkqueue_length(con->write_queue);
! 536:
! 537: /**
! 538: * The Content-Length header only can be sent if we have content:
! 539: * - HEAD doesn't have a content-body (but have a content-length)
! 540: * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
! 541: *
! 542: * Otherwise generate a Content-Length header as chunked encoding is not
! 543: * available
! 544: */
! 545: if ((con->http_status >= 100 && con->http_status < 200) ||
! 546: con->http_status == 204 ||
! 547: con->http_status == 304) {
! 548: data_string *ds;
! 549: /* no Content-Body, no Content-Length */
! 550: if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) {
! 551: buffer_reset(ds->value); /* Headers with empty values are ignored for output */
! 552: }
! 553: } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) {
! 554: /* qlen = 0 is important for Redirects (301, ...) as they MAY have
! 555: * a content. Browsers are waiting for a Content otherwise
! 556: */
! 557: buffer_copy_off_t(srv->tmp_buf, qlen);
! 558:
! 559: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
! 560: }
! 561: }
! 562: } else {
! 563: /**
! 564: * the file isn't finished yet, but we have all headers
! 565: *
! 566: * to get keep-alive we either need:
! 567: * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
! 568: * - Transfer-Encoding: chunked (HTTP/1.1)
! 569: */
! 570:
! 571: if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) &&
! 572: ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
! 573: con->keep_alive = 0;
! 574: }
! 575:
! 576: /**
! 577: * if the backend sent a Connection: close, follow the wish
! 578: *
! 579: * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
! 580: * will close the connection. That's fine. We can always decide the close
! 581: * the connection
! 582: *
! 583: * FIXME: to be nice we should remove the Connection: ...
! 584: */
! 585: if (con->parsed_response & HTTP_CONNECTION) {
! 586: /* a subrequest disable keep-alive although the client wanted it */
! 587: if (con->keep_alive && !con->response.keep_alive) {
! 588: con->keep_alive = 0;
! 589: }
! 590: }
! 591: }
! 592:
! 593: if (con->request.http_method == HTTP_METHOD_HEAD) {
! 594: /**
! 595: * a HEAD request has the same as a GET
! 596: * without the content
! 597: */
! 598: con->file_finished = 1;
! 599:
! 600: chunkqueue_reset(con->write_queue);
! 601: con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
! 602: }
! 603:
! 604: http_response_write_header(srv, con);
! 605:
! 606: return 0;
! 607: }
! 608:
! 609: static int connection_handle_write(server *srv, connection *con) {
! 610: switch(network_write_chunkqueue(srv, con, con->write_queue, MAX_WRITE_LIMIT)) {
! 611: case 0:
! 612: con->write_request_ts = srv->cur_ts;
! 613: if (con->file_finished) {
! 614: connection_set_state(srv, con, CON_STATE_RESPONSE_END);
! 615: joblist_append(srv, con);
! 616: }
! 617: break;
! 618: case -1: /* error on our side */
! 619: log_error_write(srv, __FILE__, __LINE__, "sd",
! 620: "connection closed: write failed on fd", con->fd);
! 621: connection_set_state(srv, con, CON_STATE_ERROR);
! 622: joblist_append(srv, con);
! 623: break;
! 624: case -2: /* remote close */
! 625: connection_set_state(srv, con, CON_STATE_ERROR);
! 626: joblist_append(srv, con);
! 627: break;
! 628: case 1:
! 629: con->write_request_ts = srv->cur_ts;
! 630: con->is_writable = 0;
! 631:
! 632: /* not finished yet -> WRITE */
! 633: break;
! 634: }
! 635:
! 636: return 0;
! 637: }
! 638:
! 639:
! 640:
! 641: connection *connection_init(server *srv) {
! 642: connection *con;
! 643:
! 644: UNUSED(srv);
! 645:
! 646: con = calloc(1, sizeof(*con));
! 647:
! 648: con->fd = 0;
! 649: con->ndx = -1;
! 650: con->fde_ndx = -1;
! 651: con->bytes_written = 0;
! 652: con->bytes_read = 0;
! 653: con->bytes_header = 0;
! 654: con->loops_per_request = 0;
! 655:
! 656: #define CLEAN(x) \
! 657: con->x = buffer_init();
! 658:
! 659: CLEAN(request.uri);
! 660: CLEAN(request.request_line);
! 661: CLEAN(request.request);
! 662: CLEAN(request.pathinfo);
! 663:
! 664: CLEAN(request.orig_uri);
! 665:
! 666: CLEAN(uri.scheme);
! 667: CLEAN(uri.authority);
! 668: CLEAN(uri.path);
! 669: CLEAN(uri.path_raw);
! 670: CLEAN(uri.query);
! 671:
! 672: CLEAN(physical.doc_root);
! 673: CLEAN(physical.path);
! 674: CLEAN(physical.basedir);
! 675: CLEAN(physical.rel_path);
! 676: CLEAN(physical.etag);
! 677: CLEAN(parse_request);
! 678:
! 679: CLEAN(server_name);
! 680: CLEAN(error_handler);
! 681: CLEAN(dst_addr_buf);
! 682: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
! 683: CLEAN(tlsext_server_name);
! 684: #endif
! 685:
! 686: #undef CLEAN
! 687: con->write_queue = chunkqueue_init();
! 688: con->read_queue = chunkqueue_init();
! 689: con->request_content_queue = chunkqueue_init();
! 690: chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs);
! 691:
! 692: con->request.headers = array_init();
! 693: con->response.headers = array_init();
! 694: con->environment = array_init();
! 695:
! 696: /* init plugin specific connection structures */
! 697:
! 698: con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
! 699:
! 700: con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
! 701: config_setup_connection(srv, con);
! 702:
! 703: return con;
! 704: }
! 705:
! 706: void connections_free(server *srv) {
! 707: connections *conns = srv->conns;
! 708: size_t i;
! 709:
! 710: for (i = 0; i < conns->size; i++) {
! 711: connection *con = conns->ptr[i];
! 712:
! 713: connection_reset(srv, con);
! 714:
! 715: chunkqueue_free(con->write_queue);
! 716: chunkqueue_free(con->read_queue);
! 717: chunkqueue_free(con->request_content_queue);
! 718: array_free(con->request.headers);
! 719: array_free(con->response.headers);
! 720: array_free(con->environment);
! 721:
! 722: #define CLEAN(x) \
! 723: buffer_free(con->x);
! 724:
! 725: CLEAN(request.uri);
! 726: CLEAN(request.request_line);
! 727: CLEAN(request.request);
! 728: CLEAN(request.pathinfo);
! 729:
! 730: CLEAN(request.orig_uri);
! 731:
! 732: CLEAN(uri.scheme);
! 733: CLEAN(uri.authority);
! 734: CLEAN(uri.path);
! 735: CLEAN(uri.path_raw);
! 736: CLEAN(uri.query);
! 737:
! 738: CLEAN(physical.doc_root);
! 739: CLEAN(physical.path);
! 740: CLEAN(physical.basedir);
! 741: CLEAN(physical.etag);
! 742: CLEAN(physical.rel_path);
! 743: CLEAN(parse_request);
! 744:
! 745: CLEAN(server_name);
! 746: CLEAN(error_handler);
! 747: CLEAN(dst_addr_buf);
! 748: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
! 749: CLEAN(tlsext_server_name);
! 750: #endif
! 751: #undef CLEAN
! 752: free(con->plugin_ctx);
! 753: free(con->cond_cache);
! 754:
! 755: free(con);
! 756: }
! 757:
! 758: free(conns->ptr);
! 759: }
! 760:
! 761:
! 762: int connection_reset(server *srv, connection *con) {
! 763: size_t i;
! 764:
! 765: plugins_call_connection_reset(srv, con);
! 766:
! 767: con->is_readable = 1;
! 768: con->is_writable = 1;
! 769: con->http_status = 0;
! 770: con->file_finished = 0;
! 771: con->file_started = 0;
! 772: con->got_response = 0;
! 773:
! 774: con->parsed_response = 0;
! 775:
! 776: con->bytes_written = 0;
! 777: con->bytes_written_cur_second = 0;
! 778: con->bytes_read = 0;
! 779: con->bytes_header = 0;
! 780: con->loops_per_request = 0;
! 781:
! 782: con->request.http_method = HTTP_METHOD_UNSET;
! 783: con->request.http_version = HTTP_VERSION_UNSET;
! 784:
! 785: con->request.http_if_modified_since = NULL;
! 786: con->request.http_if_none_match = NULL;
! 787:
! 788: con->response.keep_alive = 0;
! 789: con->response.content_length = -1;
! 790: con->response.transfer_encoding = 0;
! 791:
! 792: con->mode = DIRECT;
! 793:
! 794: #define CLEAN(x) \
! 795: if (con->x) buffer_reset(con->x);
! 796:
! 797: CLEAN(request.uri);
! 798: CLEAN(request.request_line);
! 799: CLEAN(request.pathinfo);
! 800: CLEAN(request.request);
! 801:
! 802: /* CLEAN(request.orig_uri); */
! 803:
! 804: CLEAN(uri.scheme);
! 805: /* CLEAN(uri.authority); */
! 806: /* CLEAN(uri.path); */
! 807: CLEAN(uri.path_raw);
! 808: /* CLEAN(uri.query); */
! 809:
! 810: CLEAN(physical.doc_root);
! 811: CLEAN(physical.path);
! 812: CLEAN(physical.basedir);
! 813: CLEAN(physical.rel_path);
! 814: CLEAN(physical.etag);
! 815:
! 816: CLEAN(parse_request);
! 817:
! 818: CLEAN(server_name);
! 819: CLEAN(error_handler);
! 820: #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
! 821: CLEAN(tlsext_server_name);
! 822: #endif
! 823: #undef CLEAN
! 824:
! 825: #define CLEAN(x) \
! 826: if (con->x) con->x->used = 0;
! 827:
! 828: #undef CLEAN
! 829:
! 830: #define CLEAN(x) \
! 831: con->request.x = NULL;
! 832:
! 833: CLEAN(http_host);
! 834: CLEAN(http_range);
! 835: CLEAN(http_content_type);
! 836: #undef CLEAN
! 837: con->request.content_length = 0;
! 838:
! 839: array_reset(con->request.headers);
! 840: array_reset(con->response.headers);
! 841: array_reset(con->environment);
! 842:
! 843: chunkqueue_reset(con->write_queue);
! 844: chunkqueue_reset(con->request_content_queue);
! 845:
! 846: /* the plugins should cleanup themself */
! 847: for (i = 0; i < srv->plugins.used; i++) {
! 848: plugin *p = ((plugin **)(srv->plugins.ptr))[i];
! 849: plugin_data *pd = p->data;
! 850:
! 851: if (!pd) continue;
! 852:
! 853: if (con->plugin_ctx[pd->id] != NULL) {
! 854: log_error_write(srv, __FILE__, __LINE__, "sb", "missing cleanup in", p->name);
! 855: }
! 856:
! 857: con->plugin_ctx[pd->id] = NULL;
! 858: }
! 859:
! 860: /* The cond_cache gets reset in response.c */
! 861: /* config_cond_cache_reset(srv, con); */
! 862:
! 863: con->header_len = 0;
! 864: con->in_error_handler = 0;
! 865:
! 866: config_setup_connection(srv, con);
! 867:
! 868: return 0;
! 869: }
! 870:
! 871: /**
! 872: * handle all header and content read
! 873: *
! 874: * we get called by the state-engine and by the fdevent-handler
! 875: */
! 876: static int connection_handle_read_state(server *srv, connection *con) {
! 877: connection_state_t ostate = con->state;
! 878: chunk *c, *last_chunk;
! 879: off_t last_offset;
! 880: chunkqueue *cq = con->read_queue;
! 881: chunkqueue *dst_cq = con->request_content_queue;
! 882: int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
! 883:
! 884: if (con->is_readable) {
! 885: con->read_idle_ts = srv->cur_ts;
! 886:
! 887: switch(connection_handle_read(srv, con)) {
! 888: case -1:
! 889: return -1;
! 890: case -2:
! 891: is_closed = 1;
! 892: break;
! 893: default:
! 894: break;
! 895: }
! 896: }
! 897:
! 898: /* the last chunk might be empty */
! 899: for (c = cq->first; c;) {
! 900: if (cq->first == c && c->mem->used == 0) {
! 901: /* the first node is empty */
! 902: /* ... and it is empty, move it to unused */
! 903:
! 904: cq->first = c->next;
! 905: if (cq->first == NULL) cq->last = NULL;
! 906:
! 907: c->next = cq->unused;
! 908: cq->unused = c;
! 909: cq->unused_chunks++;
! 910:
! 911: c = cq->first;
! 912: } else if (c->next && c->next->mem->used == 0) {
! 913: chunk *fc;
! 914: /* next node is the last one */
! 915: /* ... and it is empty, move it to unused */
! 916:
! 917: fc = c->next;
! 918: c->next = fc->next;
! 919:
! 920: fc->next = cq->unused;
! 921: cq->unused = fc;
! 922: cq->unused_chunks++;
! 923:
! 924: /* the last node was empty */
! 925: if (c->next == NULL) {
! 926: cq->last = c;
! 927: }
! 928:
! 929: c = c->next;
! 930: } else {
! 931: c = c->next;
! 932: }
! 933: }
! 934:
! 935: /* we might have got several packets at once
! 936: */
! 937:
! 938: switch(ostate) {
! 939: case CON_STATE_READ:
! 940: /* if there is a \r\n\r\n in the chunkqueue
! 941: *
! 942: * scan the chunk-queue twice
! 943: * 1. to find the \r\n\r\n
! 944: * 2. to copy the header-packet
! 945: *
! 946: */
! 947:
! 948: last_chunk = NULL;
! 949: last_offset = 0;
! 950:
! 951: for (c = cq->first; c; c = c->next) {
! 952: buffer b;
! 953: size_t i;
! 954:
! 955: b.ptr = c->mem->ptr + c->offset;
! 956: b.used = c->mem->used - c->offset;
! 957: if (b.used > 0) b.used--; /* buffer "used" includes terminating zero */
! 958:
! 959: for (i = 0; i < b.used; i++) {
! 960: char ch = b.ptr[i];
! 961:
! 962: if ('\r' == ch) {
! 963: /* chec if \n\r\n follows */
! 964: size_t j = i+1;
! 965: chunk *cc = c;
! 966: const char header_end[] = "\r\n\r\n";
! 967: int header_end_match_pos = 1;
! 968:
! 969: for ( ; cc; cc = cc->next, j = 0 ) {
! 970: buffer bb;
! 971: bb.ptr = cc->mem->ptr + cc->offset;
! 972: bb.used = cc->mem->used - cc->offset;
! 973: if (bb.used > 0) bb.used--; /* buffer "used" includes terminating zero */
! 974:
! 975: for ( ; j < bb.used; j++) {
! 976: ch = bb.ptr[j];
! 977:
! 978: if (ch == header_end[header_end_match_pos]) {
! 979: header_end_match_pos++;
! 980: if (4 == header_end_match_pos) {
! 981: last_chunk = cc;
! 982: last_offset = j+1;
! 983: goto found_header_end;
! 984: }
! 985: } else {
! 986: goto reset_search;
! 987: }
! 988: }
! 989: }
! 990: }
! 991: reset_search: ;
! 992: }
! 993: }
! 994: found_header_end:
! 995:
! 996: /* found */
! 997: if (last_chunk) {
! 998: buffer_reset(con->request.request);
! 999:
! 1000: for (c = cq->first; c; c = c->next) {
! 1001: buffer b;
! 1002:
! 1003: b.ptr = c->mem->ptr + c->offset;
! 1004: b.used = c->mem->used - c->offset;
! 1005:
! 1006: if (c == last_chunk) {
! 1007: b.used = last_offset + 1;
! 1008: }
! 1009:
! 1010: buffer_append_string_buffer(con->request.request, &b);
! 1011:
! 1012: if (c == last_chunk) {
! 1013: c->offset += last_offset;
! 1014:
! 1015: break;
! 1016: } else {
! 1017: /* the whole packet was copied */
! 1018: c->offset = c->mem->used - 1;
! 1019: }
! 1020: }
! 1021:
! 1022: connection_set_state(srv, con, CON_STATE_REQUEST_END);
! 1023: } else if (chunkqueue_length(cq) > 64 * 1024) {
! 1024: log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
! 1025:
! 1026: con->http_status = 414; /* Request-URI too large */
! 1027: con->keep_alive = 0;
! 1028: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1029: }
! 1030: break;
! 1031: case CON_STATE_READ_POST:
! 1032: for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
! 1033: off_t weWant, weHave, toRead;
! 1034:
! 1035: weWant = con->request.content_length - dst_cq->bytes_in;
! 1036:
! 1037: assert(c->mem->used);
! 1038:
! 1039: weHave = c->mem->used - c->offset - 1;
! 1040:
! 1041: toRead = weHave > weWant ? weWant : weHave;
! 1042:
! 1043: /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
! 1044: if (con->request.content_length > 64 * 1024) {
! 1045: chunk *dst_c = NULL;
! 1046: /* copy everything to max 1Mb sized tempfiles */
! 1047:
! 1048: /*
! 1049: * if the last chunk is
! 1050: * - smaller than 1Mb (size < 1Mb)
! 1051: * - not read yet (offset == 0)
! 1052: * -> append to it
! 1053: * otherwise
! 1054: * -> create a new chunk
! 1055: *
! 1056: * */
! 1057:
! 1058: if (dst_cq->last &&
! 1059: dst_cq->last->type == FILE_CHUNK &&
! 1060: dst_cq->last->file.is_temp &&
! 1061: dst_cq->last->offset == 0) {
! 1062: /* ok, take the last chunk for our job */
! 1063:
! 1064: if (dst_cq->last->file.length < 1 * 1024 * 1024) {
! 1065: dst_c = dst_cq->last;
! 1066:
! 1067: if (dst_c->file.fd == -1) {
! 1068: /* this should not happen as we cache the fd, but you never know */
! 1069: dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
! 1070: #ifdef FD_CLOEXEC
! 1071: fcntl(dst_c->file.fd, F_SETFD, FD_CLOEXEC);
! 1072: #endif
! 1073: }
! 1074: } else {
! 1075: /* the chunk is too large now, close it */
! 1076: dst_c = dst_cq->last;
! 1077:
! 1078: if (dst_c->file.fd != -1) {
! 1079: close(dst_c->file.fd);
! 1080: dst_c->file.fd = -1;
! 1081: }
! 1082: dst_c = chunkqueue_get_append_tempfile(dst_cq);
! 1083: }
! 1084: } else {
! 1085: dst_c = chunkqueue_get_append_tempfile(dst_cq);
! 1086: }
! 1087:
! 1088: /* we have a chunk, let's write to it */
! 1089:
! 1090: if (dst_c->file.fd == -1) {
! 1091: /* we don't have file to write to,
! 1092: * EACCES might be one reason.
! 1093: *
! 1094: * Instead of sending 500 we send 413 and say the request is too large
! 1095: * */
! 1096:
! 1097: log_error_write(srv, __FILE__, __LINE__, "sbs",
! 1098: "denying upload as opening to temp-file for upload failed:",
! 1099: dst_c->file.name, strerror(errno));
! 1100:
! 1101: con->http_status = 413; /* Request-Entity too large */
! 1102: con->keep_alive = 0;
! 1103: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1104:
! 1105: break;
! 1106: }
! 1107:
! 1108: if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
! 1109: /* write failed for some reason ... disk full ? */
! 1110: log_error_write(srv, __FILE__, __LINE__, "sbs",
! 1111: "denying upload as writing to file failed:",
! 1112: dst_c->file.name, strerror(errno));
! 1113:
! 1114: con->http_status = 413; /* Request-Entity too large */
! 1115: con->keep_alive = 0;
! 1116: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1117:
! 1118: close(dst_c->file.fd);
! 1119: dst_c->file.fd = -1;
! 1120:
! 1121: break;
! 1122: }
! 1123:
! 1124: dst_c->file.length += toRead;
! 1125:
! 1126: if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
! 1127: /* we read everything, close the chunk */
! 1128: close(dst_c->file.fd);
! 1129: dst_c->file.fd = -1;
! 1130: }
! 1131: } else {
! 1132: buffer *b;
! 1133:
! 1134: if (dst_cq->last &&
! 1135: dst_cq->last->type == MEM_CHUNK) {
! 1136: b = dst_cq->last->mem;
! 1137: } else {
! 1138: b = chunkqueue_get_append_buffer(dst_cq);
! 1139: /* prepare buffer size for remaining POST data; is < 64kb */
! 1140: buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in + 1);
! 1141: }
! 1142: buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
! 1143: }
! 1144:
! 1145: c->offset += toRead;
! 1146: dst_cq->bytes_in += toRead;
! 1147: }
! 1148:
! 1149: /* Content is ready */
! 1150: if (dst_cq->bytes_in == (off_t)con->request.content_length) {
! 1151: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1152: }
! 1153:
! 1154: break;
! 1155: default: break;
! 1156: }
! 1157:
! 1158: /* the connection got closed and we didn't got enough data to leave one of the READ states
! 1159: * the only way is to leave here */
! 1160: if (is_closed && ostate == con->state) {
! 1161: connection_set_state(srv, con, CON_STATE_ERROR);
! 1162: }
! 1163:
! 1164: chunkqueue_remove_finished_chunks(cq);
! 1165:
! 1166: return 0;
! 1167: }
! 1168:
! 1169: static handler_t connection_handle_fdevent(server *srv, void *context, int revents) {
! 1170: connection *con = context;
! 1171:
! 1172: joblist_append(srv, con);
! 1173:
! 1174: if (con->srv_socket->is_ssl) {
! 1175: /* ssl may read and write for both reads and writes */
! 1176: if (revents & (FDEVENT_IN | FDEVENT_OUT)) {
! 1177: con->is_readable = 1;
! 1178: con->is_writable = 1;
! 1179: }
! 1180: } else {
! 1181: if (revents & FDEVENT_IN) {
! 1182: con->is_readable = 1;
! 1183: }
! 1184: if (revents & FDEVENT_OUT) {
! 1185: con->is_writable = 1;
! 1186: /* we don't need the event twice */
! 1187: }
! 1188: }
! 1189:
! 1190:
! 1191: if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
! 1192: /* looks like an error */
! 1193:
! 1194: /* FIXME: revents = 0x19 still means that we should read from the queue */
! 1195: if (revents & FDEVENT_HUP) {
! 1196: if (con->state == CON_STATE_CLOSE) {
! 1197: con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
! 1198: } else {
! 1199: /* sigio reports the wrong event here
! 1200: *
! 1201: * there was no HUP at all
! 1202: */
! 1203: #ifdef USE_LINUX_SIGIO
! 1204: if (srv->ev->in_sigio == 1) {
! 1205: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1206: "connection closed: poll() -> HUP", con->fd);
! 1207: } else {
! 1208: connection_set_state(srv, con, CON_STATE_ERROR);
! 1209: }
! 1210: #else
! 1211: connection_set_state(srv, con, CON_STATE_ERROR);
! 1212: #endif
! 1213:
! 1214: }
! 1215: } else if (revents & FDEVENT_ERR) {
! 1216: /* error, connection reset, whatever... we don't want to spam the logfile */
! 1217: #if 0
! 1218: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1219: "connection closed: poll() -> ERR", con->fd);
! 1220: #endif
! 1221: connection_set_state(srv, con, CON_STATE_ERROR);
! 1222: } else {
! 1223: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1224: "connection closed: poll() -> ???", revents);
! 1225: }
! 1226: }
! 1227:
! 1228: if (con->state == CON_STATE_READ ||
! 1229: con->state == CON_STATE_READ_POST) {
! 1230: connection_handle_read_state(srv, con);
! 1231: }
! 1232:
! 1233: if (con->state == CON_STATE_WRITE &&
! 1234: !chunkqueue_is_empty(con->write_queue) &&
! 1235: con->is_writable) {
! 1236:
! 1237: if (-1 == connection_handle_write(srv, con)) {
! 1238: connection_set_state(srv, con, CON_STATE_ERROR);
! 1239:
! 1240: log_error_write(srv, __FILE__, __LINE__, "ds",
! 1241: con->fd,
! 1242: "handle write failed.");
! 1243: }
! 1244: }
! 1245:
! 1246: if (con->state == CON_STATE_CLOSE) {
! 1247: /* flush the read buffers */
! 1248: int len;
! 1249: char buf[1024];
! 1250:
! 1251: len = read(con->fd, buf, sizeof(buf));
! 1252: if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {
! 1253: con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
! 1254: }
! 1255: }
! 1256:
! 1257: return HANDLER_FINISHED;
! 1258: }
! 1259:
! 1260:
! 1261: connection *connection_accept(server *srv, server_socket *srv_socket) {
! 1262: /* accept everything */
! 1263:
! 1264: /* search an empty place */
! 1265: int cnt;
! 1266: sock_addr cnt_addr;
! 1267: socklen_t cnt_len;
! 1268: /* accept it and register the fd */
! 1269:
! 1270: /**
! 1271: * check if we can still open a new connections
! 1272: *
! 1273: * see #1216
! 1274: */
! 1275:
! 1276: if (srv->conns->used >= srv->max_conns) {
! 1277: return NULL;
! 1278: }
! 1279:
! 1280: cnt_len = sizeof(cnt_addr);
! 1281:
! 1282: if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
! 1283: switch (errno) {
! 1284: case EAGAIN:
! 1285: #if EWOULDBLOCK != EAGAIN
! 1286: case EWOULDBLOCK:
! 1287: #endif
! 1288: case EINTR:
! 1289: /* we were stopped _before_ we had a connection */
! 1290: case ECONNABORTED: /* this is a FreeBSD thingy */
! 1291: /* we were stopped _after_ we had a connection */
! 1292: break;
! 1293: case EMFILE:
! 1294: /* out of fds */
! 1295: break;
! 1296: default:
! 1297: log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
! 1298: }
! 1299: return NULL;
! 1300: } else {
! 1301: connection *con;
! 1302:
! 1303: srv->cur_fds++;
! 1304:
! 1305: /* ok, we have the connection, register it */
! 1306: #if 0
! 1307: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1308: "appected()", cnt);
! 1309: #endif
! 1310: srv->con_opened++;
! 1311:
! 1312: con = connections_get_new_connection(srv);
! 1313:
! 1314: con->fd = cnt;
! 1315: con->fde_ndx = -1;
! 1316: #if 0
! 1317: gettimeofday(&(con->start_tv), NULL);
! 1318: #endif
! 1319: fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
! 1320:
! 1321: connection_set_state(srv, con, CON_STATE_REQUEST_START);
! 1322:
! 1323: con->connection_start = srv->cur_ts;
! 1324: con->dst_addr = cnt_addr;
! 1325: buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
! 1326: con->srv_socket = srv_socket;
! 1327:
! 1328: if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
! 1329: log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
! 1330: return NULL;
! 1331: }
! 1332: #ifdef USE_OPENSSL
! 1333: /* connect FD to SSL */
! 1334: if (srv_socket->is_ssl) {
! 1335: if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
! 1336: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
! 1337: ERR_error_string(ERR_get_error(), NULL));
! 1338:
! 1339: return NULL;
! 1340: }
! 1341:
! 1342: con->renegotiations = 0;
! 1343: SSL_set_app_data(con->ssl, con);
! 1344: SSL_set_accept_state(con->ssl);
! 1345:
! 1346: if (1 != (SSL_set_fd(con->ssl, cnt))) {
! 1347: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
! 1348: ERR_error_string(ERR_get_error(), NULL));
! 1349: return NULL;
! 1350: }
! 1351: }
! 1352: #endif
! 1353: return con;
! 1354: }
! 1355: }
! 1356:
! 1357:
! 1358: int connection_state_machine(server *srv, connection *con) {
! 1359: int done = 0, r;
! 1360: #ifdef USE_OPENSSL
! 1361: server_socket *srv_sock = con->srv_socket;
! 1362: #endif
! 1363:
! 1364: if (srv->srvconf.log_state_handling) {
! 1365: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1366: "state at start",
! 1367: con->fd,
! 1368: connection_get_state(con->state));
! 1369: }
! 1370:
! 1371: while (done == 0) {
! 1372: size_t ostate = con->state;
! 1373:
! 1374: switch (con->state) {
! 1375: case CON_STATE_REQUEST_START: /* transient */
! 1376: if (srv->srvconf.log_state_handling) {
! 1377: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1378: "state for fd", con->fd, connection_get_state(con->state));
! 1379: }
! 1380:
! 1381: con->request_start = srv->cur_ts;
! 1382: con->read_idle_ts = srv->cur_ts;
! 1383:
! 1384: con->request_count++;
! 1385: con->loops_per_request = 0;
! 1386:
! 1387: connection_set_state(srv, con, CON_STATE_READ);
! 1388:
! 1389: break;
! 1390: case CON_STATE_REQUEST_END: /* transient */
! 1391: if (srv->srvconf.log_state_handling) {
! 1392: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1393: "state for fd", con->fd, connection_get_state(con->state));
! 1394: }
! 1395:
! 1396: buffer_reset(con->uri.authority);
! 1397: buffer_reset(con->uri.path);
! 1398: buffer_reset(con->uri.query);
! 1399: buffer_reset(con->request.orig_uri);
! 1400:
! 1401: if (http_request_parse(srv, con)) {
! 1402: /* we have to read some data from the POST request */
! 1403:
! 1404: connection_set_state(srv, con, CON_STATE_READ_POST);
! 1405:
! 1406: break;
! 1407: }
! 1408:
! 1409: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1410:
! 1411: break;
! 1412: case CON_STATE_HANDLE_REQUEST:
! 1413: /*
! 1414: * the request is parsed
! 1415: *
! 1416: * decided what to do with the request
! 1417: * -
! 1418: *
! 1419: *
! 1420: */
! 1421:
! 1422: if (srv->srvconf.log_state_handling) {
! 1423: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1424: "state for fd", con->fd, connection_get_state(con->state));
! 1425: }
! 1426:
! 1427: switch (r = http_response_prepare(srv, con)) {
! 1428: case HANDLER_FINISHED:
! 1429: if (con->mode == DIRECT) {
! 1430: if (con->http_status == 404 ||
! 1431: con->http_status == 403) {
! 1432: /* 404 error-handler */
! 1433:
! 1434: if (con->in_error_handler == 0 &&
! 1435: (!buffer_is_empty(con->conf.error_handler) ||
! 1436: !buffer_is_empty(con->error_handler))) {
! 1437: /* call error-handler */
! 1438:
! 1439: con->error_handler_saved_status = con->http_status;
! 1440: con->http_status = 0;
! 1441:
! 1442: if (buffer_is_empty(con->error_handler)) {
! 1443: buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
! 1444: } else {
! 1445: buffer_copy_string_buffer(con->request.uri, con->error_handler);
! 1446: }
! 1447: buffer_reset(con->physical.path);
! 1448:
! 1449: con->in_error_handler = 1;
! 1450:
! 1451: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1452:
! 1453: done = -1;
! 1454: break;
! 1455: } else if (con->in_error_handler) {
! 1456: /* error-handler is a 404 */
! 1457:
! 1458: con->http_status = con->error_handler_saved_status;
! 1459: }
! 1460: } else if (con->in_error_handler) {
! 1461: /* error-handler is back and has generated content */
! 1462: /* if Status: was set, take it otherwise use 200 */
! 1463: }
! 1464: }
! 1465: if (con->http_status == 0) con->http_status = 200;
! 1466:
! 1467: /* we have something to send, go on */
! 1468: connection_set_state(srv, con, CON_STATE_RESPONSE_START);
! 1469: break;
! 1470: case HANDLER_WAIT_FOR_FD:
! 1471: srv->want_fds++;
! 1472:
! 1473: fdwaitqueue_append(srv, con);
! 1474:
! 1475: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1476:
! 1477: break;
! 1478: case HANDLER_COMEBACK:
! 1479: done = -1;
! 1480: case HANDLER_WAIT_FOR_EVENT:
! 1481: /* come back here */
! 1482: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 1483:
! 1484: break;
! 1485: case HANDLER_ERROR:
! 1486: /* something went wrong */
! 1487: connection_set_state(srv, con, CON_STATE_ERROR);
! 1488: break;
! 1489: default:
! 1490: log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
! 1491: break;
! 1492: }
! 1493:
! 1494: break;
! 1495: case CON_STATE_RESPONSE_START:
! 1496: /*
! 1497: * the decision is done
! 1498: * - create the HTTP-Response-Header
! 1499: *
! 1500: */
! 1501:
! 1502: if (srv->srvconf.log_state_handling) {
! 1503: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1504: "state for fd", con->fd, connection_get_state(con->state));
! 1505: }
! 1506:
! 1507: if (-1 == connection_handle_write_prepare(srv, con)) {
! 1508: connection_set_state(srv, con, CON_STATE_ERROR);
! 1509:
! 1510: break;
! 1511: }
! 1512:
! 1513: connection_set_state(srv, con, CON_STATE_WRITE);
! 1514: break;
! 1515: case CON_STATE_RESPONSE_END: /* transient */
! 1516: /* log the request */
! 1517:
! 1518: if (srv->srvconf.log_state_handling) {
! 1519: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1520: "state for fd", con->fd, connection_get_state(con->state));
! 1521: }
! 1522:
! 1523: plugins_call_handle_request_done(srv, con);
! 1524:
! 1525: srv->con_written++;
! 1526:
! 1527: if (con->keep_alive) {
! 1528: connection_set_state(srv, con, CON_STATE_REQUEST_START);
! 1529:
! 1530: #if 0
! 1531: con->request_start = srv->cur_ts;
! 1532: con->read_idle_ts = srv->cur_ts;
! 1533: #endif
! 1534: } else {
! 1535: switch(r = plugins_call_handle_connection_close(srv, con)) {
! 1536: case HANDLER_GO_ON:
! 1537: case HANDLER_FINISHED:
! 1538: break;
! 1539: default:
! 1540: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
! 1541: break;
! 1542: }
! 1543:
! 1544: #ifdef USE_OPENSSL
! 1545: if (srv_sock->is_ssl) {
! 1546: switch (SSL_shutdown(con->ssl)) {
! 1547: case 1:
! 1548: /* done */
! 1549: break;
! 1550: case 0:
! 1551: /* wait for fd-event
! 1552: *
! 1553: * FIXME: wait for fdevent and call SSL_shutdown again
! 1554: *
! 1555: */
! 1556:
! 1557: break;
! 1558: default:
! 1559: log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
! 1560: ERR_error_string(ERR_get_error(), NULL));
! 1561: }
! 1562: }
! 1563: #endif
! 1564: if ((0 == shutdown(con->fd, SHUT_WR))) {
! 1565: con->close_timeout_ts = srv->cur_ts;
! 1566: connection_set_state(srv, con, CON_STATE_CLOSE);
! 1567: } else {
! 1568: connection_close(srv, con);
! 1569: }
! 1570:
! 1571: srv->con_closed++;
! 1572: }
! 1573:
! 1574: connection_reset(srv, con);
! 1575:
! 1576: break;
! 1577: case CON_STATE_CONNECT:
! 1578: if (srv->srvconf.log_state_handling) {
! 1579: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1580: "state for fd", con->fd, connection_get_state(con->state));
! 1581: }
! 1582:
! 1583: chunkqueue_reset(con->read_queue);
! 1584:
! 1585: con->request_count = 0;
! 1586:
! 1587: break;
! 1588: case CON_STATE_CLOSE:
! 1589: if (srv->srvconf.log_state_handling) {
! 1590: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1591: "state for fd", con->fd, connection_get_state(con->state));
! 1592: }
! 1593:
! 1594: /* we have to do the linger_on_close stuff regardless
! 1595: * of con->keep_alive; even non-keepalive sockets may
! 1596: * still have unread data, and closing before reading
! 1597: * it will make the client not see all our output.
! 1598: */
! 1599: {
! 1600: int len;
! 1601: char buf[1024];
! 1602:
! 1603: len = read(con->fd, buf, sizeof(buf));
! 1604: if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {
! 1605: con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
! 1606: }
! 1607: }
! 1608:
! 1609: if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) {
! 1610: connection_close(srv, con);
! 1611:
! 1612: if (srv->srvconf.log_state_handling) {
! 1613: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1614: "connection closed for fd", con->fd);
! 1615: }
! 1616: }
! 1617:
! 1618: break;
! 1619: case CON_STATE_READ_POST:
! 1620: case CON_STATE_READ:
! 1621: if (srv->srvconf.log_state_handling) {
! 1622: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1623: "state for fd", con->fd, connection_get_state(con->state));
! 1624: }
! 1625:
! 1626: connection_handle_read_state(srv, con);
! 1627: break;
! 1628: case CON_STATE_WRITE:
! 1629: if (srv->srvconf.log_state_handling) {
! 1630: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1631: "state for fd", con->fd, connection_get_state(con->state));
! 1632: }
! 1633:
! 1634: /* only try to write if we have something in the queue */
! 1635: if (!chunkqueue_is_empty(con->write_queue)) {
! 1636: #if 0
! 1637: log_error_write(srv, __FILE__, __LINE__, "dsd",
! 1638: con->fd,
! 1639: "packets to write:",
! 1640: con->write_queue->used);
! 1641: #endif
! 1642: }
! 1643: if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
! 1644: if (-1 == connection_handle_write(srv, con)) {
! 1645: log_error_write(srv, __FILE__, __LINE__, "ds",
! 1646: con->fd,
! 1647: "handle write failed.");
! 1648: connection_set_state(srv, con, CON_STATE_ERROR);
! 1649: }
! 1650: }
! 1651:
! 1652: break;
! 1653: case CON_STATE_ERROR: /* transient */
! 1654:
! 1655: /* even if the connection was drop we still have to write it to the access log */
! 1656: if (con->http_status) {
! 1657: plugins_call_handle_request_done(srv, con);
! 1658: }
! 1659: #ifdef USE_OPENSSL
! 1660: if (srv_sock->is_ssl) {
! 1661: int ret, ssl_r;
! 1662: unsigned long err;
! 1663: ERR_clear_error();
! 1664: switch ((ret = SSL_shutdown(con->ssl))) {
! 1665: case 1:
! 1666: /* ok */
! 1667: break;
! 1668: case 0:
! 1669: ERR_clear_error();
! 1670: if (-1 != (ret = SSL_shutdown(con->ssl))) break;
! 1671:
! 1672: /* fall through */
! 1673: default:
! 1674:
! 1675: switch ((ssl_r = SSL_get_error(con->ssl, ret))) {
! 1676: case SSL_ERROR_WANT_WRITE:
! 1677: case SSL_ERROR_WANT_READ:
! 1678: break;
! 1679: case SSL_ERROR_SYSCALL:
! 1680: /* perhaps we have error waiting in our error-queue */
! 1681: if (0 != (err = ERR_get_error())) {
! 1682: do {
! 1683: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 1684: ssl_r, ret,
! 1685: ERR_error_string(err, NULL));
! 1686: } while((err = ERR_get_error()));
! 1687: } else if (errno != 0) { /* ssl bug (see lighttpd ticket #2213): sometimes errno == 0 */
! 1688: switch(errno) {
! 1689: case EPIPE:
! 1690: case ECONNRESET:
! 1691: break;
! 1692: default:
! 1693: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
! 1694: ssl_r, ret, errno,
! 1695: strerror(errno));
! 1696: break;
! 1697: }
! 1698: }
! 1699:
! 1700: break;
! 1701: default:
! 1702: while((err = ERR_get_error())) {
! 1703: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 1704: ssl_r, ret,
! 1705: ERR_error_string(err, NULL));
! 1706: }
! 1707:
! 1708: break;
! 1709: }
! 1710: }
! 1711: ERR_clear_error();
! 1712: }
! 1713: #endif
! 1714:
! 1715: switch(con->mode) {
! 1716: case DIRECT:
! 1717: #if 0
! 1718: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1719: "emergency exit: direct",
! 1720: con->fd);
! 1721: #endif
! 1722: break;
! 1723: default:
! 1724: switch(r = plugins_call_handle_connection_close(srv, con)) {
! 1725: case HANDLER_GO_ON:
! 1726: case HANDLER_FINISHED:
! 1727: break;
! 1728: default:
! 1729: log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
! 1730: break;
! 1731: }
! 1732: break;
! 1733: }
! 1734:
! 1735: connection_reset(srv, con);
! 1736:
! 1737: /* close the connection */
! 1738: if ((0 == shutdown(con->fd, SHUT_WR))) {
! 1739: con->close_timeout_ts = srv->cur_ts;
! 1740: connection_set_state(srv, con, CON_STATE_CLOSE);
! 1741:
! 1742: if (srv->srvconf.log_state_handling) {
! 1743: log_error_write(srv, __FILE__, __LINE__, "sd",
! 1744: "shutdown for fd", con->fd);
! 1745: }
! 1746: } else {
! 1747: connection_close(srv, con);
! 1748: }
! 1749:
! 1750: con->keep_alive = 0;
! 1751:
! 1752: srv->con_closed++;
! 1753:
! 1754: break;
! 1755: default:
! 1756: log_error_write(srv, __FILE__, __LINE__, "sdd",
! 1757: "unknown state:", con->fd, con->state);
! 1758:
! 1759: break;
! 1760: }
! 1761:
! 1762: if (done == -1) {
! 1763: done = 0;
! 1764: } else if (ostate == con->state) {
! 1765: done = 1;
! 1766: }
! 1767: }
! 1768:
! 1769: if (srv->srvconf.log_state_handling) {
! 1770: log_error_write(srv, __FILE__, __LINE__, "sds",
! 1771: "state at exit:",
! 1772: con->fd,
! 1773: connection_get_state(con->state));
! 1774: }
! 1775:
! 1776: switch(con->state) {
! 1777: case CON_STATE_READ_POST:
! 1778: case CON_STATE_READ:
! 1779: case CON_STATE_CLOSE:
! 1780: fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
! 1781: break;
! 1782: case CON_STATE_WRITE:
! 1783: /* request write-fdevent only if we really need it
! 1784: * - if we have data to write
! 1785: * - if the socket is not writable yet
! 1786: */
! 1787: if (!chunkqueue_is_empty(con->write_queue) &&
! 1788: (con->is_writable == 0) &&
! 1789: (con->traffic_limit_reached == 0)) {
! 1790: fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
! 1791: } else {
! 1792: fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
! 1793: }
! 1794: break;
! 1795: default:
! 1796: fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
! 1797: break;
! 1798: }
! 1799:
! 1800: return 0;
! 1801: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>