Commit 897a7b3a authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

http2: store upload state per stream

Use a curl_off_t for upload left
parent 155b1f5d
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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 */

+47 −17
Original line number Diff line number Diff line
@@ -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;