]> git.kaiwu.me - nginx.git/commitdiff
SSL: do not treat SSL handshake as request.
authorValentin Bartenev <vbart@nginx.com>
Wed, 27 Feb 2013 17:21:21 +0000 (17:21 +0000)
committerValentin Bartenev <vbart@nginx.com>
Wed, 27 Feb 2013 17:21:21 +0000 (17:21 +0000)
The request object will not be created until SSL handshake is complete.
This simplifies adding another connection handler that does not need
request object right after handshake (e.g., SPDY).

There are also a few more intentional effects:

 - the "client_header_buffer_size" directive will be taken from the
   server configuration that was negotiated by SNI;

 - SSL handshake errors and timeouts are not logged into access log
   as bad requests;

 - ngx_ssl_create_connection() is not called until the first byte of
   ClientHello message was received.  This also decreases memory
   consumption if plain HTTP request is sent to SSL socket.

src/http/ngx_http_request.c
src/http/ngx_http_request.h

index 2c9e878b051fa8a3040dd613b6235619ad209410..c96c2633b40b7f91046ed9262d18c97b21918e55 100644 (file)
@@ -316,6 +316,31 @@ ngx_http_init_connection(ngx_connection_t *c)
     rev->handler = ngx_http_init_request;
     c->write->handler = ngx_http_empty_handler;
 
+#if (NGX_HTTP_SSL)
+    {
+    ngx_http_ssl_srv_conf_t  *sscf;
+
+    sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
+
+    if (sscf->enable || hc->addr_conf->ssl) {
+
+        c->log->action = "SSL handshaking";
+
+        if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) {
+            ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                          "no \"ssl_certificate\" is defined "
+                          "in server listening on SSL port");
+            ngx_http_close_connection(c);
+            return;
+        }
+
+        hc->ssl = 1;
+
+        rev->handler = ngx_http_ssl_handshake;
+    }
+    }
+#endif
+
     if (rev->ready) {
         /* the deferred accept(), rtsig, aio, iocp */
 
@@ -324,7 +349,7 @@ ngx_http_init_connection(ngx_connection_t *c)
             return;
         }
 
-        ngx_http_init_request(rev);
+        rev->handler(rev);
         return;
     }
 
@@ -395,45 +420,8 @@ ngx_http_init_request(ngx_event_t *rev)
     r->srv_conf = hc->conf_ctx->srv_conf;
     r->loc_conf = hc->conf_ctx->loc_conf;
 
-    rev->handler = ngx_http_process_request_line;
     r->read_event_handler = ngx_http_block_reading;
 
-#if (NGX_HTTP_SSL)
-
-    {
-    ngx_http_ssl_srv_conf_t  *sscf;
-
-    sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
-    if (sscf->enable || hc->addr_conf->ssl) {
-
-        if (c->ssl == NULL) {
-
-            c->log->action = "SSL handshaking";
-
-            if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) {
-                ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                              "no \"ssl_certificate\" is defined "
-                              "in server listening on SSL port");
-                ngx_http_close_connection(c);
-                return;
-            }
-
-            if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
-                != NGX_OK)
-            {
-                ngx_http_close_connection(c);
-                return;
-            }
-
-            rev->handler = ngx_http_ssl_handshake;
-        }
-
-        r->main_filter_need_in_memory = 1;
-    }
-    }
-
-#endif
-
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     ngx_http_set_connection_log(r->connection, clcf->error_log);
@@ -489,6 +477,12 @@ ngx_http_init_request(ngx_event_t *rev)
     c->single_connection = 1;
     c->destroyed = 0;
 
+#if (NGX_HTTP_SSL)
+    if (c->ssl) {
+        r->main_filter_need_in_memory = 1;
+    }
+#endif
+
     r->main = r;
     r->count = 1;
 
@@ -519,7 +513,8 @@ ngx_http_init_request(ngx_event_t *rev)
     (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
 #endif
 
-    rev->handler(rev);
+    rev->handler = ngx_http_process_request_line;
+    ngx_http_process_request_line(rev);
 }
 
 
@@ -528,37 +523,48 @@ ngx_http_init_request(ngx_event_t *rev)
 static void
 ngx_http_ssl_handshake(ngx_event_t *rev)
 {
-    u_char               buf[1];
-    ssize_t              n;
-    ngx_int_t            rc;
-    ngx_connection_t    *c;
-    ngx_http_request_t  *r;
+    u_char                    buf[1];
+    ssize_t                   n;
+    ngx_err_t                 err;
+    ngx_int_t                 rc;
+    ngx_connection_t         *c;
+    ngx_http_connection_t    *hc;
+    ngx_http_ssl_srv_conf_t  *sscf;
 
     c = rev->data;
-    r = c->data;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                    "http check ssl handshake");
 
     if (rev->timedout) {
         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
-        c->timedout = 1;
-        ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+        ngx_http_close_connection(c);
         return;
     }
 
     n = recv(c->fd, (char *) buf, 1, MSG_PEEK);
 
-    if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
+    err = ngx_socket_errno;
 
-        if (!rev->timer_set) {
-            ngx_add_timer(rev, c->listening->post_accept_timeout);
-        }
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %d", n);
 
-        if (ngx_handle_read_event(rev, 0) != NGX_OK) {
-            ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    if (n == -1) {
+        if (err == NGX_EAGAIN) {
+
+            if (!rev->timer_set) {
+                ngx_add_timer(rev, c->listening->post_accept_timeout);
+            }
+
+            if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+                ngx_http_close_connection(c);
+            }
+
+            return;
         }
 
+        ngx_connection_error(c, err, "recv() failed");
+        ngx_http_close_connection(c);
+
         return;
     }
 
@@ -567,6 +573,17 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                            "https ssl handshake: 0x%02Xd", buf[0]);
 
+            hc = c->data;
+            sscf = ngx_http_get_module_srv_conf(hc->conf_ctx,
+                                                ngx_http_ssl_module);
+
+            if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
+                != NGX_OK)
+            {
+                ngx_http_close_connection(c);
+                return;
+            }
+
             rc = ngx_ssl_handshake(c);
 
             if (rc == NGX_AGAIN) {
@@ -582,27 +599,26 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
             ngx_http_ssl_handshake_handler(c);
 
             return;
+        }
 
-        } else {
-            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
-                           "plain http");
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "plain http");
 
-            r->plain_http = 1;
-        }
-    }
+        c->log->action = "reading client request line";
 
-    c->log->action = "reading client request line";
+        rev->handler = ngx_http_init_request;
+        ngx_http_init_request(rev);
 
-    rev->handler = ngx_http_process_request_line;
-    ngx_http_process_request_line(rev);
+        return;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection");
+    ngx_http_close_connection(c);
 }
 
 
 static void
 ngx_http_ssl_handshake_handler(ngx_connection_t *c)
 {
-    ngx_http_request_t  *r;
-
     if (c->ssl->handshaked) {
 
         /*
@@ -617,19 +633,19 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
 
         c->log->action = "reading client request line";
 
-        c->read->handler = ngx_http_process_request_line;
+        c->read->handler = ngx_http_init_request;
         /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler;
 
-        ngx_http_process_request_line(c->read);
+        ngx_http_init_request(c->read);
 
         return;
     }
 
-    r = c->data;
-
-    ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
+    if (c->read->timedout) {
+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
+    }
 
-    return;
+    ngx_http_close_connection(c);
 }
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -640,7 +656,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
     ngx_str_t                  host;
     const char                *servername;
     ngx_connection_t          *c;
-    ngx_http_request_t        *r;
     ngx_http_connection_t     *hc;
     ngx_http_ssl_srv_conf_t   *sscf;
     ngx_http_core_loc_conf_t  *clcf;
@@ -663,15 +678,13 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
         return SSL_TLSEXT_ERR_NOACK;
     }
 
-    r = c->data;
-
     host.data = (u_char *) servername;
 
-    if (ngx_http_validate_host(&host, r->pool, 1) != NGX_OK) {
+    if (ngx_http_validate_host(&host, c->pool, 1) != NGX_OK) {
         return SSL_TLSEXT_ERR_NOACK;
     }
 
-    hc = r->http_connection;
+    hc = c->data;
 
     if (ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host,
                                      NULL, &cscf)
@@ -682,14 +695,11 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
 
     hc->conf_ctx = cscf->ctx;
 
-    r->srv_conf = cscf->ctx->srv_conf;
-    r->loc_conf = cscf->ctx->loc_conf;
-
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+    clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module);
 
     ngx_http_set_connection_log(c, clcf->error_log);
 
-    sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
+    sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
 
     if (sscf->ssl.ctx) {
         SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx);
@@ -1631,20 +1641,20 @@ ngx_http_process_request(ngx_http_request_t *r)
 
     c = r->connection;
 
-    if (r->plain_http) {
-        ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                      "client sent plain HTTP request to HTTPS port");
-        ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
-        return;
-    }
-
 #if (NGX_HTTP_SSL)
 
-    if (c->ssl) {
+    if (r->http_connection->ssl) {
         long                      rc;
         X509                     *cert;
         ngx_http_ssl_srv_conf_t  *sscf;
 
+        if (c->ssl == NULL) {
+            ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                          "client sent plain HTTP request to HTTPS port");
+            ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
+            return;
+        }
+
         sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
 
         if (sscf->verify) {
index a2df0c6f29e1e25ae81371df03d8158eb3e7b326..c4b6422c497ea70c0832166f0e1b1cb9dc06a622 100644 (file)
@@ -303,7 +303,8 @@ typedef struct {
     ngx_buf_t                       **free;
     ngx_int_t                         nfree;
 
-    ngx_uint_t                        pipeline;    /* unsigned  pipeline:1; */
+    unsigned                          pipeline:1;
+    unsigned                          ssl:1;
 } ngx_http_connection_t;
 
 
@@ -492,7 +493,6 @@ struct ngx_http_request_s {
 #endif
 
     unsigned                          pipeline:1;
-    unsigned                          plain_http:1;
     unsigned                          chunked:1;
     unsigned                          header_only:1;
     unsigned                          keepalive:1;