aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2015-04-29 15:21:45 +0200
committerDaniel Stenberg <daniel@haxx.se>2015-05-18 08:57:17 +0200
commit84c6b6561f8a537f43b0647e4dbd7f2b258e2174 (patch)
tree688c13f3a36cc9f4992853b4e67a02520609820b
parent2c238ea1fc3b0979ebe6a6088591198df5ea5415 (diff)
http2: more stream-oriented data, stream ID 0 is for connections
-rw-r--r--lib/http.c2
-rw-r--r--lib/http.h4
-rw-r--r--lib/http2.c47
-rw-r--r--lib/transfer.c3
4 files changed, 31 insertions, 25 deletions
diff --git a/lib/http.c b/lib/http.c
index aa1dcbf0e..4b67db4b9 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -168,6 +168,8 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
http->status_code = -1;
http->data = NULL;
http->datalen = 0;
+ http->error_code = NGHTTP2_NO_ERROR;
+ http->closed = FALSE;
return CURLE_OK;
}
diff --git a/lib/http.h b/lib/http.h
index a64d83f18..48f5c7350 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -164,6 +164,8 @@ struct HTTP {
int status_code; /* HTTP status code */
const uint8_t *data; /* pointer to data chunk, received in on_data_chunk */
size_t datalen; /* the number of bytes left in data */
+ bool closed; /* TRUE on HTTP2 stream close */
+ uint32_t error_code; /* HTTP/2 error code */
};
typedef int (*sending)(void); /* Curl_send */
@@ -179,8 +181,6 @@ struct http_conn {
size_t len; /* size of the buffer 'mem' points to */
sending send_underlying; /* underlying send Curl_send callback */
recving recv_underlying; /* underlying recv Curl_recv callback */
- bool closed; /* TRUE on HTTP2 stream close */
- uint32_t error_code; /* HTTP/2 error code */
char *inbuf; /* buffer to receive data from underlying socket */
/* We need separate buffer for transmission and reception because we
may call nghttp2_session_send() after the
diff --git a/lib/http2.c b/lib/http2.c
index 3959a4f8a..8a60c3747 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -379,23 +379,30 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *userp)
{
struct connectdata *conn = (struct connectdata *)userp;
- struct http_conn *c = &conn->proto.httpc;
- struct HTTP *stream = conn->data->req.protop;
+ struct SessionHandle *data_s;
+ struct HTTP *stream;
(void)session;
(void)stream_id;
- DEBUGF(infof(conn->data, "on_stream_close() was called, error_code = %d\n",
- error_code));
+ DEBUGF(infof(conn->data, "on_stream_close(), error_code = %d, stream %x\n",
+ error_code, stream_id));
- if(stream_id != stream->stream_id) {
- DEBUGF(infof(conn->data, "on_stream_close() "
- "got stream %x, expected stream %x\n",
- stream_id, stream->stream_id));
- return 0;
- }
-
- c->error_code = error_code;
- c->closed = TRUE;
+ if(stream_id) {
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
+ data_s = Curl_hash_pick(&conn->proto.httpc.streamsh, &stream_id,
+ sizeof(stream_id));
+ if(!data_s) {
+ /* Receiving a Stream ID not in the hash should not happen, this is an
+ internal error more than anything else! */
+ failf(conn->data, "Received frame on Stream ID: %x not in stream hash!",
+ stream_id);
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ stream = data_s->req.protop;
+ stream->error_code = error_code;
+ stream->closed = TRUE;
+ }
return 0;
}
@@ -732,10 +739,10 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
(void)sockindex; /* we always do HTTP2 on sockindex 0 */
- if(httpc->closed) {
+ if(stream->closed) {
/* Reset to FALSE to prevent infinite loop in readwrite_data
function. */
- httpc->closed = FALSE;
+ stream->closed = FALSE;
return 0;
}
@@ -826,14 +833,14 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
}
/* If stream is closed, return 0 to signal the http routine to close
the connection */
- if(httpc->closed) {
+ if(stream->closed) {
/* Reset to FALSE to prevent infinite loop in readwrite_data
function. */
- httpc->closed = FALSE;
- if(httpc->error_code != NGHTTP2_NO_ERROR) {
+ stream->closed = FALSE;
+ if(stream->error_code != NGHTTP2_NO_ERROR) {
failf(conn->data,
"HTTP/2 stream = %x was not closed cleanly: error_code = %d",
- stream->stream_id, httpc->error_code);
+ stream->stream_id, stream->error_code);
*err = CURLE_HTTP2;
return -1;
}
@@ -1058,8 +1065,6 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
return result;
infof(conn->data, "Using HTTP2, server supports multi-use\n");
- httpc->error_code = NGHTTP2_NO_ERROR;
- httpc->closed = FALSE;
httpc->upload_left = 0;
httpc->upload_mem = NULL;
httpc->upload_len = 0;
diff --git a/lib/transfer.c b/lib/transfer.c
index 267e0a1cc..2d7b13785 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -317,8 +317,7 @@ static int data_pending(const struct connectdata *conn)
TRUE. The thing is if we read everything, then http2_recv won't
be called and we cannot signal the HTTP/2 stream has closed. As
a workaround, we return nonzero here to call http2_recv. */
- ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20 &&
- conn->proto.httpc.closed);
+ ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20);
#else
Curl_ssl_data_pending(conn, FIRSTSOCKET);
#endif