]> granicus.if.org Git - apache/commitdiff
no GOAWAYs on connection failures, sending last received stream id back in GOAWAY...
authorStefan Eissing <icing@apache.org>
Mon, 21 Sep 2015 10:59:50 +0000 (10:59 +0000)
committerStefan Eissing <icing@apache.org>
Mon, 21 Sep 2015 10:59:50 +0000 (10:59 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1704262 13f79535-47bb-0310-9956-ffa450edef68

modules/http2/h2_conn.c
modules/http2/h2_session.c
modules/http2/h2_session.h
modules/http2/h2_stream.c
modules/http2/h2_stream.h

index 38e5c11a2836e6e9c3954edea704aa396cda6986..8bffbc42693cad31e50ff0b3b86e15046c9922da 100644 (file)
@@ -288,24 +288,24 @@ apr_status_t h2_session_process(h2_session *session)
                                   || session->frames_received <= 1)?
                                  APR_BLOCK_READ : APR_NONBLOCK_READ);
         switch (status) {
-            case APR_SUCCESS:
-                /* successful read, reset our idle timers */
+            case APR_SUCCESS:       /* successful read, reset our idle timers */
                 have_read = 1;
                 wait_micros = 0;
                 break;
-            case APR_EAGAIN:
+            case APR_EAGAIN:              /* non-blocking read, nothing there */
                 break;
-            case APR_EBADF:
+            case APR_EBADF:               /* connection is not there any more */
             case APR_EOF:
             case APR_ECONNABORTED:
             case APR_ECONNRESET:
+            case APR_TIMEUP:                       /* blocked read, timed out */
                 ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
                               "h2_session(%ld): reading",
                               session->id);
                 h2_session_abort(session, status, 0);
                 break;
             default:
-                ap_log_cerror( APLOG_MARK, APLOG_WARNING, status, session->c,
+                ap_log_cerror( APLOG_MARK, APLOG_INFO, status, session->c,
                               APLOGNO(02950) 
                               "h2_session(%ld): error reading, terminating",
                               session->id);
index 8c8bced32a4210065ee1b0837de97dba98b0a4d8..c3456a0654da6254ae50e3e3e9787d20238f4c1b 100644 (file)
@@ -64,6 +64,9 @@ static int stream_open(h2_session *session, int stream_id)
     stream = h2_mplx_open_io(session->mplx, stream_id);
     if (stream) {
         h2_stream_set_add(session->streams, stream);
+        if (stream->id > session->max_stream_received) {
+            session->max_stream_received = stream->id;
+        }
         
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_session: stream(%ld-%d): opened",
@@ -223,10 +226,25 @@ static int on_frame_not_send_cb(nghttp2_session *ngh2,
     return 0;
 }
 
-static apr_status_t stream_destroy(h2_session *session, h2_stream *stream) 
+static apr_status_t stream_destroy(h2_session *session, 
+                                   h2_stream *stream,
+                                   uint32_t error_code) 
 {
-    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
-                  "h2_stream(%ld-%d): closing", session->id, (int)stream->id);
+    if (!error_code) {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                      "h2_stream(%ld-%d): handled, closing", 
+                      session->id, (int)stream->id);
+        if (stream->id > session->max_stream_handled) {
+            session->max_stream_handled = stream->id;
+        }
+    }
+    else {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
+                      "h2_stream(%ld-%d): closing with err=%d %s", 
+                      session->id, (int)stream->id, (int)error_code,
+                      nghttp2_strerror(error_code));
+    }
+    
     h2_stream_set_remove(session->streams, stream);
     return h2_mplx_cleanup_stream(session->mplx, stream);
 }
@@ -243,7 +261,7 @@ static int on_stream_close_cb(nghttp2_session *ngh2, int32_t stream_id,
     }
     stream = h2_stream_set_get(session->streams, stream_id);
     if (stream) {
-        stream_destroy(session, stream);
+        stream_destroy(session, stream, error_code);
     }
     
     if (error_code) {
@@ -655,50 +673,43 @@ void h2_session_destroy(h2_session *session)
     }
 }
 
-apr_status_t h2_session_goaway(h2_session *session, apr_status_t reason)
-{
-    apr_status_t status = APR_SUCCESS;
-    int rv;
-    AP_DEBUG_ASSERT(session);
-    if (session->aborted) {
-        return APR_EINVAL;
-    }
-    
-    rv = 0;
-    if (reason == APR_SUCCESS) {
-        rv = nghttp2_submit_shutdown_notice(session->ngh2);
-    }
-    else {
-        int err = 0;
-        int last_id = nghttp2_session_get_last_proc_stream_id(session->ngh2);
-        rv = nghttp2_submit_goaway(session->ngh2, last_id,
-                                   NGHTTP2_FLAG_NONE, err, NULL, 0);
-    }
-    if (rv != 0) {
-        status = APR_EGENERAL;
-        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
-                    APLOGNO(02930) "session(%ld): submit goaway: %s",
-                      session->id, nghttp2_strerror(rv));
-    }
-    return status;
-}
-
 static apr_status_t h2_session_abort_int(h2_session *session, int reason)
 {
     AP_DEBUG_ASSERT(session);
     if (!session->aborted) {
         session->aborted = 1;
         if (session->ngh2) {
-            if (reason) {
-                ap_log_cerror(APLOG_MARK, (reason == NGHTTP2_ERR_EOF)?
-                              APLOG_DEBUG : APLOG_INFO, 0, session->c,
+            
+            if (!reason) {
+                nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE, 
+                                      session->max_stream_received, 
+                                      reason, NULL, 0);
+                nghttp2_session_send(session->ngh2);
+                h2_conn_io_flush(&session->io);
+            }
+            else {
+                const char *err = nghttp2_strerror(reason);
+                
+                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                               "session(%ld): aborting session, reason=%d %s",
-                              session->id, reason, nghttp2_strerror(reason));
+                              session->id, reason, err);
+                
+                if (NGHTTP2_ERR_EOF == reason) {
+                    /* This is our way of indication that the connection is
+                     * gone. No use to send any GOAWAY frames. */
+                    nghttp2_session_terminate_session(session->ngh2, reason);
+                }
+                else {
+                    /* The connection might still be there and we shut down
+                     * with GOAWAY and reason information. */
+                     nghttp2_submit_goaway(session->ngh2, NGHTTP2_FLAG_NONE, 
+                                           session->max_stream_received, 
+                                           reason, (const uint8_t *)err, 
+                                           strlen(err));
+                     nghttp2_session_send(session->ngh2);
+                     h2_conn_io_flush(&session->io);
+                }
             }
-            nghttp2_session_terminate_session(session->ngh2, reason);
-            nghttp2_submit_goaway(session->ngh2, 0, 0, reason, NULL, 0);
-            nghttp2_session_send(session->ngh2);
-            h2_conn_io_flush(&session->io);
         }
         h2_mplx_abort(session->mplx);
     }
@@ -714,10 +725,12 @@ apr_status_t h2_session_abort(h2_session *session, apr_status_t reason, int rv)
             case APR_ENOMEM:
                 rv = NGHTTP2_ERR_NOMEM;
                 break;
-            case APR_EOF:
-                rv = 0;
+            case APR_SUCCESS:                            /* all fine, just... */
+            case APR_EOF:                         /* client closed its end... */
+            case APR_TIMEUP:                          /* got bored waiting... */
+                rv = 0;                            /* ...gracefully shut down */
                 break;
-            case APR_EBADF:
+            case APR_EBADF:        /* connection unusable, terminate silently */
             case APR_ECONNABORTED:
                 rv = NGHTTP2_ERR_EOF;
                 break;
@@ -1006,7 +1019,7 @@ apr_status_t h2_session_read(h2_session *session, apr_read_type_e block)
 apr_status_t h2_session_close(h2_session *session)
 {
     AP_DEBUG_ASSERT(session);
-    return h2_conn_io_flush(&session->io);
+    return session->aborted? APR_SUCCESS : h2_conn_io_flush(&session->io);
 }
 
 /* The session wants to send more DATA for the given stream.
index 77dd440a55e21e4263217e3083cbeab60551b977..12768a90fb374e6e157a112fcf4889be98b650bb 100644 (file)
@@ -71,44 +71,70 @@ struct h2_session {
     
     struct h2_stream_set *streams;  /* streams handled by this session */
     
+    int max_stream_received;        /* highest stream id created */
+    int max_stream_handled;         /* highest stream id handled successfully */
+    
     struct nghttp2_session *ngh2;   /* the nghttp2 session (internal use) */
     struct h2_workers *workers;     /* for executing stream tasks */
 };
 
 
-/* Create a new h2_session for the given connection (mode 'h2').
+/**
+ * Create a new h2_session for the given connection.
  * The session will apply the configured parameter.
+ * @param c       the connection to work on
+ * @param cfg     the module config to apply
+ * @param workers the worker pool to use
+ * @return the created session
  */
 h2_session *h2_session_create(conn_rec *c, struct h2_config *cfg, 
                               struct h2_workers *workers);
 
-/* Create a new h2_session for the given request (mode 'h2c').
+/**
+ * Create a new h2_session for the given request.
  * The session will apply the configured parameter.
+ * @param r       the request that was upgraded
+ * @param cfg     the module config to apply
+ * @param workers the worker pool to use
+ * @return the created session
  */
 h2_session *h2_session_rcreate(request_rec *r, struct h2_config *cfg,
                                struct h2_workers *workers);
 
-/* Destroy the session and all object it still contains. This will not
- * destroy h2_task instances that not finished yet. */
+/**
+ * Destroy the session and all objects it still contains. This will not
+ * destroy h2_task instances that have not finished yet. 
+ * @param session the session to destroy
+ */
 void h2_session_destroy(h2_session *session);
 
-/* Called once at start of session. Performs initial client thingies. */
+/**
+ * Called once at start of session. 
+ * Sets up the session and sends the initial SETTINGS frame.
+ * @param session the session to start
+ * @param rv error codes in libnghttp2 lingo are returned here
+ * @return APR_SUCCESS if all went well
+ */
 apr_status_t h2_session_start(h2_session *session, int *rv);
 
-/* Return != 0 iff session is finished and connection can be closed.
+/**
+ * Determine if session is finished.
+ * @return != 0 iff session is finished and connection can be closed.
  */
 int h2_session_is_done(h2_session *session);
 
-/* Called when the session will shutdown after all open streams
- * are handled. New streams will no longer be accepted. 
- * Call with reason APR_SUCCESS to initiate a graceful shutdown. */
-apr_status_t h2_session_goaway(h2_session *session, apr_status_t reason);
-
-/* Called when an error occured and the session needs to shut down.
- * Status indicates the reason of the error. */
+/**
+ * Called when an error occured and the session needs to shut down.
+ * @param session the session to shut down
+ * @param reason  the apache status that caused the shutdown
+ * @param rv      the nghttp2 reason for shutdown, set to 0 if you have none.
+ *
+ */
 apr_status_t h2_session_abort(h2_session *session, apr_status_t reason, int rv);
 
-/* Called before a session gets destroyed, might flush output etc. */
+/**
+ * Called before a session gets destroyed, might flush output etc. 
+ */
 apr_status_t h2_session_close(h2_session *session);
 
 /* Read more data from the client connection. Used normally with blocking
index 08b8f5a3f8463f57239dfbc4f89d0f62a3b1696d..52781d8474fec50392e95dbf3417dc5eaf722cf1 100644 (file)
@@ -61,7 +61,7 @@ h2_stream *h2_stream_create(int id, apr_pool_t *pool, struct h2_mplx *m)
     return stream;
 }
 
-void h2_stream_cleanup(h2_stream *stream)
+static void h2_stream_cleanup(h2_stream *stream)
 {
     if (stream->request) {
         h2_request_destroy(stream->request);
index f6bd71a5f84ce8773e04cbfa7a7a5637f31f8c2b..0608f2f34006fcfeb28f2624637512b28ce523b4 100644 (file)
@@ -72,7 +72,6 @@ struct h2_stream {
 h2_stream *h2_stream_create(int id, apr_pool_t *pool, struct h2_mplx *m);
 
 apr_status_t h2_stream_destroy(h2_stream *stream);
-void h2_stream_cleanup(h2_stream *stream);
 
 apr_pool_t *h2_stream_detach_pool(h2_stream *stream);
 void h2_stream_attach_pool(h2_stream *stream, apr_pool_t *pool);