|
@@ -38,6 +38,7 @@
|
|
|
#include "strcase.h"
|
|
|
#include "multiif.h"
|
|
|
#include "url.h"
|
|
|
+#include "urlapi-int.h"
|
|
|
#include "cfilters.h"
|
|
|
#include "connect.h"
|
|
|
#include "strtoofft.h"
|
|
@@ -768,7 +769,7 @@ static int set_transfer_url(struct Curl_easy *data,
|
|
|
|
|
|
v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY);
|
|
|
if(v) {
|
|
|
- uc = curl_url_set(u, CURLUPART_HOST, v, 0);
|
|
|
+ uc = curl_url_set_authority(u, v, CURLU_DISALLOW_USER);
|
|
|
if(uc) {
|
|
|
rc = 2;
|
|
|
goto fail;
|
|
@@ -950,8 +951,15 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
|
|
|
|
|
switch(frame->hd.type) {
|
|
|
case NGHTTP2_DATA:
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[DATA len=%zu pad=%zu], "
|
|
|
+ "buffered=%zu, window=%d/%d",
|
|
|
+ stream_id, frame->hd.length, frame->data.padlen,
|
|
|
+ Curl_bufq_len(&stream->recvbuf),
|
|
|
+ nghttp2_session_get_stream_effective_recv_data_length(
|
|
|
+ ctx->h2, stream->id),
|
|
|
+ nghttp2_session_get_stream_effective_local_window_size(
|
|
|
+ ctx->h2, stream->id)));
|
|
|
/* If !body started on this stream, then receiving DATA is illegal. */
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv frame DATA", stream_id));
|
|
|
if(!stream->bodystarted) {
|
|
|
rv = nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
|
|
|
stream_id, NGHTTP2_PROTOCOL_ERROR);
|
|
@@ -965,7 +973,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
|
|
}
|
|
|
break;
|
|
|
case NGHTTP2_HEADERS:
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv frame HEADERS", stream_id));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[HEADERS]", stream_id));
|
|
|
if(stream->bodystarted) {
|
|
|
/* Only valid HEADERS after body started is trailer HEADERS. We
|
|
|
buffer them in on_header callback. */
|
|
@@ -993,7 +1001,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
|
|
drain_stream(cf, data, stream);
|
|
|
break;
|
|
|
case NGHTTP2_PUSH_PROMISE:
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv PUSH_PROMISE", stream_id));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[PUSH_PROMISE]", stream_id));
|
|
|
rv = push_promise(cf, data, &frame->push_promise);
|
|
|
if(rv) { /* deny! */
|
|
|
DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
|
|
@@ -1010,13 +1018,13 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
|
|
}
|
|
|
break;
|
|
|
case NGHTTP2_RST_STREAM:
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv RST", stream_id));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FARME[RST]", stream_id));
|
|
|
stream->closed = TRUE;
|
|
|
stream->reset = TRUE;
|
|
|
drain_stream(cf, data, stream);
|
|
|
break;
|
|
|
case NGHTTP2_WINDOW_UPDATE:
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv WINDOW_UPDATE", stream_id));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[WINDOW_UPDATE]", stream_id));
|
|
|
if((data->req.keepon & KEEP_SEND_HOLD) &&
|
|
|
(data->req.keepon & KEEP_SEND)) {
|
|
|
data->req.keepon &= ~KEEP_SEND_HOLD;
|
|
@@ -1026,7 +1034,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] recv frame %x",
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] FRAME[%x]",
|
|
|
stream_id, frame->hd.type));
|
|
|
break;
|
|
|
}
|
|
@@ -1048,7 +1056,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
|
|
switch(frame->hd.type) {
|
|
|
case NGHTTP2_SETTINGS: {
|
|
|
uint32_t max_conn = ctx->max_concurrent_streams;
|
|
|
- DEBUGF(LOG_CF(data, cf, "recv frame SETTINGS"));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "FRAME[SETTINGS]"));
|
|
|
ctx->max_concurrent_streams = nghttp2_session_get_remote_settings(
|
|
|
session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
|
|
|
ctx->enable_push = nghttp2_session_get_remote_settings(
|
|
@@ -1070,7 +1078,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
|
|
ctx->goaway_error = frame->goaway.error_code;
|
|
|
ctx->last_stream_id = frame->goaway.last_stream_id;
|
|
|
if(data) {
|
|
|
- DEBUGF(LOG_CF(data, cf, "recv GOAWAY, error=%d, last_stream=%u",
|
|
|
+ DEBUGF(LOG_CF(data, cf, "FRAME[GOAWAY, error=%d, last_stream=%u]",
|
|
|
ctx->goaway_error, ctx->last_stream_id));
|
|
|
infof(data, "received GOAWAY, error=%d, last_stream=%u",
|
|
|
ctx->goaway_error, ctx->last_stream_id);
|
|
@@ -1078,7 +1086,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
|
|
}
|
|
|
break;
|
|
|
case NGHTTP2_WINDOW_UPDATE:
|
|
|
- DEBUGF(LOG_CF(data, cf, "recv frame WINDOW_UPDATE"));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "FRAME[WINDOW_UPDATE]"));
|
|
|
break;
|
|
|
default:
|
|
|
DEBUGF(LOG_CF(data, cf, "recv frame %x on 0", frame->hd.type));
|
|
@@ -1139,10 +1147,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
|
|
|
drain_stream(cf, data_s, stream);
|
|
|
|
|
|
DEBUGASSERT((size_t)nwritten == len);
|
|
|
- DEBUGF(LOG_CF(data_s, cf, "[h2sid=%d] %zd/%zu DATA recvd, "
|
|
|
- "(buffer now holds %zu)",
|
|
|
- stream_id, nwritten, len, Curl_bufq_len(&stream->recvbuf)));
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1675,11 +1679,13 @@ static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|
|
|
|
|
if(nread < 0) {
|
|
|
if(stream->closed) {
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] returning CLOSE", stream->id));
|
|
|
nread = http2_handle_stream_close(cf, data, stream, err);
|
|
|
}
|
|
|
else if(stream->reset ||
|
|
|
(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
|
|
|
(ctx->goaway && ctx->last_stream_id < stream->id)) {
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] returning ERR", stream->id));
|
|
|
*err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
|
|
|
nread = -1;
|
|
|
}
|
|
@@ -1730,7 +1736,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
|
|
|
Curl_bufq_len(&ctx->inbufq), nread, result)); */
|
|
|
if(nread < 0) {
|
|
|
if(result != CURLE_AGAIN) {
|
|
|
- failf(data, "Failed receiving HTTP2 data");
|
|
|
+ failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
|
|
|
+ curl_easy_strerror(result));
|
|
|
return result;
|
|
|
}
|
|
|
break;
|
|
@@ -1762,12 +1769,6 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|
|
|
|
|
CF_DATA_SAVE(save, cf, data);
|
|
|
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_recv: win %u/%u",
|
|
|
- stream->id,
|
|
|
- nghttp2_session_get_local_window_size(ctx->h2),
|
|
|
- nghttp2_session_get_stream_local_window_size(ctx->h2,
|
|
|
- stream->id)
|
|
|
- ));
|
|
|
nread = stream_recv(cf, data, buf, len, err);
|
|
|
if(nread < 0 && *err != CURLE_AGAIN)
|
|
|
goto out;
|
|
@@ -1794,8 +1795,6 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
|
|
|
stream->resp_hds_len = 0;
|
|
|
}
|
|
|
if(data_consumed) {
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] increase window by %zu",
|
|
|
- stream->id, data_consumed));
|
|
|
nghttp2_session_consume(ctx->h2, stream->id, data_consumed);
|
|
|
}
|
|
|
}
|
|
@@ -1813,8 +1812,15 @@ out:
|
|
|
*err = result;
|
|
|
nread = -1;
|
|
|
}
|
|
|
- DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_recv(len=%zu) -> %zd %d",
|
|
|
- stream->id, len, nread, *err));
|
|
|
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_recv(len=%zu) -> %zd %d, "
|
|
|
+ "buffered=%zu, window=%d/%d",
|
|
|
+ stream->id, len, nread, *err,
|
|
|
+ Curl_bufq_len(&stream->recvbuf),
|
|
|
+ nghttp2_session_get_stream_effective_recv_data_length(
|
|
|
+ ctx->h2, stream->id),
|
|
|
+ nghttp2_session_get_stream_effective_local_window_size(
|
|
|
+ ctx->h2, stream->id)));
|
|
|
+
|
|
|
CF_DATA_RESTORE(cf, save);
|
|
|
return nread;
|
|
|
}
|
|
@@ -2205,6 +2211,9 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
|
|
|
return CURLE_HTTP2;
|
|
|
}
|
|
|
|
|
|
+ if(!pause)
|
|
|
+ drain_stream(cf, data, stream);
|
|
|
+
|
|
|
/* make sure the window update gets sent */
|
|
|
result = h2_progress_egress(cf, data);
|
|
|
if(result)
|