diff src/event/ngx_event_openssl.c @ 126:df17fbafec8f NGINX_0_3_10

nginx 0.3.10 *) Change: the "valid_referers" directive and the "$invalid_referer" variable were moved to the new ngx_http_referer_module from the ngx_http_rewrite_module. *) Change: the "$apache_bytes_sent" variable name was changed to "$body_bytes_sent". *) Feature: the "$sent_http_..." variables. *) Feature: the "if" directive supports the "=" and "!=" operations. *) Feature: the "proxy_pass" directive supports the HTTPS protocol. *) Feature: the "proxy_set_body" directive. *) Feature: the "post_action" directive. *) Feature: the ngx_http_empty_gif_module. *) Feature: the "worker_cpu_affinity" directive for Linux. *) Bugfix: the "rewrite" directive did not unescape URI part in redirect, now it is unescaped except the %00-%25 and %7F-%FF characters. *) Bugfix: nginx could not be built by the icc 9.0 compiler. *) Bugfix: if the SSI was enabled for zero size static file, then the chunked response was encoded incorrectly.
author Igor Sysoev <http://sysoev.ru>
date Tue, 15 Nov 2005 00:00:00 +0300
parents e85dca77c46a
children 91372f004adf
line wrap: on
line diff
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -18,6 +18,7 @@ static void ngx_ssl_handshake_handler(ng
 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
 static void ngx_ssl_write_handler(ngx_event_t *wev);
 static void ngx_ssl_read_handler(ngx_event_t *rev);
+static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
     ngx_err_t err, char *text);
 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
@@ -51,7 +52,7 @@ static ngx_core_module_t  ngx_openssl_mo
     ngx_string("openssl"),
     ngx_openssl_create_conf,
     ngx_openssl_init_conf
-};  
+};
 
 
 ngx_module_t  ngx_openssl_module = {
@@ -99,19 +100,20 @@ ngx_ssl_init(ngx_log_t *log)
 ngx_int_t
 ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols)
 {
-    ssl->ctx = SSL_CTX_new(SSLv23_server_method());
+    ssl->ctx = SSL_CTX_new(SSLv23_method());
 
     if (ssl->ctx == NULL) {
         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
         return NGX_ERROR;
     }
 
-    /*
-     * these options are needed on client side only:
-     *    SSL_OP_MICROSOFT_SESS_ID_BUG
-     *    SSL_OP_NETSCAPE_CHALLENGE_BUG
-     *    SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
-     */
+    /* client side options */
+
+    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
+    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
+    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
+
+    /* server side options */
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
@@ -195,7 +197,7 @@ ngx_ssl_generate_rsa512_key(ngx_ssl_t *s
 
 ngx_int_t
 ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
-{   
+{
     ngx_ssl_connection_t  *sc;
 
     sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));
@@ -224,7 +226,12 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl
         return NGX_ERROR;
     }
 
-    SSL_set_accept_state(sc->connection);
+    if (flags & NGX_SSL_CLIENT) {
+        SSL_set_connect_state(sc->connection);
+
+    } else {
+        SSL_set_accept_state(sc->connection);
+    }
 
     c->ssl = sc;
 
@@ -233,6 +240,20 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl
 
 
 ngx_int_t
+ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session)
+{
+    if (session) {
+        if (SSL_set_session(c->ssl->connection, session) == 0) {
+            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_session() failed");
+            return NGX_ERROR;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_ssl_handshake(ngx_connection_t *c)
 {
     int        n, sslerr;
@@ -240,7 +261,7 @@ ngx_ssl_handshake(ngx_connection_t *c)
 
     n = SSL_do_handshake(c->ssl->connection);
 
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); 
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
 
     if (n == 1) {
 
@@ -282,7 +303,7 @@ ngx_ssl_handshake(ngx_connection_t *c)
 
             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
                            "SSL: %s, cipher: \"%s\"",
-                           SSL_get_version(c->ssl->connection), &buf[1]); 
+                           SSL_get_version(c->ssl->connection), &buf[1]);
 
             if (SSL_session_reused(c->ssl->connection)) {
                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -291,7 +312,7 @@ ngx_ssl_handshake(ngx_connection_t *c)
 
         } else {
             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "SSL no shared ciphers"); 
+                           "SSL no shared ciphers");
         }
         }
 #endif
@@ -300,7 +321,8 @@ ngx_ssl_handshake(ngx_connection_t *c)
 
         c->recv = ngx_ssl_recv;
         c->send = ngx_ssl_write;
-        c->send_chain = ngx_ssl_send_chain; 
+        c->recv_chain = ngx_ssl_recv_chain;
+        c->send_chain = ngx_ssl_send_chain;
 
         return NGX_OK;
     }
@@ -338,7 +360,7 @@ ngx_ssl_handshake(ngx_connection_t *c)
 
     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
         ngx_log_error(NGX_LOG_INFO, c->log, err,
-                      "client closed connection in SSL handshake");
+                      "peer closed connection in SSL handshake");
 
         return NGX_ERROR;
     }
@@ -357,7 +379,7 @@ ngx_ssl_handshake_handler(ngx_event_t *e
     c = ev->data;
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                   "ssl handshake handler: %d", ev->write);
+                   "SSL handshake handler: %d", ev->write);
 
     if (ngx_ssl_handshake(c) == NGX_AGAIN) {
         return;
@@ -368,6 +390,41 @@ ngx_ssl_handshake_handler(ngx_event_t *e
 
 
 ssize_t
+ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl)
+{
+    ssize_t     n, bytes;
+    ngx_buf_t  *b;
+
+    bytes = 0;
+
+    while (cl) {
+        b = cl->buf;
+
+        n = ngx_ssl_recv(c, b->last, b->end - b->last);
+
+        if (n > 0) {
+            b->last += n;
+            bytes += n;
+
+            if (b->last == b->end) {
+                cl = cl->next;
+            }
+
+            continue;
+        }
+
+        if (bytes) {
+            return bytes;
+        }
+
+        return n;
+    }
+
+    return bytes;
+}
+
+
+ssize_t
 ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
 {
     int  n, bytes;
@@ -376,6 +433,10 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
         return NGX_ERROR;
     }
 
+    if (c->ssl->last == NGX_DONE) {
+        return 0;
+    }
+
     bytes = 0;
 
     /*
@@ -387,7 +448,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 
         n = SSL_read(c->ssl->connection, buf, size);
 
-        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); 
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n);
 
         if (n > 0) {
             bytes += n;
@@ -399,10 +460,13 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 
             if (bytes) {
                 return bytes;
+            }
 
-            } else {
-                return c->ssl->last;
+            if (c->ssl->last == NGX_DONE) {
+                return 0;
             }
+
+            return c->ssl->last;
         }
 
         size -= n;
@@ -454,7 +518,7 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
     if (sslerr == SSL_ERROR_WANT_WRITE) {
 
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                      "client started SSL renegotiation");
+                      "peer started SSL renegotiation");
 
         c->write->ready = 0;
 
@@ -478,9 +542,9 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
     c->ssl->no_send_shutdown = 1;
 
     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
-        ngx_log_error(NGX_LOG_INFO, c->log, err, "client closed connection");
-
-        return NGX_ERROR;
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                       "peer shutdown SSL cleanly");
+        return NGX_DONE;
     }
 
     ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed");
@@ -516,28 +580,38 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
     ssize_t      send, size;
     ngx_buf_t   *buf;
 
-    buf = c->ssl->buf;
-
-    if (in && in->next == NULL && !c->buffered && !c->ssl->buffer) {
+    if (!c->ssl->buffer || (in && in->next == NULL && !c->buffered)) {
 
         /*
-         * we avoid a buffer copy if the incoming buf is a single,
-         * our buffer is empty, and we do not need to buffer the output
+         * we avoid a buffer copy if
+         *     we do not need to buffer the output
+         *     or the incoming buf is a single and our buffer is empty
          */
 
-        n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos);
+        while (in) {
+            if (ngx_buf_special(in->buf)) {
+                in = in->next;
+                continue;
+            }
 
-        if (n == NGX_ERROR) {
-            return NGX_CHAIN_ERROR;
-        }
+            n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos);
+
+            if (n == NGX_ERROR) {
+                return NGX_CHAIN_ERROR;
+            }
 
-        if (n == NGX_AGAIN) {
-            c->buffered = 1;
-            return in;
+            if (n == NGX_AGAIN) {
+                c->buffered = 1;
+                return in;
+            }
+
+            in->buf->pos += n;
+
+            if (in->buf->pos == in->buf->last) {
+                in = in->next;
+            }
         }
 
-        in->buf->pos += n;
-
         return in;
     }
 
@@ -549,6 +623,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
     }
 
 
+    buf = c->ssl->buf;
     send = 0;
     flush = (in == NULL) ? 1 : 0;
 
@@ -576,7 +651,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
              */
 
             if (send + size > limit) {
-                size = limit - send;
+                size = (ssize_t) (limit - send);
                 flush = 1;
             }
 
@@ -588,6 +663,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
             buf->last += size;
 
             in->buf->pos += size;
+
             if (in->buf->pos == in->buf->last) {
                 in = in->next;
             }
@@ -678,7 +754,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
     if (sslerr == SSL_ERROR_WANT_READ) {
 
         ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                      "client started SSL renegotiation");
+                      "peer started SSL renegotiation");
 
         c->read->ready = 0;
 
@@ -725,7 +801,7 @@ ngx_ssl_shutdown(ngx_connection_t *c)
     int         n, sslerr, mode;
     ngx_uint_t  again;
 
-    if (c->read->timedout) {
+    if (c->timedout) {
         mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
 
     } else {
@@ -752,7 +828,7 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
 
-        if (n == 1 || (n == 0 && c->read->timedout)) {
+        if (n == 1 || (n == 0 && c->timedout)) {
             SSL_free(c->ssl->connection);
             c->ssl = NULL;
 
@@ -778,6 +854,8 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
         ngx_add_timer(c->read, 30000);
 
+        c->read->handler = ngx_ssl_shutdown_handler;
+
         if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
             return NGX_ERROR;
         }
@@ -787,6 +865,8 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
     if (sslerr == SSL_ERROR_WANT_WRITE) {
 
+        c->write->handler = ngx_ssl_shutdown_handler;
+
         if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
             return NGX_ERROR;
         }
@@ -804,6 +884,29 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
 
 static void
+ngx_ssl_shutdown_handler(ngx_event_t *ev)
+{
+    ngx_connection_t           *c;
+    ngx_connection_handler_pt   handler;
+
+    c = ev->data;
+    handler = c->ssl->handler;
+
+    if (ev->timedout) {
+        c->timedout = 1;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "SSL shutdown handler");
+
+    if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
+        return;
+    }
+
+    handler(c);
+}
+
+
+static void
 ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
     char *text)
 {
@@ -842,7 +945,7 @@ ngx_ssl_connection_error(ngx_connection_
 
 void
 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
-{   
+{
     u_long   n;
     va_list  args;
     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
@@ -887,18 +990,18 @@ static void *
 ngx_openssl_create_conf(ngx_cycle_t *cycle)
 {
     ngx_openssl_conf_t  *oscf;
-    
+
     oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
     if (oscf == NULL) {
         return NGX_CONF_ERROR;
     }
-    
+
     /*
      * set by ngx_pcalloc():
-     * 
+     *
      *     oscf->engine.len = 0;
      *     oscf->engine.data = NULL;
-     */    
+     */
 
     return oscf;
 }
@@ -915,7 +1018,7 @@ ngx_openssl_init_conf(ngx_cycle_t *cycle
     if (oscf->engine.len == 0) {
         return NGX_CONF_OK;
     }
-    
+
     engine = ENGINE_by_id((const char *) oscf->engine.data);
 
     if (engine == NULL) {