Skip to content

Commit

Permalink
http2: store upload state per stream
Browse files Browse the repository at this point in the history
Use a curl_off_t for upload left
  • Loading branch information
bagder committed May 18, 2015
1 parent 155b1f5 commit 897a7b3
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 20 deletions.
7 changes: 4 additions & 3 deletions lib/http.h
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */

Expand Down
64 changes: 47 additions & 17 deletions lib/http2.c
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) */
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 897a7b3

Please sign in to comment.