You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@serf.apache.org by rh...@apache.org on 2015/10/20 22:23:04 UTC
svn commit: r1709676 - in /serf/trunk/protocols: http2_protocol.c
http2_protocol.h
Author: rhuijben
Date: Tue Oct 20 20:23:04 2015
New Revision: 1709676
URL: http://svn.apache.org/viewvc?rev=1709676&view=rev
Log:
Checkpoint the current prototype of a http2 protocol implementation.
When used with a recent OpenSSL and a serf_get with '--http2' enabled
this version can successfully send HTTP/2 requests to http2 enabled
servers such as https://www.google.com and https://www.akamai.com
But that is about it... it just dumps the frame information when
using the debug mode.
* serf-dev/dev/protocols/http2_protocol.c
(header): Fix indentation.
(includes): Add protocols/http2_protocol.h.
(serf__http2_protocol_init): Schedule http2 preface and initial setting
frame.
(setup_for_http2): New function.
(http2_read): Properly handle the success result. Print out the debug
information from go-away frames if there is interesting data.
(Google sends parser errors as text there).
(http2_protocol_read): Handle the ssl implementation's stop_writing.
(http2_protocol_write): Write out data when possible.
* serf-dev/dev/protocols/http2_protocol.h
New private header, containing many HTTP2 specific constants.
Added:
serf/trunk/protocols/http2_protocol.h (with props)
Modified:
serf/trunk/protocols/http2_protocol.c
Modified: serf/trunk/protocols/http2_protocol.c
URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1709676&r1=1709675&r2=1709676&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.c (original)
+++ serf/trunk/protocols/http2_protocol.c Tue Oct 20 20:23:04 2015
@@ -1,22 +1,22 @@
/* ====================================================================
-* 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.
-* ====================================================================
-*/
+ * 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.
+ * ====================================================================
+ */
#include <apr_pools.h>
#include <apr_poll.h>
@@ -28,6 +28,7 @@
#include "serf_bucket_util.h"
#include "serf_private.h"
+#include "protocols/http2_protocol.h"
static apr_status_t
http2_protocol_read(serf_connection_t *conn);
@@ -71,6 +72,7 @@ void serf__http2_protocol_init(serf_conn
{
serf_http2_procotol_state_t *ctx;
apr_pool_t *protocol_pool;
+ serf_bucket_t *tmp;
apr_pool_create(&protocol_pool, conn->pool);
@@ -85,6 +87,64 @@ void serf__http2_protocol_init(serf_conn
conn->perform_hangup = http2_protocol_hangup;
conn->perform_teardown = http2_protocol_teardown;
conn->protocol_baton = ctx;
+
+ /* Disable HTTP/1.1 guessing that affects writability */
+ conn->probable_keepalive_limit = 0;
+ conn->max_outstanding_requests = 0;
+
+ /* Send the HTTP/2 Connection Preface */
+ tmp = SERF_BUCKET_SIMPLE_STRING("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n",
+ conn->allocator);
+ serf_bucket_aggregate_append(conn->ostream_tail, tmp);
+
+ /* And now a settings frame */
+ {
+ serf_bucket_t *no_settings;
+ apr_int32_t frame_id = 0;
+
+ no_settings = serf_bucket_simple_create("", 0, NULL, NULL, conn->allocator);
+ tmp = serf_bucket_http2_frame_create(no_settings, HTTP2_FRAME_TYPE_SETTINGS, 0,
+ &frame_id, NULL, NULL, /* Static id: 0*/
+ 16384 /* max_framesize */,
+ NULL, NULL, conn->allocator);
+
+ serf_bucket_aggregate_append(conn->ostream_tail, tmp);
+ }
+}
+
+/* Creates a HTTP/2 request from a serf request */
+static apr_status_t
+setup_for_http2(serf_request_t *request)
+{
+ apr_status_t status;
+ serf_bucket_t *rq;
+ serf_bucket_t *hpack;
+ serf_bucket_t *body;
+ static apr_int32_t NEXT_frame = 1;
+
+ apr_int32_t streamid = NEXT_frame;
+ NEXT_frame += 2;
+
+ rq = request->req_bkt;
+
+ status = serf__bucket_hpack_create_from_request(&hpack, NULL,
+ rq,
+ request->conn->host_info.scheme,
+ request->allocator);
+ if (status)
+ return status;
+
+ hpack = serf_bucket_http2_frame_create(hpack, HTTP2_FRAME_TYPE_HEADERS,
+ HTTP2_FLAG_END_STREAM
+ | HTTP2_FLAG_END_HEADERS,
+ &streamid, NULL, NULL,
+ HTTP2_DEFAULT_MAX_FRAMESIZE,
+ NULL, NULL, request->allocator);
+
+ serf_bucket_aggregate_append(request->conn->ostream_tail,
+ hpack);
+
+ return APR_SUCCESS;
}
static apr_status_t
@@ -93,10 +153,46 @@ http2_read(serf_connection_t *conn)
serf_http2_procotol_state_t *ctx = conn->protocol_baton;
apr_status_t status = APR_SUCCESS;
+
while (TRUE)
{
status = APR_SUCCESS;
+ {
+ serf_request_t *request = conn->unwritten_reqs;
+
+ if (request)
+ {
+ apr_status_t status;
+ serf_bucket_t *req_bkt;
+
+ /* 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;
+
+ if (!request->req_bkt
+ || !SERF_BUCKET_IS_REQUEST(request->req_bkt))
+ {
+ status = serf__setup_request(request);
+ if (status)
+ return status;
+ }
+
+ status = setup_for_http2(request);
+ if (status)
+ return status;
+ }
+ }
+
if (ctx->cur_frame)
{
const char *data;
@@ -137,6 +233,8 @@ http2_read(serf_connection_t *conn)
memcpy(&ctx->buffer[ctx->buffer_used], data, len);
ctx->buffer_used += len;
}
+ else
+ break;
if (APR_STATUS_IS_EOF(status))
{
@@ -144,20 +242,28 @@ http2_read(serf_connection_t *conn)
unsigned char frametype;
unsigned char flags;
- status = serf_bucket_http2_unframe_read_info(ctx->cur_frame,
- &streamid, &frametype,
- &flags);
+ serf_bucket_http2_unframe_read_info(ctx->cur_frame,
+ &streamid, &frametype,
+ &flags);
serf__log(LOGLVL_INFO, LOGCOMP_CONN, __FILE__, conn->config,
"Read 0x%02x http2 frame on stream 0x%x, flags=0x%x\n",
(int)frametype, (int)streamid, (int)flags);
+ if (frametype == HTTP2_FRAME_TYPE_GOAWAY && conn)
+ serf__log(LOGLVL_WARNING, LOGCOMP_CONN, __FILE__, conn->config,
+ "Go away reason %d: %s\n", ctx->buffer[7],
+ apr_pstrmemdup(conn->pool,
+ &ctx->buffer[8],
+ (ctx->buffer_used >= 8)
+ ? ctx->buffer_used-8 : 0));
+
serf_bucket_destroy(ctx->cur_payload);
ctx->cur_frame = ctx->cur_payload = NULL;
ctx->in_payload = FALSE;
ctx->buffer_used = 0;
}
- else if (status)
- break;
+ else
+ continue;
}
if (APR_STATUS_IS_EOF(status))
@@ -186,7 +292,18 @@ http2_read(serf_connection_t *conn)
static apr_status_t
http2_protocol_read(serf_connection_t *conn)
{
- apr_status_t status = http2_read(conn);
+ apr_status_t status;
+
+ /* If the stop_writing flag was set on the connection, reset it now because
+ there is some data to read. */
+ if (conn->stop_writing)
+ {
+ conn->stop_writing = 0;
+ conn->dirty_conn = 1;
+ conn->ctx->dirty_pollset = 1;
+ }
+
+ status = http2_read(conn);
if (!status)
return APR_SUCCESS;
@@ -208,7 +325,19 @@ http2_protocol_read(serf_connection_t *c
static apr_status_t
http2_protocol_write(serf_connection_t *conn)
{
- /* serf_http2_procotol_state_t *ctx = conn->protocol_baton; */
+ serf_http2_procotol_state_t *ctx = conn->protocol_baton;
+ apr_status_t status;
+
+ status = serf__connection_flush(conn, TRUE);
+
+ if (APR_STATUS_IS_EAGAIN(status))
+ return APR_SUCCESS;
+ else if (status)
+ return status;
+
+ /* Probably nothing to write. Connection will check new requests */
+ conn->dirty_conn = 1;
+ conn->ctx->dirty_pollset = 1;
return APR_SUCCESS;
}
Added: serf/trunk/protocols/http2_protocol.h
URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.h?rev=1709676&view=auto
==============================================================================
--- serf/trunk/protocols/http2_protocol.h (added)
+++ serf/trunk/protocols/http2_protocol.h Tue Oct 20 20:23:04 2015
@@ -0,0 +1,85 @@
+/* ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+#ifndef SERF_PROTOCOL_HTTP2_PRIVATE_H
+#define SERF_PROTOCOL_HTTP2_PRIVATE_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ********** HTTP2 Frame types ********** */
+
+/* The standard maximum framesize. Always supported */
+#define HTTP2_DEFAULT_MAX_FRAMESIZE 16384
+
+/* Frame type is an 8 bit unsigned integer */
+
+/* http://tools.ietf.org/html/rfc7540#section-11.2 */
+#define HTTP2_FRAME_TYPE_DATA 0x00
+#define HTTP2_FRAME_TYPE_HEADERS 0x01
+#define HTTP2_FRAME_TYPE_PRIORITY 0x02
+#define HTTP2_FRAME_TYPE_RST_STREAM 0x03
+#define HTTP2_FRAME_TYPE_SETTINGS 0x04
+#define HTTP2_FRAME_TYPE_PUSH_PROMISE 0x05
+#define HTTP2_FRAME_TYPE_PING 0x06
+#define HTTP2_FRAME_TYPE_GOAWAY 0x07
+#define HTTP2_FRAME_TYPE_WINDOW_UPDATE 0x08
+#define HTTP2_FRAME_TYPE_CONTINUATION 0x09
+/* https://httpwg.github.io/http-extensions/alt-svc.html
+ documents that frame 0x0A will most likely be assigned
+ to ALT-SVC */
+
+/* ********** HTTP2 Flags ********** */
+
+/* Flags are currently unique over all frame types, but perhaps this
+ may change in future specs */
+
+
+/* Defined on DATA and HEADERS */
+#define HTTP2_FLAG_END_STREAM 0x01
+/* Defined on HEADERS and CONTINUATION */
+#define HTTP2_FLAG_END_HEADERS 0x04
+/* Defined on DATA and HEADERS */
+#define HTTP2_FLAG_PADDED 0x08
+/* Defined on HEADERS */
+#define HTTP2_FLAG_PRIORITY 0x20
+
+
+/* ********** HTTP2 Settings ********** */
+
+/* Settings are 16 bit unsigned integers*/
+#define HTTP2_SETTING_HEADER_TABLE_SIZE 0x0001 /* default: 4096 */
+#define HTTP2_SETTING_ENABLE_PUSH 0x0002 /* default: 1 */
+#define HTTP2_SETTING_MAX_CONCURRENT_STREAMS 0x0003 /* default: (infinite) */
+#define HTTP2_SETTING_INITIAL_WINDOW_SIZE 0x0004 /* default: 65535 */
+#define HTTP2_SETTING_MAX_FRAME_SIZE 0x0005 /* default: 16384 */
+#define HTTP2_SETTING_MAX_HEADER_LIST_SIZE 0x0006 /* default: (infinite) */
+
+/* https://tools.ietf.org/html/rfc7540#section-3.5 */
+#define HTTP2_CONNECTION_PREFIX "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Propchange: serf/trunk/protocols/http2_protocol.h
------------------------------------------------------------------------------
svn:eol-style = native