From 8d3608f2ad29bb65ce0926a45b46ff29902c279f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 12 Sep 2013 13:51:04 +0200 Subject: [PATCH] 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 da03a44c5..8df0105a1 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 b876436e1..f15cb1700 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -37,6 +37,32 @@ /* include memdebug.h last */ #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 09b91d112..ffe16820e 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 a00894e5c..7cb685707 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. */