Annotation of embedaddon/lighttpd/src/connections-glue.c, revision 1.1.1.2

1.1.1.2 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       3: #include "base.h"
                      4: #include "connections.h"
1.1.1.2 ! misho       5: #include "joblist.h"
        !             6: #include "log.h"
        !             7: 
        !             8: #include <errno.h>
        !             9: 
        !            10: #ifdef USE_OPENSSL
        !            11: # include <openssl/ssl.h>
        !            12: # include <openssl/err.h>
        !            13: #endif
1.1       misho      14: 
                     15: const char *connection_get_state(connection_state_t state) {
                     16:        switch (state) {
                     17:        case CON_STATE_CONNECT: return "connect";
                     18:        case CON_STATE_READ: return "read";
                     19:        case CON_STATE_READ_POST: return "readpost";
                     20:        case CON_STATE_WRITE: return "write";
                     21:        case CON_STATE_CLOSE: return "close";
                     22:        case CON_STATE_ERROR: return "error";
                     23:        case CON_STATE_HANDLE_REQUEST: return "handle-req";
                     24:        case CON_STATE_REQUEST_START: return "req-start";
                     25:        case CON_STATE_REQUEST_END: return "req-end";
                     26:        case CON_STATE_RESPONSE_START: return "resp-start";
                     27:        case CON_STATE_RESPONSE_END: return "resp-end";
                     28:        default: return "(unknown)";
                     29:        }
                     30: }
                     31: 
                     32: const char *connection_get_short_state(connection_state_t state) {
                     33:        switch (state) {
                     34:        case CON_STATE_CONNECT: return ".";
                     35:        case CON_STATE_READ: return "r";
                     36:        case CON_STATE_READ_POST: return "R";
                     37:        case CON_STATE_WRITE: return "W";
                     38:        case CON_STATE_CLOSE: return "C";
                     39:        case CON_STATE_ERROR: return "E";
                     40:        case CON_STATE_HANDLE_REQUEST: return "h";
                     41:        case CON_STATE_REQUEST_START: return "q";
                     42:        case CON_STATE_REQUEST_END: return "Q";
                     43:        case CON_STATE_RESPONSE_START: return "s";
                     44:        case CON_STATE_RESPONSE_END: return "S";
                     45:        default: return "x";
                     46:        }
                     47: }
                     48: 
                     49: int connection_set_state(server *srv, connection *con, connection_state_t state) {
                     50:        UNUSED(srv);
                     51: 
                     52:        con->state = state;
                     53: 
                     54:        return 0;
                     55: }
                     56: 
1.1.1.2 ! misho      57: #if 0
        !            58: static void dump_packet(const unsigned char *data, size_t len) {
        !            59:        size_t i, j;
        !            60: 
        !            61:        if (len == 0) return;
        !            62: 
        !            63:        for (i = 0; i < len; i++) {
        !            64:                if (i % 16 == 0) fprintf(stderr, "  ");
        !            65: 
        !            66:                fprintf(stderr, "%02x ", data[i]);
        !            67: 
        !            68:                if ((i + 1) % 16 == 0) {
        !            69:                        fprintf(stderr, "  ");
        !            70:                        for (j = 0; j <= i % 16; j++) {
        !            71:                                unsigned char c;
        !            72: 
        !            73:                                if (i-15+j >= len) break;
        !            74: 
        !            75:                                c = data[i-15+j];
        !            76: 
        !            77:                                fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
        !            78:                        }
        !            79: 
        !            80:                        fprintf(stderr, "\n");
        !            81:                }
        !            82:        }
        !            83: 
        !            84:        if (len % 16 != 0) {
        !            85:                for (j = i % 16; j < 16; j++) {
        !            86:                        fprintf(stderr, "   ");
        !            87:                }
        !            88: 
        !            89:                fprintf(stderr, "  ");
        !            90:                for (j = i & ~0xf; j < len; j++) {
        !            91:                        unsigned char c;
        !            92: 
        !            93:                        c = data[j];
        !            94:                        fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
        !            95:                }
        !            96:                fprintf(stderr, "\n");
        !            97:        }
        !            98: }
        !            99: #endif
        !           100: 
        !           101: static int connection_handle_read_ssl(server *srv, connection *con) {
        !           102: #ifdef USE_OPENSSL
        !           103:        int r, ssl_err, len;
        !           104:        char *mem = NULL;
        !           105:        size_t mem_len = 0;
        !           106: 
        !           107:        if (!con->srv_socket->is_ssl) return -1;
        !           108: 
        !           109:        ERR_clear_error();
        !           110:        do {
        !           111:                chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl));
        !           112: #if 0
        !           113:                /* overwrite everything with 0 */
        !           114:                memset(mem, 0, mem_len);
        !           115: #endif
        !           116: 
        !           117:                len = SSL_read(con->ssl, mem, mem_len);
        !           118:                if (len > 0) {
        !           119:                        chunkqueue_use_memory(con->read_queue, len);
        !           120:                        con->bytes_read += len;
        !           121:                } else {
        !           122:                        chunkqueue_use_memory(con->read_queue, 0);
        !           123:                }
        !           124: 
        !           125:                if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
        !           126:                        log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
        !           127:                        connection_set_state(srv, con, CON_STATE_ERROR);
        !           128:                        return -1;
        !           129:                }
        !           130:        } while (len > 0);
        !           131: 
        !           132:        if (len < 0) {
        !           133:                int oerrno = errno;
        !           134:                switch ((r = SSL_get_error(con->ssl, len))) {
        !           135:                case SSL_ERROR_WANT_WRITE:
        !           136:                        con->is_writable = -1;
        !           137:                case SSL_ERROR_WANT_READ:
        !           138:                        con->is_readable = 0;
        !           139: 
        !           140:                        /* the manual says we have to call SSL_read with the same arguments next time.
        !           141:                         * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
        !           142:                         */
        !           143: 
        !           144:                        return 0;
        !           145:                case SSL_ERROR_SYSCALL:
        !           146:                        /**
        !           147:                         * man SSL_get_error()
        !           148:                         *
        !           149:                         * SSL_ERROR_SYSCALL
        !           150:                         *   Some I/O error occurred.  The OpenSSL error queue may contain more
        !           151:                         *   information on the error.  If the error queue is empty (i.e.
        !           152:                         *   ERR_get_error() returns 0), ret can be used to find out more about
        !           153:                         *   the error: If ret == 0, an EOF was observed that violates the
        !           154:                         *   protocol.  If ret == -1, the underlying BIO reported an I/O error
        !           155:                         *   (for socket I/O on Unix systems, consult errno for details).
        !           156:                         *
        !           157:                         */
        !           158:                        while((ssl_err = ERR_get_error())) {
        !           159:                                /* get all errors from the error-queue */
        !           160:                                log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
        !           161:                                                r, ERR_error_string(ssl_err, NULL));
        !           162:                        }
        !           163: 
        !           164:                        switch(oerrno) {
        !           165:                        default:
        !           166:                                log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
        !           167:                                                len, r, oerrno,
        !           168:                                                strerror(oerrno));
        !           169:                                break;
        !           170:                        }
        !           171: 
        !           172:                        break;
        !           173:                case SSL_ERROR_ZERO_RETURN:
        !           174:                        /* clean shutdown on the remote side */
        !           175: 
        !           176:                        if (r == 0) {
        !           177:                                /* FIXME: later */
        !           178:                        }
        !           179: 
        !           180:                        /* fall thourgh */
        !           181:                default:
        !           182:                        while((ssl_err = ERR_get_error())) {
        !           183:                                switch (ERR_GET_REASON(ssl_err)) {
        !           184:                                case SSL_R_SSL_HANDSHAKE_FAILURE:
        !           185:                              #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA
        !           186:                                case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
        !           187:                              #endif
        !           188:                              #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN
        !           189:                                case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
        !           190:                              #endif
        !           191:                              #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
        !           192:                                case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
        !           193:                              #endif
        !           194:                                        if (!con->conf.log_ssl_noise) continue;
        !           195:                                        break;
        !           196:                                default:
        !           197:                                        break;
        !           198:                                }
        !           199:                                /* get all errors from the error-queue */
        !           200:                                log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
        !           201:                                                r, ERR_error_string(ssl_err, NULL));
        !           202:                        }
        !           203:                        break;
        !           204:                }
        !           205: 
        !           206:                connection_set_state(srv, con, CON_STATE_ERROR);
        !           207: 
        !           208:                return -1;
        !           209:        } else if (len == 0) {
        !           210:                con->is_readable = 0;
        !           211:                /* the other end close the connection -> KEEP-ALIVE */
        !           212: 
        !           213:                return -2;
        !           214:        } else {
        !           215:                return 0;
        !           216:        }
        !           217: #else
        !           218:        UNUSED(srv);
        !           219:        UNUSED(con);
        !           220:        return -1;
        !           221: #endif
        !           222: }
        !           223: 
        !           224: /* 0: everything ok, -1: error, -2: con closed */
        !           225: int connection_handle_read(server *srv, connection *con) {
        !           226:        int len;
        !           227:        char *mem = NULL;
        !           228:        size_t mem_len = 0;
        !           229:        int toread;
        !           230: 
        !           231:        if (con->srv_socket->is_ssl) {
        !           232:                return connection_handle_read_ssl(srv, con);
        !           233:        }
        !           234: 
        !           235:        /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
        !           236:         *  us more than 4kb is available
        !           237:         * if FIONREAD doesn't signal a big chunk we fill the previous buffer
        !           238:         *  if it has >= 1kb free
        !           239:         */
        !           240: #if defined(__WIN32)
        !           241:        chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096);
        !           242: 
        !           243:        len = recv(con->fd, mem, mem_len, 0);
        !           244: #else /* __WIN32 */
        !           245:        if (ioctl(con->fd, FIONREAD, &toread) || toread <= 4*1024) {
        !           246:                toread = 4096;
        !           247:        }
        !           248:        else if (toread > MAX_READ_LIMIT) {
        !           249:                toread = MAX_READ_LIMIT;
        !           250:        }
        !           251:        chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread);
        !           252: 
        !           253:        len = read(con->fd, mem, mem_len);
        !           254: #endif /* __WIN32 */
        !           255: 
        !           256:        chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
        !           257: 
        !           258:        if (len < 0) {
        !           259:                con->is_readable = 0;
        !           260: 
        !           261: #if defined(__WIN32)
        !           262:                {
        !           263:                        int lastError = WSAGetLastError();
        !           264:                        switch (lastError) {
        !           265:                        case EAGAIN:
        !           266:                                return 0;
        !           267:                        case EINTR:
        !           268:                                /* we have been interrupted before we could read */
        !           269:                                con->is_readable = 1;
        !           270:                                return 0;
        !           271:                        case ECONNRESET:
        !           272:                                /* suppress logging for this error, expected for keep-alive */
        !           273:                                break;
        !           274:                        default:
        !           275:                                log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - recv failed: ", lastError);
        !           276:                                break;
        !           277:                        }
        !           278:                }
        !           279: #else /* __WIN32 */
        !           280:                switch (errno) {
        !           281:                case EAGAIN:
        !           282:                        return 0;
        !           283:                case EINTR:
        !           284:                        /* we have been interrupted before we could read */
        !           285:                        con->is_readable = 1;
        !           286:                        return 0;
        !           287:                case ECONNRESET:
        !           288:                        /* suppress logging for this error, expected for keep-alive */
        !           289:                        break;
        !           290:                default:
        !           291:                        log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
        !           292:                        break;
        !           293:                }
        !           294: #endif /* __WIN32 */
        !           295: 
        !           296:                connection_set_state(srv, con, CON_STATE_ERROR);
        !           297: 
        !           298:                return -1;
        !           299:        } else if (len == 0) {
        !           300:                con->is_readable = 0;
        !           301:                /* the other end close the connection -> KEEP-ALIVE */
        !           302: 
        !           303:                /* pipelining */
        !           304: 
        !           305:                return -2;
        !           306:        } else if (len != (ssize_t) mem_len) {
        !           307:                /* we got less then expected, wait for the next fd-event */
        !           308: 
        !           309:                con->is_readable = 0;
        !           310:        }
        !           311: 
        !           312:        con->bytes_read += len;
        !           313: #if 0
        !           314:        dump_packet(b->ptr, len);
        !           315: #endif
        !           316: 
        !           317:        return 0;
        !           318: }
        !           319: 
        !           320: handler_t connection_handle_read_post_state(server *srv, connection *con) {
        !           321:        chunkqueue *cq = con->read_queue;
        !           322:        chunkqueue *dst_cq = con->request_content_queue;
        !           323: 
        !           324:        int is_closed = 0;
        !           325: 
        !           326:        if (con->is_readable) {
        !           327:                con->read_idle_ts = srv->cur_ts;
        !           328: 
        !           329:                switch(connection_handle_read(srv, con)) {
        !           330:                case -1:
        !           331:                        return HANDLER_ERROR;
        !           332:                case -2:
        !           333:                        is_closed = 1;
        !           334:                        break;
        !           335:                default:
        !           336:                        break;
        !           337:                }
        !           338:        }
        !           339: 
        !           340:        chunkqueue_remove_finished_chunks(cq);
        !           341: 
        !           342:        if (con->request.content_length <= 64*1024) {
        !           343:                /* don't buffer request bodies <= 64k on disk */
        !           344:                chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
        !           345:        }
        !           346:        else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
        !           347:                /* writing to temp file failed */
        !           348:                con->http_status = 500; /* Internal Server Error */
        !           349:                con->keep_alive = 0;
        !           350:                con->mode = DIRECT;
        !           351:                chunkqueue_reset(con->write_queue);
        !           352: 
        !           353:                return HANDLER_FINISHED;
        !           354:        }
        !           355: 
        !           356:        chunkqueue_remove_finished_chunks(cq);
        !           357: 
        !           358:        if (dst_cq->bytes_in == (off_t)con->request.content_length) {
        !           359:                /* Content is ready */
        !           360:                con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
        !           361:                if (con->state == CON_STATE_READ_POST) {
        !           362:                        connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
        !           363:                }
        !           364:                return HANDLER_GO_ON;
        !           365:        } else if (is_closed) {
        !           366:              #if 0
        !           367:                con->http_status = 400; /* Bad Request */
        !           368:                con->keep_alive = 0;
        !           369:                con->mode = DIRECT;
        !           370:                chunkqueue_reset(con->write_queue);
        !           371: 
        !           372:                return HANDLER_FINISHED;
        !           373:              #endif
        !           374:                return HANDLER_ERROR;
        !           375:        } else {
        !           376:                con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
        !           377:                return (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)
        !           378:                  ? HANDLER_GO_ON
        !           379:                  : HANDLER_WAIT_FOR_EVENT;
        !           380:        }
        !           381: }
        !           382: 
        !           383: void connection_response_reset(server *srv, connection *con) {
        !           384:        UNUSED(srv);
        !           385: 
        !           386:        con->http_status = 0;
        !           387:        con->is_writable = 1;
        !           388:        con->file_finished = 0;
        !           389:        con->file_started = 0;
        !           390:        con->got_response = 0;
        !           391:        con->parsed_response = 0;
        !           392:        con->response.keep_alive = 0;
        !           393:        con->response.content_length = -1;
        !           394:        con->response.transfer_encoding = 0;
        !           395:        buffer_reset(con->physical.path);
        !           396:        array_reset(con->response.headers);
        !           397:        chunkqueue_reset(con->write_queue);
        !           398: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>