serf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhuij...@apache.org
Subject svn commit: r1711737 - in /serf/trunk/protocols: http2_protocol.c http2_stream.c
Date Sun, 01 Nov 2015 12:18:54 GMT
Author: rhuijben
Date: Sun Nov  1 12:18:54 2015
New Revision: 1711737

URL: http://svn.apache.org/viewvc?rev=1711737&view=rev
Log:
In the http2 stream handler: hook up the standard request response
handlers.

This makes the serf_get program fully capable of sending out http/2 requests,
that don't contain a request body.

Note that for testing you need either OpenSSL 1.0.2+ or a server capable of
h2direct.

* protocols/http2_protocol.c
  (http2_process): Fix some stream status checks. Put more likely values
     first.
  (http2_protocol_write): Avoid duplicated code. Update request numbers.

* protocols/http2_stream.c
  (serf_http2__stream_setup_request): Set status to halfclosed, because we
    sent HTTP2_FLAG_END_STREAM.
  (stream_setup_response): New function.
  (serf_http2__stream_handle_hpack,
   serf_http2__stream_handle_data): Use stream_setup_response to setup response.

  (serf_http2__stream_processor): Let request read the data until it is no
    longer interested.

Modified:
    serf/trunk/protocols/http2_protocol.c
    serf/trunk/protocols/http2_stream.c

Modified: serf/trunk/protocols/http2_protocol.c
URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1711737&r1=1711736&r2=1711737&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.c (original)
+++ serf/trunk/protocols/http2_protocol.c Sun Nov  1 12:18:54 2015
@@ -961,17 +961,17 @@ http2_process(serf_http2_protocol_t *h2)
                           }
                         break;
                       case HTTP2_FRAME_TYPE_HEADERS:
-                        if (stream->status != H2S_IDLE
-                            && stream->status != H2S_RESERVED_LOCAL
-                            && stream->status != H2S_OPEN
-                            && stream->status != H2S_HALFCLOSED_REMOTE)
+                        if (stream->status != H2S_OPEN
+                            && stream->status != H2S_HALFCLOSED_LOCAL
+                            && stream->status != H2S_IDLE
+                            && stream->status != H2S_RESERVED_REMOTE)
                           {
                             reset_reason = SERF_ERROR_HTTP2_STREAM_CLOSED;
                           }
                         break;
                       case HTTP2_FRAME_TYPE_PUSH_PROMISE:
                         if (stream->status != H2S_OPEN
-                            && stream->status != H2S_HALFCLOSED_REMOTE)
+                            && stream->status != H2S_HALFCLOSED_LOCAL)
                           {
                             reset_reason = SERF_ERROR_HTTP2_STREAM_CLOSED;
                           }
@@ -1352,18 +1352,16 @@ http2_protocol_write(serf_connection_t *
 
   if (request)
     {
-      /* Yuck.. there must be easier ways to do this, but I don't
-          want to change outgoing.c all the time just yet. */
       conn->unwritten_reqs = request->next;
       if (conn->unwritten_reqs_tail == request)
         conn->unwritten_reqs = conn->unwritten_reqs_tail = NULL;
 
       request->next = NULL;
 
-      if (conn->written_reqs_tail)
-        conn->written_reqs_tail->next = request;
-      else
-        conn->written_reqs = conn->written_reqs_tail = request;
+      serf__link_requests(&conn->written_reqs, &conn->written_reqs_tail,
+                          request);
+      conn->nr_of_written_reqs++;
+      conn->nr_of_written_reqs--;
 
       status = setup_for_http2(ctx, request);
       if (status)

Modified: serf/trunk/protocols/http2_stream.c
URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_stream.c?rev=1711737&r1=1711736&r2=1711737&view=diff
==============================================================================
--- serf/trunk/protocols/http2_stream.c (original)
+++ serf/trunk/protocols/http2_stream.c Sun Nov  1 12:18:54 2015
@@ -126,7 +126,7 @@ serf_http2__stream_setup_request(serf_ht
 
   serf_http2__enqueue_frame(stream->h2, hpack, TRUE);
 
-  stream->status = H2S_OPEN; /* Headers sent */
+  stream->status = H2S_HALFCLOSED_LOCAL; /* Headers sent */
 
   return APR_SUCCESS;
 }
@@ -165,6 +165,34 @@ stream_response_eof(void *baton,
     }
 }
 
+void
+stream_setup_response(serf_http2_stream_t *stream,
+                      serf_config_t *config)
+{
+  serf_request_t *request;
+  serf_bucket_t *agg;
+
+  agg = serf_bucket_aggregate_create(stream->alloc);
+  serf_bucket_aggregate_hold_open(agg, stream_response_eof, stream);
+
+  serf_bucket_set_config(agg, config);
+
+  request = stream->data->request;
+
+  if (!request)
+    return;
+
+  if (! request->resp_bkt)
+    {
+      apr_pool_t *scratch_pool = request->respool; /* ### Pass scratch pool */
+
+      request->resp_bkt = request->acceptor(request, agg, request->acceptor_baton,
+                                            scratch_pool);
+    }
+
+  stream->data->response_agg = agg;
+}
+
 serf_bucket_t *
 serf_http2__stream_handle_hpack(serf_http2_stream_t *stream,
                                 serf_bucket_t *bucket,
@@ -176,12 +204,7 @@ serf_http2__stream_handle_hpack(serf_htt
                                 serf_bucket_alloc_t *allocator)
 {
   if (!stream->data->response_agg)
-    {
-      stream->data->response_agg = serf_bucket_aggregate_create(stream->alloc);
-      serf_bucket_aggregate_hold_open(stream->data->response_agg,
-                                      stream_response_eof, stream);
-      serf_bucket_set_config(stream->data->response_agg, config);
-    }
+    stream_setup_response(stream, config);
 
   bucket = serf__bucket_hpack_decode_create(bucket, NULL, NULL, max_entry_size,
                                             hpack_tbl, allocator);
@@ -208,13 +231,7 @@ serf_http2__stream_handle_data(serf_http
                                serf_bucket_alloc_t *allocator)
 {
   if (!stream->data->response_agg)
-    {
-      stream->data->response_agg = serf_bucket_aggregate_create(stream->alloc);
-      serf_bucket_aggregate_hold_open(stream->data->response_agg,
-                                      stream_response_eof, stream);
-
-      serf_bucket_set_config(stream->data->response_agg, config);
-    }
+    stream_setup_response(stream, config);
 
   serf_bucket_aggregate_append(stream->data->response_agg, bucket);
 
@@ -236,9 +253,76 @@ serf_http2__stream_processor(void *baton
 {
   serf_http2_stream_t *stream = baton;
   apr_status_t status = APR_SUCCESS;
+  serf_request_t *request = stream->data->request;
 
-  if (!stream->data->response_agg)
-    return APR_EAGAIN;
+  SERF_H2_assert(stream->data->response_agg != NULL);
+
+  if (request)
+    {
+      SERF_H2_assert(request->resp_bkt != NULL);
+
+      status = stream->data->request->handler(request, request->resp_bkt,
+                                              request->handler_baton,
+                                              request->respool);
+
+      if (! APR_STATUS_IS_EOF(status)
+          && !SERF_BUCKET_READ_ERROR(status))
+        return status;
+
+      /* Ok, the request thinks is done, let's handle the bookkeeping,
+         to remove it from the outstanding requests */
+      {
+        serf_connection_t *conn = serf_request_get_conn(request);
+        serf_request_t **rq = &conn->written_reqs;
+        serf_request_t *last = NULL;
+
+        while (*rq && (*rq != request))
+          {
+            last = *rq;
+            rq = &last->next;
+          }
+
+        if (*rq)
+          {
+            (*rq) = request->next;
+
+            if (conn->written_reqs_tail == request)
+              conn->written_reqs_tail = last;
+
+            conn->nr_of_written_reqs--;
+          }
+
+        serf__destroy_request(request);
+        stream->data->request = NULL;
+      }
+
+      if (SERF_BUCKET_READ_ERROR(status))
+        {
+          if (stream->status != H2S_CLOSED)
+            {
+              /* Tell the other side that we are no longer interested
+                 to receive more data */
+              serf_http2__stream_reset(stream, status, TRUE);
+            }
+
+          return status;
+        }
+
+      SERF_H2_assert(APR_STATUS_IS_EOF(status));
+
+      /* Even though the request reported that it is done, we might not
+         have read all the data that we should (*cough* padding *cough*),
+         or perhaps an invalid 'Content-Length' value; maybe both.
+
+         This may even handle not-interested - return EOF cases, but that
+         would have broken the pipeline for HTTP/1.1.
+         */
+
+      /* ### For now, fall through and eat whatever is left.
+             Usually this is 0 bytes */
+
+      status = APR_SUCCESS;
+    }
 
   /* ### TODO: Delegate to request */
   while (!status)
@@ -251,9 +335,11 @@ serf_http2__stream_processor(void *baton
 
       if (!SERF_BUCKET_READ_ERROR(status))
         {
+#if 0
           if (len > 0)
           {
-            char *printable = serf_bstrmemdup(bucket->allocator, data, len);
+            serf_bucket_alloc_t *alloc = stream->data->response_agg->allocator;
+            char *printable = serf_bstrmemdup(alloc, data, len);
             char *c;
 
             for (c = printable; *c; c++)
@@ -269,10 +355,21 @@ serf_http2__stream_processor(void *baton
             fputs(printable, stdout);
 #endif
 
-            serf_bucket_mem_free(bucket->allocator, printable);
+            serf_bucket_mem_free(alloc, printable);
           }
+#endif
         }
     }
 
+  if (APR_STATUS_IS_EOF(status)
+      && stream->status == H2S_CLOSED || stream->status == H2S_HALFCLOSED_REMOTE)
+    {
+      /* If there was a request, it is already gone, so we can now safely
+         destroy our aggregate which may include everything upto the http2
+         frames */
+      serf_bucket_destroy(stream->data->response_agg);
+      stream->data->response_agg = NULL;
+    }
+
   return status;
 }



Mime
View raw message