transfer: upload performance; avoid tiny send

Append to the upload buffer when only small amount remains in buffer
rather than performing a separate tiny send to empty buffer.

Avoid degenerative upload behavior which might cause curl to send mostly
1-byte DATA frames after exhausing the h2 send window size

Related discussion: https://github.com/nghttp2/nghttp2/issues/1722

Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
Closes #8965
This commit is contained in:
Glenn Strauss 2022-06-06 13:02:30 -04:00 коммит произвёл Daniel Stenberg
Родитель aea8ac14df
Коммит 7f43f3dc59
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 5CC908FDB71E12C2
3 изменённых файлов: 35 добавлений и 10 удалений

Просмотреть файл

@ -1820,7 +1820,9 @@ static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
return result;
}
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread)
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
const ssize_t nread,
const ssize_t offset)
{
/* When sending a SMTP payload we must detect CRLF. sequences making sure
they are sent as CRLF.. instead, as a . on the beginning of a line will
@ -1854,7 +1856,9 @@ CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread)
/* This loop can be improved by some kind of Boyer-Moore style of
approach but that is saved for later... */
for(i = 0, si = 0; i < nread; i++) {
if(offset)
memcpy(scratch, data->req.upload_fromhere, offset);
for(i = offset, si = offset; i < nread; i++) {
if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
smtp->eob++;

Просмотреть файл

@ -93,6 +93,8 @@ extern const struct Curl_handler Curl_handler_smtps;
#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
#define SMTP_EOB_REPL_LEN 4
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread);
CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
const ssize_t nread,
const ssize_t offset);
#endif /* HEADER_CURL_SMTP_H */

Просмотреть файл

@ -899,6 +899,9 @@ static void win_update_buffer_size(curl_socket_t sockfd)
#define win_update_buffer_size(x)
#endif
#define curl_upload_refill_watermark(data) \
((ssize_t)((data)->set.upload_buffer_size >> 5))
/*
* Send data to upload to the server, when the socket is writable.
*/
@ -920,13 +923,25 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
do {
curl_off_t nbody;
ssize_t offset = 0;
if(0 != k->upload_present &&
k->upload_present < curl_upload_refill_watermark(data) &&
!k->upload_chunky &&/*(variable sized chunked header; append not safe)*/
!k->upload_done && /*!(k->upload_done once k->upload_present sent)*/
!(k->writebytecount + k->upload_present - k->pendingheader ==
data->state.infilesize)) {
offset = k->upload_present;
}
/* only read more data if there's no upload data already
present in the upload buffer */
if(0 == k->upload_present) {
present in the upload buffer, or if appending to upload buffer */
if(0 == k->upload_present || offset) {
result = Curl_get_upload_buffer(data);
if(result)
return result;
if(offset && k->upload_fromhere != data->state.ulbuf)
memmove(data->state.ulbuf, k->upload_fromhere, offset);
/* init the "upload from here" pointer */
k->upload_fromhere = data->state.ulbuf;
@ -959,12 +974,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
sending_http_headers = FALSE;
}
result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
k->upload_fromhere += offset;
result = Curl_fillreadbuffer(data, data->set.upload_buffer_size-offset,
&fillcount);
k->upload_fromhere -= offset;
if(result)
return result;
nread = fillcount;
nread = offset + fillcount;
}
else
nread = 0; /* we're done uploading/reading */
@ -1006,7 +1023,9 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
* That means the hex values for ASCII CR (0x0d) & LF (0x0a)
* must be used instead of the escape sequences \r & \n.
*/
for(i = 0, si = 0; i < nread; i++, si++) {
if(offset)
memcpy(data->state.scratch, k->upload_fromhere, offset);
for(i = offset, si = offset; i < nread; i++, si++) {
if(k->upload_fromhere[i] == 0x0a) {
data->state.scratch[si++] = 0x0d;
data->state.scratch[si] = 0x0a;
@ -1036,12 +1055,12 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
#ifndef CURL_DISABLE_SMTP
if(conn->handler->protocol & PROTO_FAMILY_SMTP) {
result = Curl_smtp_escape_eob(data, nread);
result = Curl_smtp_escape_eob(data, nread, offset);
if(result)
return result;
}
#endif /* CURL_DISABLE_SMTP */
} /* if 0 == k->upload_present */
} /* if 0 == k->upload_present or appended to upload buffer */
else {
/* We have a partial buffer left from a previous "round". Use
that instead of reading more data */