CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
stream_id, length, stream->body_eos, nread, result);
- if(nread == 0)
- return NGHTTP2_ERR_DEFERRED;
- if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf))
+ if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf)) {
*data_flags = NGHTTP2_DATA_FLAG_EOF;
-
- return nread;
+ return nread;
+ }
+ return (nread == 0)? NGHTTP2_ERR_DEFERRED : nread;
}
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
eos = TRUE;
}
result = Curl_xfer_send(data, buf, blen, eos, pnwritten);
- if(!result && *pnwritten) {
- if(hds_len)
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
- CURLMIN(hds_len, *pnwritten));
- if(*pnwritten > hds_len) {
- size_t body_len = *pnwritten - hds_len;
- Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
- data->req.writebytecount += body_len;
- Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+ if(!result) {
+ if(eos && (blen == *pnwritten))
+ data->req.eos_sent = TRUE;
+ if(*pnwritten) {
+ if(hds_len)
+ Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
+ CURLMIN(hds_len, *pnwritten));
+ if(*pnwritten > hds_len) {
+ size_t body_len = *pnwritten - hds_len;
+ Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
+ data->req.writebytecount += body_len;
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+ }
}
}
return result;
return Curl_xfer_flush(data);
}
- if(!data->req.upload_done && data->req.eos_read &&
- Curl_bufq_is_empty(&data->req.sendbuf)) {
+ if(data->req.eos_read && !data->req.eos_sent) {
+ char tmp;
+ size_t nwritten;
+ result = xfer_send(data, &tmp, 0, 0, &nwritten);
+ if(result)
+ return result;
+ DEBUGASSERT(data->req.eos_sent);
+ }
+
+ if(!data->req.upload_done && data->req.eos_read && data->req.eos_sent) {
+ DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
if(data->req.shutdown) {
bool done;
result = Curl_xfer_send_shutdown(data, &done);
BIT(download_done); /* set to TRUE when download is complete */
BIT(eos_written); /* iff EOS has been written to client */
BIT(eos_read); /* iff EOS has been read from the client */
+ BIT(eos_sent); /* iff EOS has been sent to the server */
BIT(rewind_read); /* iff reader needs rewind at next start */
BIT(upload_done); /* set to TRUE when all request data has been sent */
BIT(upload_aborted); /* set to TRUE when upload was aborted. Will also
else if(!result && *pnwritten)
data->info.request_size += *pnwritten;
- DEBUGF(infof(data, "Curl_xfer_send(len=%zu) -> %d, %zu",
- blen, result, *pnwritten));
+ DEBUGF(infof(data, "Curl_xfer_send(len=%zu, eos=%d) -> %d, %zu",
+ blen, eos, result, *pnwritten));
return result;
}
respdata = open(curl.response_file(i)).readlines()
assert respdata == indata
+ # upload from stdin, issue #14870
+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
+ @pytest.mark.parametrize("indata", [
+ '', '1', '123\n456andsomething\n\n'
+ ])
+ def test_07_14_upload_stdin(self, env: Env, httpd, nghttpx, proto, indata):
+ if proto == 'h3' and not env.have_h3():
+ pytest.skip("h3 not supported")
+ if proto == 'h3' and env.curl_uses_lib('msh3'):
+ pytest.skip("msh3 stalls here")
+ count = 1
+ curl = CurlClient(env=env)
+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-{count-1}]'
+ r = curl.http_put(urls=[url], data=indata, alpn_proto=proto)
+ r.check_stats(count=count, http_status=200, exitcode=0)
+ for i in range(count):
+ respdata = open(curl.response_file(i)).readlines()
+ assert respdata == [f'{len(indata)}']
+
# upload data parallel, check that they were echoed
@pytest.mark.parametrize("proto", ['h2', 'h3'])
def test_07_20_upload_parallel(self, env: Env, httpd, nghttpx, repeat, proto):
'--expect100-timeout', f'{read_delay-1}'
])
r.check_stats(count=1, http_status=200, exitcode=0)
+
+ # speed limited on echo handler
+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
+ def test_07_51_echo_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat):
+ if proto == 'h3' and not env.have_h3():
+ pytest.skip("h3 not supported")
+ count = 1
+ fdata = os.path.join(env.gen_dir, 'data-100k')
+ speed_limit = 50 * 1024
+ curl = CurlClient(env=env)
+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]'
+ r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto,
+ with_headers=True, extra_args=[
+ '--limit-rate', f'{speed_limit}'
+ ])
+ r.check_response(count=count, http_status=200)
+ up_speed = r.stats[0]['speed_upload']
+ assert (speed_limit * 0.5) <= up_speed <= (speed_limit * 1.5), f'{r.stats[0]}'