#include "setopt.h"
#include "http_digest.h"
#include "system_win32.h"
+#include "http2.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
/* put it back in the keepon */
k->keepon = newstate;
- if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) {
- /* there are buffers for sending that can be delivered as the receive
- pausing is lifted! */
- unsigned int i;
- unsigned int count = data->state.tempcount;
- struct tempbuf writebuf[3]; /* there can only be three */
- struct connectdata *conn = data->conn;
- struct Curl_easy *saved_data = NULL;
-
- /* copy the structs to allow for immediate re-pausing */
- for(i = 0; i < data->state.tempcount; i++) {
- writebuf[i] = data->state.tempwrite[i];
- data->state.tempwrite[i].buf = NULL;
- }
- data->state.tempcount = 0;
+ if(!(newstate & KEEP_RECV_PAUSE)) {
+ Curl_http2_stream_pause(data, FALSE);
+
+ if(data->state.tempcount) {
+ /* there are buffers for sending that can be delivered as the receive
+ pausing is lifted! */
+ unsigned int i;
+ unsigned int count = data->state.tempcount;
+ struct tempbuf writebuf[3]; /* there can only be three */
+ struct connectdata *conn = data->conn;
+ struct Curl_easy *saved_data = NULL;
+
+ /* copy the structs to allow for immediate re-pausing */
+ for(i = 0; i < data->state.tempcount; i++) {
+ writebuf[i] = data->state.tempwrite[i];
+ data->state.tempwrite[i].buf = NULL;
+ }
+ data->state.tempcount = 0;
- /* set the connection's current owner */
- if(conn->data != data) {
- saved_data = conn->data;
- conn->data = data;
- }
+ /* set the connection's current owner */
+ if(conn->data != data) {
+ saved_data = conn->data;
+ conn->data = data;
+ }
- for(i = 0; i < count; i++) {
- /* even if one function returns error, this loops through and frees all
- buffers */
- if(!result)
- result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
- writebuf[i].len);
- free(writebuf[i].buf);
- }
+ for(i = 0; i < count; i++) {
+ /* even if one function returns error, this loops through and frees
+ all buffers */
+ if(!result)
+ result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
+ writebuf[i].len);
+ free(writebuf[i].buf);
+ }
- /* recover previous owner of the connection */
- if(saved_data)
- conn->data = saved_data;
+ /* recover previous owner of the connection */
+ if(saved_data)
+ conn->data = saved_data;
- if(result)
- return result;
+ if(result)
+ return result;
+ }
}
/* if there's no error and we're not pausing both directions, we want
#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
#endif
-#define HTTP2_HUGE_WINDOW_SIZE (1 << 30)
+#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */
#ifdef DEBUG_HTTP2
#define H2BUGF(x) x
struct http_conn *httpc)
{
nghttp2_settings_entry *iv = httpc->local_settings;
+ DEBUGASSERT(conn->data);
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = Curl_multi_max_concurrent_streams(conn->data->multi);
return ncopy;
}
- H2BUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
- data, stream->stream_id));
+ H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u\n",
+ data, stream->stream_id,
+ nghttp2_session_get_local_window_size(httpc->h2),
+ nghttp2_session_get_stream_local_window_size(httpc->h2,
+ stream->stream_id)
+ ));
if((data->state.drain) && stream->memlen) {
H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
stream->pausedata += nread;
stream->pauselen -= nread;
- infof(data, "%zd data bytes written\n", nread);
if(stream->pauselen == 0) {
H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
return CURLE_OK;
}
+CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
+{
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ /* if it isn't HTTP/2, we're done */
+ if(!data->conn->proto.httpc.h2)
+ return CURLE_OK;
+#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
+ else {
+ struct HTTP *stream = data->req.protop;
+ struct http_conn *httpc = &data->conn->proto.httpc;
+ uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
+ int rv = nghttp2_session_set_local_window_size(httpc->h2,
+ NGHTTP2_FLAG_NONE,
+ stream->stream_id,
+ window);
+ if(rv) {
+ failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+ nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
+
+ /* make sure the window update gets sent */
+ rv = h2_session_send(data, httpc->h2);
+ if(rv)
+ return CURLE_SEND_ERROR;
+
+ DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u\n",
+ window, stream->stream_id));
+
+#ifdef DEBUGBUILD
+ {
+ /* read out the stream local window again */
+ uint32_t window2 =
+ nghttp2_session_get_stream_local_window_size(httpc->h2,
+ stream->stream_id);
+ DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u\n",
+ window2, stream->stream_id));
+ }
+#endif
+ }
+#endif
+ return CURLE_OK;
+}
+
CURLcode Curl_http2_add_child(struct Curl_easy *parent,
struct Curl_easy *child,
bool exclusive)
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
void Curl_http2_remove_child(struct Curl_easy *parent,
struct Curl_easy *child);
void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
+CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
bool Curl_h2_http_1_1_error(struct connectdata *conn);
#define Curl_http2_add_child(x, y, z)
#define Curl_http2_remove_child(x, y)
#define Curl_http2_cleanup_dependencies(x)
+#define Curl_http2_stream_pause(x, y)
#define Curl_h2_http_1_1_error(x) 0
#endif
#include "strerror.h"
#include "select.h"
#include "strdup.h"
+#include "http2.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
unsigned int i;
bool newtype = TRUE;
+ /* If this transfers over HTTP/2, pause the stream! */
+ Curl_http2_stream_pause(data, TRUE);
+
if(s->tempcount) {
for(i = 0; i< s->tempcount; i++) {
if(s->tempwrite[i].type == type) {
/* update the pointer and the size */
s->tempwrite[i].buf = newptr;
s->tempwrite[i].len = newlen;
+
+ len = newlen; /* for the debug output below */
}
else {
dupl = Curl_memdup(ptr, len);
Accept: */*\r
Connection: Upgrade, HTTP2-Settings\r
Upgrade: %H2CVER\r
-HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA\r
+HTTP2-Settings: AAMAAABkAAQCAAAAAAIAAAAA\r
\r
</protocol>
</verify>