On Sat, 25 Jan 2014, Fabian Frank wrote:
It would be great if someone working on http2 (Daniel?) could share the
current status, planned design - if there is one - and most importantly,
where help and contribution is needed.
General http2 status:
Firefox has an implementation of http2 draft-09 and so does twitter. I
blogged about what's about to change in http2 from this point:
http://daniel.haxx.se/blog/2014/01/24/http2-the-next-step/
There's likely to be a draft-10 out within a few weeks and it will change the
protocol on the wire a bit again. I'm pretty sure both Firefox and Twitter
will adapt pretty swiftly and that help us with interop.
Source code status:
There's no HTTPS/http2 support at all yet. We need to ask for 'h2,http' using
ALPN as that's the negotiation mechanism chosen for http2 and OpenSSL has not
released ALPN support in a public release yet. I also decided to work on the
plain-text version of the protocol first to kind of start somewhere.
I have two patches pending (attached) that do the Upgrade dance a little bit
and start to use the nghttp2 API to actually "decode" the HTTP2 stream. The
binary "junk" seen right now is because libcurl simply downloads the TCP as-is
without caring about the HTTP2 protocol at all.
When I last worked on this code I found a problem with the nghttp2 API that
Tatsushiro has since adressed so we should be able to proceed better now. To
do next is basically to make sure we pipe incoming tcp data properly to
nghttp2 and take care of what nghttp2 decodes for us.
Most likely we need to make a http2=>http1 translation of incoming headers,
and then pass the headers through our existing http parser (at least for the
subset of headers that aren't related to message framing etc). It will also
give us the opportunity (optionally) to pass on http2 headers to applications
with the "old" look and possibly ease transition even more.
Next steps:
After the release on this coming Wednesday, I'll push my two pending http2
commits. Then we can work on making sure we decode the received data properly
and make sure that we can send http2 requests and uploads properly. We also
need to work on how to do ALPN properly which has an added complexity in the
fact that we have the "vtls" layer that abstracts a lot of SSL backends.
Finally:
I'm glad to see your interest to help out. I would love to see some progress
here so that we can join the small community of early http2 implementations
and hopefully try it out early and see how it works!
Questions or comments?
--
/ daniel.haxx.se
From 99e5aab547b86a32c3f796b2361a9c832d3e97e0 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <[email protected]>
Date: Thu, 12 Sep 2013 13:51:04 +0200
Subject: [PATCH 1/2] http2: handle 101 responses and switch to HTTP2
---
lib/http.c | 25 +++++++++++++++++++++----
lib/http2.c | 36 ++++++++++++++++++++++++++++++++++++
lib/http2.h | 2 ++
lib/urldata.h | 9 ++++++++-
4 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/lib/http.c b/lib/http.c
index da03a44..8df0105 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -2872,10 +2872,27 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
k->header = TRUE;
k->headerline = 0; /* restart the header line counter */
- /* if we did wait for this do enable write now! */
- if(k->exp100) {
- k->exp100 = EXP100_SEND_DATA;
- k->keepon |= KEEP_SEND;
+ /* "A user agent MAY ignore unexpected 1xx status responses." */
+ switch(k->httpcode) {
+ case 100:
+ /* if we did wait for this do enable write now! */
+ if(k->exp100) {
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ }
+ break;
+ case 101:
+ /* Switching Protocols */
+ if(k->upgr101 == UPGR101_REQUESTED) {
+ infof(data, "Received 101\n");
+ k->upgr101 = UPGR101_RECEIVED;
+
+ /* switch to http2 now */
+ Curl_http2_switched(conn);
+ }
+ break;
+ default:
+ break;
}
}
else {
diff --git a/lib/http2.c b/lib/http2.c
index b876436..f15cb17 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -38,6 +38,32 @@
#include "memdebug.h"
/*
+ * HTTP2 handler interface. This isn't added to the general list of protocols
+ * but will be used at run-time when the protocol is dynamically switched from
+ * HTTP to HTTP2.
+ */
+const struct Curl_handler Curl_handler_http2 = {
+ "HTTP2", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ ZERO_NULL, /* do_it */
+ ZERO_NULL , /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTP, /* defport */
+ 0, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+
+/*
* Store nghttp2 version info in this buffer, Prefix with a space. Return
* total length written.
*/
@@ -138,6 +164,7 @@ CURLcode Curl_http2_request(Curl_send_buffer *req,
ssize_t binlen;
char *base64;
size_t blen;
+ struct SingleRequest *k = &conn->data->req;
if(!conn->proto.httpc.h2) {
/* The nghttp2 session is not yet setup, do it */
@@ -176,7 +203,16 @@ CURLcode Curl_http2_request(Curl_send_buffer *req,
NGHTTP2_PROTO_VERSION_ID, base64);
free(base64);
+ k->upgr101 = UPGR101_REQUESTED;
+
return result;
}
+void Curl_http2_switched(struct connectdata *conn)
+{
+ /* we are switched! */
+ conn->handler = &Curl_handler_http2;
+ infof(conn->data, "We have switched to HTTP2\n");
+}
+
#endif
diff --git a/lib/http2.h b/lib/http2.h
index 09b91d1..ffe1682 100644
--- a/lib/http2.h
+++ b/lib/http2.h
@@ -34,8 +34,10 @@ int Curl_http2_ver(char *p, size_t len);
CURLcode Curl_http2_request(Curl_send_buffer *req,
struct connectdata *conn);
+void Curl_http2_switched(struct connectdata *conn);
#else /* USE_NGHTTP2 */
#define Curl_http2_request(x,y) CURLE_OK
+#define Curl_http2_switched(x)
#endif
#endif /* HEADER_CURL_HTTP2_H */
diff --git a/lib/urldata.h b/lib/urldata.h
index a00894e..7cb6857 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -580,7 +580,6 @@ struct Curl_async {
typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *);
typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
-
enum expect100 {
EXP100_SEND_DATA, /* enough waiting, just send the body now */
EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
@@ -589,6 +588,13 @@ enum expect100 {
EXP100_FAILED /* used on 417 Expectation Failed */
};
+enum upgrade101 {
+ UPGR101_INIT, /* default state */
+ UPGR101_REQUESTED, /* upgrade requested */
+ UPGR101_RECEIVED, /* response received */
+ UPGR101_WORKING /* talking upgraded protocol */
+};
+
/*
* Request specific data in the easy handle (SessionHandle). Previously,
* these members were on the connectdata struct but since a conn struct may
@@ -639,6 +645,7 @@ struct SingleRequest {
'RTSP/1.? XXX' line */
struct timeval start100; /* time stamp to wait for the 100 code from */
enum expect100 exp100; /* expect 100 continue state */
+ enum upgrade101 upgr101; /* 101 upgrade state */
int auto_decoding; /* What content encoding. sec 3.5, RFC2616. */
--
1.8.5.3
From 29e6f7c659d49bb2570f0e8c710e177fb1971dad Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <[email protected]>
Date: Wed, 18 Sep 2013 22:43:13 +0200
Subject: [PATCH 2/2] http2: switch recv/send functions to http2 ones after 101
---
lib/http.h | 3 +++
lib/http2.c | 38 +++++++++++++++++++++++++++++++++++++-
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/lib/http.h b/lib/http.h
index 82a7b50..8d3f9d0 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -152,6 +152,9 @@ struct HTTP {
struct http_conn {
#ifdef USE_NGHTTP2
nghttp2_session *h2;
+ char *mem; /* points to a buffer in memory to store or read from */
+ size_t size; /* size of the buffer 'mem' points to */
+ ssize_t nread; /* how much data that was sent/recv by the HTTP2 engine */
#else
int unused; /* prevent a compiler warning */
#endif
diff --git a/lib/http2.c b/lib/http2.c
index f15cb17..b6b01cb 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -111,7 +111,7 @@ static ssize_t recv_callback(nghttp2_session *h2,
{
struct connectdata *conn = (struct connectdata *)userp;
ssize_t nread;
- CURLcode rc = Curl_read(conn, conn->sock[0], (char *)buf, length, &nread);
+ CURLcode rc = Curl_read_plain(conn->sock[0], (char *)buf, length, &nread);
(void)h2;
(void)flags;
@@ -208,10 +208,46 @@ CURLcode Curl_http2_request(Curl_send_buffer *req,
return result;
}
+/*
+ * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
+ * a regular CURLcode value.
+ */
+static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
+{
+ int rc;
+ (void)sockindex; /* we always do HTTP2 on sockindex 0 */
+
+ conn->proto.httpc.mem = mem;
+ conn->proto.httpc.size = len;
+
+ rc = nghttp2_session_recv(conn->proto.httpc.h2);
+
+ if(rc < 0) {
+ *err = CURLE_RECV_ERROR;
+ }
+ return 0;
+}
+
+/* return number of received (decrypted) bytes */
+static ssize_t http2_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
+{
+ /* TODO: proper implementation */
+ (void)conn;
+ (void)sockindex;
+ (void)mem;
+ (void)len;
+ (void)err;
+ return 0;
+}
+
void Curl_http2_switched(struct connectdata *conn)
{
/* we are switched! */
conn->handler = &Curl_handler_http2;
+ conn->recv[FIRSTSOCKET] = http2_recv;
+ conn->send[FIRSTSOCKET] = http2_send;
infof(conn->data, "We have switched to HTTP2\n");
}
--
1.8.5.3
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html