aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2015-05-18 14:01:38 +0200
committerDaniel Stenberg <daniel@haxx.se>2015-05-18 15:41:43 +0200
commit897a7b3a13138468fb8bb98b8d54cdd5eef7ae9d (patch)
tree3ad61135f916f0203877c12a798dfbb674d72c1b
parent155b1f5df9b772e861da2b72aafd8342013b76a2 (diff)
http2: store upload state per stream
Use a curl_off_t for upload left
-rw-r--r--lib/http.h7
-rw-r--r--lib/http2.c64
2 files changed, 51 insertions, 20 deletions
diff --git a/lib/http.h b/lib/http.h
index e8014409b..cb861e2e5 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -171,6 +171,10 @@ struct HTTP {
char *mem; /* points to a buffer in memory to store received data */
size_t len; /* size of the buffer 'mem' points to */
size_t memlen; /* size of data copied to mem */
+
+ const uint8_t *upload_mem; /* points to a buffer to read from */
+ size_t upload_len; /* size of the buffer 'upload_mem' points to */
+ curl_off_t upload_left; /* number of bytes left to upload */
};
typedef int (*sending)(void); /* Curl_send */
@@ -199,9 +203,6 @@ struct http_conn {
nghttp2_session_mem_recv() but mem buffer is still not full. In
this case, we wrongly sends the content of mem buffer if we share
them for both cases. */
- const uint8_t *upload_mem; /* points to a buffer to read from */
- size_t upload_len; /* size of the buffer 'upload_mem' points to */
- size_t upload_left; /* number of bytes left to upload */
int32_t pause_stream_id; /* stream ID which paused
nghttp2_session_mem_recv */
diff --git a/lib/http2.c b/lib/http2.c
index 867162a76..c653bbe17 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -588,24 +588,47 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
{
struct connectdata *conn = (struct connectdata *)userp;
struct http_conn *c = &conn->proto.httpc;
+ struct SessionHandle *data_s;
+ struct HTTP *stream = NULL;
size_t nread;
(void)session;
(void)stream_id;
(void)source;
- nread = MIN(c->upload_len, length);
+ 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(&c->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, "Asked for data to stream %x not in hash!", stream_id);
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ stream = data_s->req.protop;
+ }
+ else {
+ failf(conn->data, "nghttp2 confusion");
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ nread = MIN(stream->upload_len, length);
if(nread > 0) {
- memcpy(buf, c->upload_mem, nread);
- c->upload_mem += nread;
- c->upload_len -= nread;
- c->upload_left -= nread;
+ memcpy(buf, stream->upload_mem, nread);
+ stream->upload_mem += nread;
+ stream->upload_len -= nread;
+ stream->upload_left -= nread;
}
- if(c->upload_left == 0)
+ if(stream->upload_left == 0)
*data_flags = 1;
else if(nread == 0)
return NGHTTP2_ERR_DEFERRED;
+ DEBUGF(infof(data_s, "data_source_read_callback: "
+ "returns %zu bytes stream %x\n",
+ nread, stream_id));
+
return nread;
}
@@ -792,8 +815,8 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
/* Nullify here because we call nghttp2_session_send() and they
might refer to the old buffer. */
- httpc->upload_mem = NULL;
- httpc->upload_len = 0;
+ stream->upload_mem = NULL;
+ stream->upload_len = 0;
/*
* At this point 'stream' is just in the SessionHandle the connection
@@ -991,15 +1014,19 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
if(stream->stream_id != -1) {
/* If stream_id != -1, we have dispatched request HEADERS, and now
are going to send or sending request body in DATA frame */
- httpc->upload_mem = mem;
- httpc->upload_len = len;
+ stream->upload_mem = mem;
+ stream->upload_len = len;
nghttp2_session_resume_data(h2, stream->stream_id);
rv = nghttp2_session_send(h2);
if(nghttp2_is_fatal(rv)) {
*err = CURLE_SEND_ERROR;
return -1;
}
- return len - httpc->upload_len;
+ len -= stream->upload_len;
+
+ DEBUGF(infof(conn->data, "http2_send returns %zu for stream %x\n", len,
+ stream->stream_id));
+ return len;
}
/* Calculate number of headers contained in [mem, mem + len) */
@@ -1078,12 +1105,15 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
if(nva[i].namelen == 14 &&
Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
size_t j;
+ stream->upload_left = 0;
for(j = 0; j < nva[i].valuelen; ++j) {
- httpc->upload_left *= 10;
- httpc->upload_left += nva[i].value[j] - '0';
+ stream->upload_left *= 10;
+ stream->upload_left += nva[i].value[j] - '0';
}
DEBUGF(infof(conn->data,
- "request content-length=%zu\n", httpc->upload_left));
+ "request content-length=%"
+ CURL_FORMAT_CURL_OFF_T
+ "\n", stream->upload_left));
}
}
@@ -1177,9 +1207,9 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
return result;
infof(conn->data, "Using HTTP2, server supports multi-use\n");
- httpc->upload_left = 0;
- httpc->upload_mem = NULL;
- httpc->upload_len = 0;
+ stream->upload_left = 0;
+ stream->upload_mem = NULL;
+ stream->upload_len = 0;
httpc->inbuflen = 0;
httpc->nread_inbuf = 0;