]> granicus.if.org Git - apache/blobdiff - modules/http2/h2_filter.c
correct copyright/license headers
[apache] / modules / http2 / h2_filter.c
index a4ef20d7e905a7cc8d8e42ee534d9bef16b61818..23cfe68832b03706bca56ce32b1e6d2079d56e3b 100644 (file)
@@ -1,3 +1,19 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
 #define UNSET       -1
 #define H2MIN(x,y) ((x) < (y) ? (x) : (y))
 
-static apr_status_t consume_brigade(h2_filter_cin *cin, 
-                                    apr_bucket_brigade *bb, 
-                                    apr_read_type_e block)
+static apr_status_t recv_RAW_DATA(conn_rec *c, h2_filter_cin *cin, 
+                                  apr_bucket *b, apr_read_type_e block)
 {
+    h2_session *session = cin->session;
     apr_status_t status = APR_SUCCESS;
-    apr_size_t readlen = 0;
+    apr_size_t len;
+    const char *data;
+    ssize_t n;
     
-    while (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) {
+    status = apr_bucket_read(b, &data, &len, block);
+    
+    while (status == APR_SUCCESS && len > 0) {
+        n = nghttp2_session_mem_recv(session->ngh2, (const uint8_t *)data, len);
         
-        apr_bucket* bucket = APR_BRIGADE_FIRST(bb);
-        if (APR_BUCKET_IS_METADATA(bucket)) {
-            /* we do nothing regarding any meta here */
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
+                      H2_SSSN_MSG(session, "fed %ld bytes to nghttp2, %ld read"),
+                      (long)len, (long)n);
+        if (n < 0) {
+            if (nghttp2_is_fatal((int)n)) {
+                h2_session_event(session, H2_SESSION_EV_PROTO_ERROR, 
+                                 (int)n, nghttp2_strerror((int)n));
+                status = APR_EGENERAL;
+            }
         }
         else {
-            const char *bucket_data = NULL;
-            apr_size_t bucket_length = 0;
-            status = apr_bucket_read(bucket, &bucket_data,
-                                     &bucket_length, block);
-            
-            if (status == APR_SUCCESS && bucket_length > 0) {
-                apr_size_t consumed = 0;
-
-                status = cin->cb(cin->cb_ctx, bucket_data, bucket_length, &consumed);
-                if (status == APR_SUCCESS && bucket_length > consumed) {
-                    /* We have data left in the bucket. Split it. */
-                    status = apr_bucket_split(bucket, consumed);
-                }
-                readlen += consumed;
-                cin->start_read = apr_time_now();
+            session->io.bytes_read += n;
+            if (len <= n) {
+                break;
             }
+            len -= n;
+            data += n;
+        }
+    }
+    
+    return status;
+}
+
+static apr_status_t recv_RAW_brigade(conn_rec *c, h2_filter_cin *cin, 
+                                     apr_bucket_brigade *bb, 
+                                     apr_read_type_e block)
+{
+    apr_status_t status = APR_SUCCESS;
+    apr_bucket* b;
+    int consumed = 0;
+    
+    h2_util_bb_log(c, c->id, APLOG_TRACE2, "RAW_in", bb);
+    while (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) {
+        b = APR_BRIGADE_FIRST(bb);
+
+        if (APR_BUCKET_IS_METADATA(b)) {
+            /* nop */
+        }
+        else {
+            status = recv_RAW_DATA(c, cin, b, block);
         }
-        apr_bucket_delete(bucket);
+        consumed = 1;
+        apr_bucket_delete(b);
     }
     
-    if (readlen == 0 && status == APR_SUCCESS && block == APR_NONBLOCK_READ) {
+    if (!consumed && status == APR_SUCCESS && block == APR_NONBLOCK_READ) {
         return APR_EAGAIN;
     }
     return status;
 }
 
-h2_filter_cin *h2_filter_cin_create(apr_pool_t *p, h2_filter_cin_cb *cb, void *ctx)
+h2_filter_cin *h2_filter_cin_create(h2_session *session)
 {
     h2_filter_cin *cin;
     
-    cin = apr_pcalloc(p, sizeof(*cin));
-    cin->pool      = p;
-    cin->cb        = cb;
-    cin->cb_ctx    = ctx;
-    cin->start_read = UNSET;
+    cin = apr_pcalloc(session->pool, sizeof(*cin));
+    if (!cin) {
+        return NULL;
+    }
+    cin->session = session;
     return cin;
 }
 
@@ -110,11 +151,14 @@ apr_status_t h2_filter_core_input(ap_filter_t* f,
     h2_filter_cin *cin = f->ctx;
     apr_status_t status = APR_SUCCESS;
     apr_interval_time_t saved_timeout = UNSET;
+    const int trace1 = APLOGctrace1(f->c);
     
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
-                  "core_input(%ld): read, %s, mode=%d, readbytes=%ld", 
-                  (long)f->c->id, (block == APR_BLOCK_READ)? "BLOCK_READ" : "NONBLOCK_READ", 
-                  mode, (long)readbytes);
+    if (trace1) {
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
+                      "h2_session(%ld): read, %s, mode=%d, readbytes=%ld", 
+                      (long)f->c->id, (block == APR_BLOCK_READ)? 
+                      "BLOCK_READ" : "NONBLOCK_READ", mode, (long)readbytes);
+    }
     
     if (mode == AP_MODE_INIT || mode == AP_MODE_SPECULATIVE) {
         return ap_get_brigade(f->next, brigade, mode, block, readbytes);
@@ -125,20 +169,16 @@ apr_status_t h2_filter_core_input(ap_filter_t* f,
     }
     
     if (!cin->bb) {
-        cin->bb = apr_brigade_create(cin->pool, f->c->bucket_alloc);
+        cin->bb = apr_brigade_create(cin->session->pool, f->c->bucket_alloc);
     }
 
     if (!cin->socket) {
         cin->socket = ap_get_conn_socket(f->c);
     }
     
-    cin->start_read = apr_time_now();
     if (APR_BRIGADE_EMPTY(cin->bb)) {
         /* We only do a blocking read when we have no streams to process. So,
          * in httpd scoreboard lingo, we are in a KEEPALIVE connection state.
-         * When reading non-blocking, we do have streams to process and update
-         * child with NULL request. That way, any current request information
-         * in the scoreboard is preserved.
          */
         if (block == APR_BLOCK_READ) {
             if (cin->timeout > 0) {
@@ -155,17 +195,19 @@ apr_status_t h2_filter_core_input(ap_filter_t* f,
     
     switch (status) {
         case APR_SUCCESS:
-            status = consume_brigade(cin, cin->bb, block);
+            status = recv_RAW_brigade(f->c, cin, cin->bb, block);
             break;
         case APR_EOF:
         case APR_EAGAIN:
         case APR_TIMEUP:
-            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
-                          "core_input(%ld): read", (long)f->c->id);
+            if (trace1) {
+                ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
+                              "h2_session(%ld): read", f->c->id);
+            }
             break;
         default:
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, f->c, APLOGNO(03046)
-                          "h2_conn_io: error reading");
+                          "h2_session(%ld): error reading", f->c->id);
             break;
     }
     return status;