Diff for /embedaddon/lighttpd/src/connections-glue.c between versions 1.1 and 1.1.1.2

version 1.1, 2013/10/14 10:32:48 version 1.1.1.2, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "base.h"  #include "base.h"
 #include "connections.h"  #include "connections.h"
   #include "joblist.h"
   #include "log.h"
   
   #include <errno.h>
   
   #ifdef USE_OPENSSL
   # include <openssl/ssl.h>
   # include <openssl/err.h>
   #endif
   
 const char *connection_get_state(connection_state_t state) {  const char *connection_get_state(connection_state_t state) {
         switch (state) {          switch (state) {
         case CON_STATE_CONNECT: return "connect";          case CON_STATE_CONNECT: return "connect";
Line 43  int connection_set_state(server *srv, connection *con, Line 54  int connection_set_state(server *srv, connection *con,
         return 0;          return 0;
 }  }
   
   #if 0
   static void dump_packet(const unsigned char *data, size_t len) {
           size_t i, j;
   
           if (len == 0) return;
   
           for (i = 0; i < len; i++) {
                   if (i % 16 == 0) fprintf(stderr, "  ");
   
                   fprintf(stderr, "%02x ", data[i]);
   
                   if ((i + 1) % 16 == 0) {
                           fprintf(stderr, "  ");
                           for (j = 0; j <= i % 16; j++) {
                                   unsigned char c;
   
                                   if (i-15+j >= len) break;
   
                                   c = data[i-15+j];
   
                                   fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
                           }
   
                           fprintf(stderr, "\n");
                   }
           }
   
           if (len % 16 != 0) {
                   for (j = i % 16; j < 16; j++) {
                           fprintf(stderr, "   ");
                   }
   
                   fprintf(stderr, "  ");
                   for (j = i & ~0xf; j < len; j++) {
                           unsigned char c;
   
                           c = data[j];
                           fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
                   }
                   fprintf(stderr, "\n");
           }
   }
   #endif
   
   static int connection_handle_read_ssl(server *srv, connection *con) {
   #ifdef USE_OPENSSL
           int r, ssl_err, len;
           char *mem = NULL;
           size_t mem_len = 0;
   
           if (!con->srv_socket->is_ssl) return -1;
   
           ERR_clear_error();
           do {
                   chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl));
   #if 0
                   /* overwrite everything with 0 */
                   memset(mem, 0, mem_len);
   #endif
   
                   len = SSL_read(con->ssl, mem, mem_len);
                   if (len > 0) {
                           chunkqueue_use_memory(con->read_queue, len);
                           con->bytes_read += len;
                   } else {
                           chunkqueue_use_memory(con->read_queue, 0);
                   }
   
                   if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
                           log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
                           connection_set_state(srv, con, CON_STATE_ERROR);
                           return -1;
                   }
           } while (len > 0);
   
           if (len < 0) {
                   int oerrno = errno;
                   switch ((r = SSL_get_error(con->ssl, len))) {
                   case SSL_ERROR_WANT_WRITE:
                           con->is_writable = -1;
                   case SSL_ERROR_WANT_READ:
                           con->is_readable = 0;
   
                           /* the manual says we have to call SSL_read with the same arguments next time.
                            * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
                            */
   
                           return 0;
                   case SSL_ERROR_SYSCALL:
                           /**
                            * man SSL_get_error()
                            *
                            * SSL_ERROR_SYSCALL
                            *   Some I/O error occurred.  The OpenSSL error queue may contain more
                            *   information on the error.  If the error queue is empty (i.e.
                            *   ERR_get_error() returns 0), ret can be used to find out more about
                            *   the error: If ret == 0, an EOF was observed that violates the
                            *   protocol.  If ret == -1, the underlying BIO reported an I/O error
                            *   (for socket I/O on Unix systems, consult errno for details).
                            *
                            */
                           while((ssl_err = ERR_get_error())) {
                                   /* get all errors from the error-queue */
                                   log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
                                                   r, ERR_error_string(ssl_err, NULL));
                           }
   
                           switch(oerrno) {
                           default:
                                   log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
                                                   len, r, oerrno,
                                                   strerror(oerrno));
                                   break;
                           }
   
                           break;
                   case SSL_ERROR_ZERO_RETURN:
                           /* clean shutdown on the remote side */
   
                           if (r == 0) {
                                   /* FIXME: later */
                           }
   
                           /* fall thourgh */
                   default:
                           while((ssl_err = ERR_get_error())) {
                                   switch (ERR_GET_REASON(ssl_err)) {
                                   case SSL_R_SSL_HANDSHAKE_FAILURE:
                                 #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA
                                   case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
                                 #endif
                                 #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN
                                   case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
                                 #endif
                                 #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
                                   case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
                                 #endif
                                           if (!con->conf.log_ssl_noise) continue;
                                           break;
                                   default:
                                           break;
                                   }
                                   /* get all errors from the error-queue */
                                   log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
                                                   r, ERR_error_string(ssl_err, NULL));
                           }
                           break;
                   }
   
                   connection_set_state(srv, con, CON_STATE_ERROR);
   
                   return -1;
           } else if (len == 0) {
                   con->is_readable = 0;
                   /* the other end close the connection -> KEEP-ALIVE */
   
                   return -2;
           } else {
                   return 0;
           }
   #else
           UNUSED(srv);
           UNUSED(con);
           return -1;
   #endif
   }
   
   /* 0: everything ok, -1: error, -2: con closed */
   int connection_handle_read(server *srv, connection *con) {
           int len;
           char *mem = NULL;
           size_t mem_len = 0;
           int toread;
   
           if (con->srv_socket->is_ssl) {
                   return connection_handle_read_ssl(srv, con);
           }
   
           /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
            *  us more than 4kb is available
            * if FIONREAD doesn't signal a big chunk we fill the previous buffer
            *  if it has >= 1kb free
            */
   #if defined(__WIN32)
           chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096);
   
           len = recv(con->fd, mem, mem_len, 0);
   #else /* __WIN32 */
           if (ioctl(con->fd, FIONREAD, &toread) || toread <= 4*1024) {
                   toread = 4096;
           }
           else if (toread > MAX_READ_LIMIT) {
                   toread = MAX_READ_LIMIT;
           }
           chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread);
   
           len = read(con->fd, mem, mem_len);
   #endif /* __WIN32 */
   
           chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
   
           if (len < 0) {
                   con->is_readable = 0;
   
   #if defined(__WIN32)
                   {
                           int lastError = WSAGetLastError();
                           switch (lastError) {
                           case EAGAIN:
                                   return 0;
                           case EINTR:
                                   /* we have been interrupted before we could read */
                                   con->is_readable = 1;
                                   return 0;
                           case ECONNRESET:
                                   /* suppress logging for this error, expected for keep-alive */
                                   break;
                           default:
                                   log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - recv failed: ", lastError);
                                   break;
                           }
                   }
   #else /* __WIN32 */
                   switch (errno) {
                   case EAGAIN:
                           return 0;
                   case EINTR:
                           /* we have been interrupted before we could read */
                           con->is_readable = 1;
                           return 0;
                   case ECONNRESET:
                           /* suppress logging for this error, expected for keep-alive */
                           break;
                   default:
                           log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
                           break;
                   }
   #endif /* __WIN32 */
   
                   connection_set_state(srv, con, CON_STATE_ERROR);
   
                   return -1;
           } else if (len == 0) {
                   con->is_readable = 0;
                   /* the other end close the connection -> KEEP-ALIVE */
   
                   /* pipelining */
   
                   return -2;
           } else if (len != (ssize_t) mem_len) {
                   /* we got less then expected, wait for the next fd-event */
   
                   con->is_readable = 0;
           }
   
           con->bytes_read += len;
   #if 0
           dump_packet(b->ptr, len);
   #endif
   
           return 0;
   }
   
   handler_t connection_handle_read_post_state(server *srv, connection *con) {
           chunkqueue *cq = con->read_queue;
           chunkqueue *dst_cq = con->request_content_queue;
   
           int is_closed = 0;
   
           if (con->is_readable) {
                   con->read_idle_ts = srv->cur_ts;
   
                   switch(connection_handle_read(srv, con)) {
                   case -1:
                           return HANDLER_ERROR;
                   case -2:
                           is_closed = 1;
                           break;
                   default:
                           break;
                   }
           }
   
           chunkqueue_remove_finished_chunks(cq);
   
           if (con->request.content_length <= 64*1024) {
                   /* don't buffer request bodies <= 64k on disk */
                   chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
           }
           else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
                   /* writing to temp file failed */
                   con->http_status = 500; /* Internal Server Error */
                   con->keep_alive = 0;
                   con->mode = DIRECT;
                   chunkqueue_reset(con->write_queue);
   
                   return HANDLER_FINISHED;
           }
   
           chunkqueue_remove_finished_chunks(cq);
   
           if (dst_cq->bytes_in == (off_t)con->request.content_length) {
                   /* Content is ready */
                   con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
                   if (con->state == CON_STATE_READ_POST) {
                           connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
                   }
                   return HANDLER_GO_ON;
           } else if (is_closed) {
                 #if 0
                   con->http_status = 400; /* Bad Request */
                   con->keep_alive = 0;
                   con->mode = DIRECT;
                   chunkqueue_reset(con->write_queue);
   
                   return HANDLER_FINISHED;
                 #endif
                   return HANDLER_ERROR;
           } else {
                   con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
                   return (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)
                     ? HANDLER_GO_ON
                     : HANDLER_WAIT_FOR_EVENT;
           }
   }
   
   void connection_response_reset(server *srv, connection *con) {
           UNUSED(srv);
   
           con->http_status = 0;
           con->is_writable = 1;
           con->file_finished = 0;
           con->file_started = 0;
           con->got_response = 0;
           con->parsed_response = 0;
           con->response.keep_alive = 0;
           con->response.content_length = -1;
           con->response.transfer_encoding = 0;
           buffer_reset(con->physical.path);
           array_reset(con->response.headers);
           chunkqueue_reset(con->write_queue);
   }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.2


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