1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

http2: store upload state per stream

Use a curl_off_t for upload left
This commit is contained in:
Daniel Stenberg 2015-05-18 14:01:38 +02:00
parent 155b1f5df9
commit 897a7b3a13
2 changed files with 52 additions and 21 deletions

View File

@ -171,6 +171,10 @@ struct HTTP {
char *mem; /* points to a buffer in memory to store received data */ char *mem; /* points to a buffer in memory to store received data */
size_t len; /* size of the buffer 'mem' points to */ size_t len; /* size of the buffer 'mem' points to */
size_t memlen; /* size of data copied to mem */ 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 */ 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 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 this case, we wrongly sends the content of mem buffer if we share
them for both cases. */ 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 int32_t pause_stream_id; /* stream ID which paused
nghttp2_session_mem_recv */ nghttp2_session_mem_recv */

View File

@ -588,24 +588,47 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
{ {
struct connectdata *conn = (struct connectdata *)userp; struct connectdata *conn = (struct connectdata *)userp;
struct http_conn *c = &conn->proto.httpc; struct http_conn *c = &conn->proto.httpc;
struct SessionHandle *data_s;
struct HTTP *stream = NULL;
size_t nread; size_t nread;
(void)session; (void)session;
(void)stream_id; (void)stream_id;
(void)source; (void)source;
nread = MIN(c->upload_len, length); if(stream_id) {
if(nread > 0) { /* get the stream from the hash based on Stream ID, stream ID zero is for
memcpy(buf, c->upload_mem, nread); connection-oriented stuff */
c->upload_mem += nread; data_s = Curl_hash_pick(&c->streamsh, &stream_id, sizeof(stream_id));
c->upload_len -= nread; if(!data_s) {
c->upload_left -= nread; /* 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;
} }
if(c->upload_left == 0) nread = MIN(stream->upload_len, length);
if(nread > 0) {
memcpy(buf, stream->upload_mem, nread);
stream->upload_mem += nread;
stream->upload_len -= nread;
stream->upload_left -= nread;
}
if(stream->upload_left == 0)
*data_flags = 1; *data_flags = 1;
else if(nread == 0) else if(nread == 0)
return NGHTTP2_ERR_DEFERRED; return NGHTTP2_ERR_DEFERRED;
DEBUGF(infof(data_s, "data_source_read_callback: "
"returns %zu bytes stream %x\n",
nread, stream_id));
return nread; 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 /* Nullify here because we call nghttp2_session_send() and they
might refer to the old buffer. */ might refer to the old buffer. */
httpc->upload_mem = NULL; stream->upload_mem = NULL;
httpc->upload_len = 0; stream->upload_len = 0;
/* /*
* At this point 'stream' is just in the SessionHandle the connection * 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->stream_id != -1) {
/* If stream_id != -1, we have dispatched request HEADERS, and now /* If stream_id != -1, we have dispatched request HEADERS, and now
are going to send or sending request body in DATA frame */ are going to send or sending request body in DATA frame */
httpc->upload_mem = mem; stream->upload_mem = mem;
httpc->upload_len = len; stream->upload_len = len;
nghttp2_session_resume_data(h2, stream->stream_id); nghttp2_session_resume_data(h2, stream->stream_id);
rv = nghttp2_session_send(h2); rv = nghttp2_session_send(h2);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
*err = CURLE_SEND_ERROR; *err = CURLE_SEND_ERROR;
return -1; 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) */ /* 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 && if(nva[i].namelen == 14 &&
Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
size_t j; size_t j;
stream->upload_left = 0;
for(j = 0; j < nva[i].valuelen; ++j) { for(j = 0; j < nva[i].valuelen; ++j) {
httpc->upload_left *= 10; stream->upload_left *= 10;
httpc->upload_left += nva[i].value[j] - '0'; stream->upload_left += nva[i].value[j] - '0';
} }
DEBUGF(infof(conn->data, 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; return result;
infof(conn->data, "Using HTTP2, server supports multi-use\n"); infof(conn->data, "Using HTTP2, server supports multi-use\n");
httpc->upload_left = 0; stream->upload_left = 0;
httpc->upload_mem = NULL; stream->upload_mem = NULL;
httpc->upload_len = 0; stream->upload_len = 0;
httpc->inbuflen = 0; httpc->inbuflen = 0;
httpc->nread_inbuf = 0; httpc->nread_inbuf = 0;