lib: send rework

Curl_read/Curl_write clarifications

- replace `Curl_read()`, `Curl_write()` and `Curl_nwrite()` to 1clarify
  when and at what level they operate

- send/recv of transfer related data is now done via
  `Curl_xfer_send()/Curl_xfer_recv()` which no longer has
  socket/socketindex as parameter. It decides on the transfer setup of
  `conn->sockfd` and `conn->writesockfd` on which connection filter
  chain to operate.

- send/recv on a specific connection filter chain is done via
  `Curl_conn_send()/Curl_conn_recv()` which get the socket index as
  parameter.

- rename `Curl_setup_transfer()` to `Curl_xfer_setup()` for naming
  consistency

- clarify that the special CURLE_AGAIN handling to return `CURLE_OK`
  with length 0 only applies to `Curl_xfer_send()` and CURLE_AGAIN is
  returned by all other send() variants.

SingleRequest reshuffling

- move functions into request.[ch]
- differentiate between reset and free
- add Curl_req_done() to perform last actions
- add a send `bufq` to SingleRequest for future use in keeping upload data

Closes #12963
This commit is contained in:
Stefan Eissing 2024-02-14 12:09:32 +01:00 committed by Daniel Stenberg
parent b8ed0f8259
commit 5929822114
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
41 changed files with 687 additions and 488 deletions

View File

@ -201,6 +201,7 @@ LIB_CFILES = \
psl.c \
rand.c \
rename.c \
request.c \
rtsp.c \
select.c \
sendf.c \
@ -337,6 +338,7 @@ LIB_HFILES = \
psl.h \
rand.h \
rename.h \
request.h \
rtsp.h \
select.h \
sendf.h \

View File

@ -53,6 +53,7 @@
#include <hyper.h>
#include "urldata.h"
#include "cfilters.h"
#include "sendf.h"
#include "headers.h"
#include "transfer.h"
@ -74,7 +75,8 @@ typedef enum {
size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
uint8_t *buf, size_t buflen)
{
struct Curl_easy *data = userp;
struct hyp_io_ctx *io_ctx = userp;
struct Curl_easy *data = io_ctx->data;
struct connectdata *conn = data->conn;
CURLcode result;
ssize_t nread;
@ -82,7 +84,8 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
(void)ctx;
DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
result = Curl_conn_recv(data, io_ctx->sockindex,
(char *)buf, buflen, &nread);
if(result == CURLE_AGAIN) {
/* would block, register interest */
DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
@ -106,15 +109,14 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
size_t Curl_hyper_send(void *userp, hyper_context *ctx,
const uint8_t *buf, size_t buflen)
{
struct Curl_easy *data = userp;
struct connectdata *conn = data->conn;
struct hyp_io_ctx *io_ctx = userp;
struct Curl_easy *data = io_ctx->data;
CURLcode result;
ssize_t nwrote;
DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
if(!result && !nwrote)
result = CURLE_AGAIN;
result = Curl_conn_send(data, io_ctx->sockindex,
(void *)buf, buflen, &nwrote);
if(result == CURLE_AGAIN) {
DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
/* would block, register interest */
@ -885,7 +887,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
may be parts of the request that is not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
Curl_client_cleanup(data);
Curl_cw_reset(data);
/* Add collecting of headers written to client. For a new connection,
* we might have done that already, but reuse
@ -939,7 +941,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
/* tell Hyper how to read/write network data */
hyper_io_set_userdata(io, data);
h->io_ctx.data = data;
h->io_ctx.sockindex = FIRSTSOCKET;
hyper_io_set_userdata(io, &h->io_ctx);
hyper_io_set_read(io, Curl_hyper_recv);
hyper_io_set_write(io, Curl_hyper_send);
@ -1200,7 +1204,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
/* HTTP GET/HEAD download */
Curl_pgrsSetUploadSize(data, 0); /* nothing */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
}
conn->datastream = Curl_hyper_stream;
if(data->state.expect100header)

View File

@ -29,6 +29,11 @@
#include <hyper.h>
struct hyp_io_ctx {
struct Curl_easy *data;
int sockindex;
};
/* per-transfer data for the Hyper backend */
struct hyptransfer {
hyper_waker *write_waker;
@ -36,6 +41,7 @@ struct hyptransfer {
const hyper_executor *exec;
hyper_waker *exp100_waker;
hyper_waker *send_body_waker;
struct hyp_io_ctx io_ctx;
};
size_t Curl_hyper_recv(void *userp, hyper_context *ctx,

View File

@ -366,7 +366,6 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
{
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
char *linep;
size_t line_len;
int error, writetype;
@ -386,7 +385,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
/* Read one byte at a time to avoid a race condition. Wait at most one
second before looping to ensure continuous pgrsUpdates. */
result = Curl_read(data, tunnelsocket, &byte, 1, &nread);
result = Curl_conn_recv(data, cf->sockindex, &byte, 1, &nread);
if(result == CURLE_AGAIN)
/* socket buffer drained, return */
return CURLE_OK;
@ -593,7 +592,9 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
goto error;
}
/* tell Hyper how to read/write network data */
hyper_io_set_userdata(io, data);
h->io_ctx.data = data;
h->io_ctx.sockindex = cf->sockindex;
hyper_io_set_userdata(io, &h->io_ctx);
hyper_io_set_read(io, Curl_hyper_recv);
hyper_io_set_write(io, Curl_hyper_send);
conn->sockfd = tunnelsocket;
@ -1007,7 +1008,7 @@ out:
data->req.header = TRUE; /* assume header */
data->req.bytecount = 0;
data->req.ignorebody = FALSE;
Curl_client_cleanup(data);
Curl_cw_reset(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);

View File

@ -129,11 +129,17 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
case HAPROXY_SEND:
len = Curl_dyn_len(&ctx->data_out);
if(len > 0) {
ssize_t written = Curl_conn_send(data, cf->sockindex,
Curl_dyn_ptr(&ctx->data_out),
len, &result);
if(written < 0)
ssize_t written;
result = Curl_conn_send(data, cf->sockindex,
Curl_dyn_ptr(&ctx->data_out),
len, &written);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
written = 0;
}
else if(result)
goto out;
DEBUGASSERT(written >= 0);
Curl_dyn_tail(&ctx->data_out, len - (size_t)written);
if(Curl_dyn_len(&ctx->data_out) > 0) {
result = CURLE_OK;

View File

@ -168,38 +168,46 @@ void Curl_conn_close(struct Curl_easy *data, int index)
}
}
ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
size_t len, CURLcode *code)
ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
*code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
cf = cf->next;
}
if(cf) {
return cf->cft->do_recv(cf, data, buf, len, code);
ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
DEBUGASSERT(nread >= 0 || *code);
DEBUGASSERT(nread < 0 || !*code);
return nread;
}
failf(data, "recv: no filter connected");
*code = CURLE_FAILED_INIT;
return -1;
}
ssize_t Curl_conn_send(struct Curl_easy *data, int num,
const void *mem, size_t len, CURLcode *code)
ssize_t Curl_cf_send(struct Curl_easy *data, int num,
const void *mem, size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
*code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
cf = cf->next;
}
if(cf) {
return cf->cft->do_send(cf, data, mem, len, code);
ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, code);
DEBUGASSERT(nwritten >= 0 || *code);
DEBUGASSERT(nwritten < 0 || !*code || !len);
return nwritten;
}
failf(data, "send: no filter connected");
DEBUGASSERT(0);
@ -662,6 +670,58 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
return (result || n <= 0)? 1 : (size_t)n;
}
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
{
if(data && data->conn &&
sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
return SECONDARYSOCKET;
return FIRSTSOCKET;
}
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
char *buf, size_t blen, ssize_t *n)
{
CURLcode result = CURLE_OK;
ssize_t nread;
DEBUGASSERT(data->conn);
nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
DEBUGASSERT(nread >= 0 || result);
DEBUGASSERT(nread < 0 || !result);
*n = (nread >= 0)? (size_t)nread : 0;
return result;
}
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t blen,
ssize_t *pnwritten)
{
ssize_t nwritten;
CURLcode result = CURLE_OK;
struct connectdata *conn;
DEBUGASSERT(sockindex >= 0 && sockindex < 2);
DEBUGASSERT(pnwritten);
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
conn = data->conn;
#ifdef CURLDEBUG
{
/* Allow debug builds to override this logic to force short sends
*/
char *p = getenv("CURL_SMALLSENDS");
if(p) {
size_t altsize = (size_t)strtoul(p, NULL, 10);
if(altsize)
blen = CURLMIN(blen, altsize);
}
}
#endif
nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
DEBUGASSERT((nwritten >= 0) || result);
*pnwritten = nwritten;
return result;
}
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps)

View File

@ -405,8 +405,8 @@ void Curl_conn_adjust_pollset(struct Curl_easy *data,
* actuel number of bytes copied or a negative value on error.
* The error code is placed into `*code`.
*/
ssize_t Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, CURLcode *code);
ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, CURLcode *code);
/**
* Send `len` bytes of data from `buf` through the filter chain `sockindex`
@ -414,8 +414,8 @@ ssize_t Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf,
* or a negative value on error.
* The error code is placed into `*code`.
*/
ssize_t Curl_conn_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, CURLcode *code);
ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, CURLcode *code);
/**
* The easy handle `data` is being attached to `conn`. This does
@ -497,6 +497,30 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
int sockindex);
/**
* Get the index of the given socket in the connection's sockets.
* Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
* correct socket index.
*/
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
/*
* Receive data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
* Will return CURLE_AGAIN iff blocked on receiving.
*/
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
char *buf, size_t buffersize,
ssize_t *pnread);
/*
* Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
* Will return CURLE_AGAIN iff blocked on sending.
*/
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t blen,
ssize_t *pnwritten);
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps);

View File

@ -265,10 +265,10 @@ static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
if(data->state.upload) {
Curl_pgrsSetUploadSize(data, data->state.infilesize);
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
}
else
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
return CURLE_OK;
}

View File

@ -122,11 +122,10 @@ static char *unescape_word(const char *input)
}
/* sendf() sends formatted data to the server */
static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(3, 4);
static CURLcode sendf(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
const char *fmt, ...)
static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
{
ssize_t bytes_written;
size_t write_len;
@ -146,7 +145,7 @@ static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
for(;;) {
/* Write the buffer to the socket */
result = Curl_write(data, sockfd, sptr, write_len, &bytes_written);
result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
if(result)
break;
@ -178,8 +177,6 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
char *nthdef = NULL; /* This is not part of the protocol, but required
by RFC 2229 */
CURLcode result;
struct connectdata *conn = data->conn;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path;
@ -228,7 +225,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
goto error;
}
result = sendf(sockfd, data,
result = sendf(data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"MATCH "
"%s " /* database */
@ -243,7 +240,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
failf(data, "Failed sending DICT request");
goto error;
}
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
}
else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
@ -276,7 +273,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
goto error;
}
result = sendf(sockfd, data,
result = sendf(data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"DEFINE "
"%s " /* database */
@ -289,7 +286,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
failf(data, "Failed sending DICT request");
goto error;
}
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
}
else {
@ -302,7 +299,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
if(ppath[i] == ':')
ppath[i] = ' ';
}
result = sendf(sockfd, data,
result = sendf(data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"%s\r\n"
"QUIT\r\n", ppath);
@ -311,7 +308,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
goto error;
}
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
}
}

View File

@ -1038,7 +1038,7 @@ fail:
*/
void curl_easy_reset(struct Curl_easy *data)
{
Curl_free_request_state(data);
Curl_req_reset(&data->req, data);
/* zero out UserDefined data: */
Curl_freeset(data);
@ -1166,9 +1166,11 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
}
static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
static CURLcode easy_connection(struct Curl_easy *data,
struct connectdata **connp)
{
curl_socket_t sfd;
if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
@ -1178,9 +1180,9 @@ static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
return CURLE_UNSUPPORTED_PROTOCOL;
}
*sfd = Curl_getconnectinfo(data, connp);
sfd = Curl_getconnectinfo(data, connp);
if(*sfd == CURL_SOCKET_BAD) {
if(sfd == CURL_SOCKET_BAD) {
failf(data, "Failed to get recent socket");
return CURLE_UNSUPPORTED_PROTOCOL;
}
@ -1196,7 +1198,6 @@ static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
size_t *n)
{
curl_socket_t sfd;
CURLcode result;
ssize_t n1;
struct connectdata *c;
@ -1204,7 +1205,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
result = easy_connection(data, &sfd, &c);
result = easy_connection(data, &c);
if(result)
return result;
@ -1214,7 +1215,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
Curl_attach_connection(data, c);
*n = 0;
result = Curl_read(data, sfd, buffer, buflen, &n1);
result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1);
if(result)
return result;
@ -1226,11 +1227,10 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
#ifdef USE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
{
curl_socket_t sfd;
CURLcode result;
struct connectdata *c = NULL;
result = easy_connection(data, &sfd, &c);
result = easy_connection(data, &c);
if(result)
return result;
@ -1251,13 +1251,12 @@ CURLcode Curl_connect_only_attach(struct Curl_easy *data)
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
size_t buflen, ssize_t *n)
{
curl_socket_t sfd;
CURLcode result;
ssize_t n1;
struct connectdata *c = NULL;
SIGPIPE_VARIABLE(pipe_st);
result = easy_connection(data, &sfd, &c);
*n = 0;
result = easy_connection(data, &c);
if(result)
return result;
@ -1266,20 +1265,12 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
needs to be reattached */
Curl_attach_connection(data, c);
*n = 0;
sigpipe_ignore(data, &pipe_st);
result = Curl_write(data, sfd, buffer, buflen, &n1);
result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, n);
sigpipe_restore(&pipe_st);
if(n1 == -1)
if(result && result != CURLE_AGAIN)
return CURLE_SEND_ERROR;
/* detect EAGAIN */
if(!result && !n1)
return CURLE_AGAIN;
*n = n1;
return result;
}

View File

@ -151,7 +151,7 @@ static CURLcode wc_statemach(struct Curl_easy *data);
static void wc_data_dtor(void *ptr);
static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
static CURLcode ftp_readresp(struct Curl_easy *data,
curl_socket_t sockfd,
int sockindex,
struct pingpong *pp,
int *ftpcode,
size_t *size);
@ -581,12 +581,12 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
/* set the SO_SNDBUF for the secondary socket for those who need it */
Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, SECONDARYSOCKET);
}
else {
/* FTP download: */
Curl_setup_transfer(data, SECONDARYSOCKET,
conn->proto.ftpc.retr_size_saved, FALSE, -1);
Curl_xfer_setup(data, SECONDARYSOCKET,
conn->proto.ftpc.retr_size_saved, FALSE, -1);
}
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
@ -664,13 +664,13 @@ static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode ftp_readresp(struct Curl_easy *data,
curl_socket_t sockfd,
int sockindex,
struct pingpong *pp,
int *ftpcode, /* return the ftp-code if done */
size_t *size) /* size of the response */
{
int code;
CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size);
CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size);
#ifdef HAVE_GSSAPI
{
@ -805,7 +805,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
break;
}
}
result = ftp_readresp(data, sockfd, pp, ftpcode, &nread);
result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
if(result)
break;
@ -1725,7 +1725,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
infof(data, "File already completely uploaded");
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
/* Set ->transfer so that we won't get any error in
* ftp_done() because we didn't transfer anything! */
@ -2396,7 +2396,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
if(ftp->downloadsize == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
/* Set ->transfer so that we won't get any error in ftp_done()
@ -2803,7 +2803,6 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int ftpcode;
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
@ -2813,7 +2812,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
if(pp->sendleft)
return Curl_pp_flushsend(data, pp);
result = ftp_readresp(data, sock, pp, &ftpcode, &nread);
result = ftp_readresp(data, FIRSTSOCKET, pp, &ftpcode, &nread);
if(result)
return result;
@ -3813,7 +3812,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
}
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
@ -4415,7 +4414,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
if(ftp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
else if(!connected)
/* since we didn't connect now, we want do_more to get called */
conn->bits.do_more = TRUE;

View File

@ -185,7 +185,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
if(strlen(sel) < 1)
break;
result = Curl_nwrite(data, FIRSTSOCKET, sel, k, &amount);
result = Curl_xfer_send(data, sel, k, &amount);
if(!result) { /* Which may not have written it all! */
result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
if(result)
@ -227,7 +227,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
free(sel_org);
if(!result)
result = Curl_nwrite(data, FIRSTSOCKET, "\r\n", 2, &amount);
result = Curl_xfer_send(data, "\r\n", 2, &amount);
if(result) {
failf(data, "Failed sending Gopher request");
return result;
@ -236,7 +236,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
if(result)
return result;
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
return CURLE_OK;
}
#endif /* CURL_DISABLE_GOPHER */

View File

@ -1356,7 +1356,11 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
sendsize = (size_t)data->set.upload_buffer_size;
}
result = Curl_nwrite(data, sockindex, ptr, sendsize, &amount);
result = Curl_conn_send(data, sockindex, ptr, sendsize, &amount);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
amount = 0;
}
if(!result) {
/*
@ -2511,8 +2515,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
failf(data, "Failed sending PUT request");
else
/* prepare for transfer */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
http->postsize?FIRSTSOCKET:-1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE,
http->postsize?FIRSTSOCKET:-1);
if(result)
return result;
break;
@ -2534,7 +2538,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
failf(data, "Failed sending POST request");
else
/* setup variables for the upcoming transfer */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
break;
}
@ -2592,8 +2596,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
failf(data, "Failed sending POST request");
else
/* prepare for transfer */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
http->postsize?FIRSTSOCKET:-1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE,
http->postsize?FIRSTSOCKET:-1);
if(result)
return result;
@ -2735,8 +2739,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
if(result)
failf(data, "Failed sending HTTP POST request");
else
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
http->postdata?FIRSTSOCKET:-1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE,
http->postdata?FIRSTSOCKET:-1);
break;
default:
@ -2755,11 +2759,11 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
!(data->set.connect_only))
/* Set up the transfer for two-way since without CONNECT_ONLY set, this
request probably wants to send data too post upgrade */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
#endif
else
/* HTTP GET/HEAD download: */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
}
return result;

View File

@ -1213,14 +1213,14 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
if(data->req.bytecount == size)
/* The entire data is already transferred! */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
else {
/* IMAP download */
data->req.maxdownload = size;
/* force a recv/send check of this connection, as the data might've been
read off the socket already */
data->state.select_bits = CURL_CSELECT_IN;
Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, size, FALSE, -1);
}
}
else {
@ -1268,7 +1268,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* IMAP upload */
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
imap_state(data, IMAP_STOP);
@ -1299,7 +1299,6 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int imapcode;
struct imap_conn *imapc = &conn->proto.imapc;
struct pingpong *pp = &imapc->pp;
@ -1316,7 +1315,7 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
do {
/* Read the response from the server */
result = Curl_pp_readresp(data, sock, pp, &imapcode, &nread);
result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &imapcode, &nread);
if(result)
return result;
@ -1694,7 +1693,7 @@ static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
if(imap->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
return CURLE_OK;
}

View File

@ -52,6 +52,7 @@
#include "ftp.h"
#include "curl_gssapi.h"
#include "sendf.h"
#include "transfer.h"
#include "curl_krb5.h"
#include "warnless.h"
#include "strcase.h"
@ -90,8 +91,7 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
result = Curl_nwrite(data, FIRSTSOCKET, sptr, write_len,
&bytes_written);
result = Curl_xfer_send(data, sptr, write_len, &bytes_written);
#ifdef HAVE_GSSAPI
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = data_sec;
@ -470,7 +470,7 @@ socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len)
ssize_t nread = 0;
while(len > 0) {
nread = Curl_conn_recv(data, sockindex, to_p, len, &result);
result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
if(nread > 0) {
len -= nread;
to_p += nread;
@ -497,8 +497,8 @@ socket_write(struct Curl_easy *data, int sockindex, const void *to,
ssize_t written;
while(len > 0) {
written = Curl_conn_send(data, sockindex, to_p, len, &result);
if(written > 0) {
result = Curl_conn_send(data, sockindex, to_p, len, &written);
if(!result && written > 0) {
len -= written;
to_p += written;
}
@ -567,8 +567,11 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
*err = CURLE_OK;
/* Handle clear text response. */
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
return Curl_conn_recv(data, sockindex, buffer, len, err);
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
ssize_t nread;
*err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
return nread;
}
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;

View File

@ -749,7 +749,7 @@ quit:
FREE_ON_WINLDAP(host);
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
connclose(conn, "LDAP connection always disable reuse");
return result;

View File

@ -120,7 +120,7 @@ static CURLcode mqtt_send(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
ssize_t n;
result = Curl_nwrite(data, FIRSTSOCKET, buf, len, &n);
result = Curl_xfer_send(data, buf, len, &n);
if(result)
return result;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
@ -366,8 +366,7 @@ static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes)
ssize_t nread;
DEBUGASSERT(nbytes - rlen < sizeof(readbuf));
result = Curl_read(data, data->conn->sock[FIRSTSOCKET],
(char *)readbuf, nbytes - rlen, &nread);
result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread);
if(result)
return result;
DEBUGASSERT(nread >= 0);
@ -622,7 +621,6 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
ssize_t nread;
size_t remlen;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
@ -679,7 +677,7 @@ MQTT_SUBACK_COMING:
size_t rest = mq->npacket;
if(rest > sizeof(buffer))
rest = sizeof(buffer);
result = Curl_read(data, sockfd, buffer, rest, &nread);
result = Curl_xfer_recv(data, buffer, rest, &nread);
if(result) {
if(CURLE_AGAIN == result) {
infof(data, "EEEE AAAAGAIN");
@ -744,7 +742,6 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
struct mqtt_conn *mqtt = &conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
ssize_t nread;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
unsigned char byte;
*done = FALSE;
@ -762,7 +759,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
switch(mqtt->state) {
case MQTT_FIRST:
/* Read the initial byte only */
result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
result = Curl_xfer_recv(data, (char *)&mq->firstbyte, 1, &nread);
if(result)
break;
else if(!nread) {
@ -778,7 +775,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
FALLTHROUGH();
case MQTT_REMAINING_LENGTH:
do {
result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
result = Curl_xfer_recv(data, (char *)&byte, 1, &nread);
if(!nread)
break;
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);

View File

@ -706,9 +706,10 @@ static CURLcode multi_done(struct Curl_easy *data,
process_pending_handles(data->multi); /* connection / multiplex */
Curl_safefree(data->state.ulbuf);
if(!result)
result = Curl_req_done(&data->req, data, premature);
Curl_client_cleanup(data);
Curl_safefree(data->state.ulbuf);
CONNCACHE_LOCK(data);
Curl_detach_connection(data);
@ -1007,7 +1008,7 @@ static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
struct connectdata *conn = data->conn;
(void)socks;
/* Not using `conn->sockfd` as `Curl_setup_transfer()` initializes
/* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes
* that *after* the connect. */
if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */

View File

@ -916,7 +916,7 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
else {
lr->msgid = msgid;
data->req.p.ldap = lr;
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
}
}

View File

@ -199,8 +199,11 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
result = Curl_nwrite(data, FIRSTSOCKET, s, write_len, &bytes_written);
if(result)
result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, &bytes_written);
if(result == CURLE_AGAIN) {
bytes_written = 0;
}
else if(result)
return result;
#ifdef HAVE_GSSAPI
data_sec = conn->data_prot;
@ -251,7 +254,7 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
}
static CURLcode pingpong_read(struct Curl_easy *data,
curl_socket_t sockfd,
int sockindex,
char *buffer,
size_t buflen,
ssize_t *nread)
@ -261,7 +264,7 @@ static CURLcode pingpong_read(struct Curl_easy *data,
enum protection_level prot = data->conn->data_prot;
data->conn->data_prot = PROT_CLEAR;
#endif
result = Curl_read(data, sockfd, buffer, buflen, nread);
result = Curl_conn_recv(data, sockindex, buffer, buflen, nread);
#ifdef HAVE_GSSAPI
DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
data->conn->data_prot = (unsigned char)prot;
@ -275,7 +278,7 @@ static CURLcode pingpong_read(struct Curl_easy *data,
* Reads a piece of a server response.
*/
CURLcode Curl_pp_readresp(struct Curl_easy *data,
curl_socket_t sockfd,
int sockindex,
struct pingpong *pp,
int *code, /* return the server code if done */
size_t *size) /* size of the response */
@ -300,7 +303,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
ssize_t gotbytes = 0;
char buffer[900];
result = pingpong_read(data, sockfd, buffer, sizeof(buffer), &gotbytes);
result = pingpong_read(data, sockindex, buffer, sizeof(buffer), &gotbytes);
if(result == CURLE_AGAIN)
return CURLE_OK;
@ -396,9 +399,15 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
{
/* we have a piece of a command still left to send */
ssize_t written;
CURLcode result = Curl_nwrite(data, FIRSTSOCKET,
pp->sendthis + pp->sendsize - pp->sendleft,
pp->sendleft, &written);
CURLcode result;
result = Curl_conn_send(data, FIRSTSOCKET,
pp->sendthis + pp->sendsize - pp->sendleft,
pp->sendleft, &written);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
written = 0;
}
if(result)
return result;

View File

@ -132,7 +132,7 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
* Reads a piece of a server response.
*/
CURLcode Curl_pp_readresp(struct Curl_easy *data,
curl_socket_t sockfd,
int sockindex,
struct pingpong *pp,
int *code, /* return the server code if done */
size_t *size); /* size of the response */

View File

@ -934,7 +934,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
if(pop3->transfer == PPTRANSFER_BODY) {
/* POP3 download */
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
if(pp->overflow) {
/* The recv buffer contains data that is actually body content so send
@ -970,7 +970,6 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int pop3code;
struct pop3_conn *pop3c = &conn->proto.pop3c;
struct pingpong *pp = &pop3c->pp;
@ -987,7 +986,7 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
do {
/* Read the response from the server */
result = Curl_pp_readresp(data, sock, pp, &pop3code, &nread);
result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &pop3code, &nread);
if(result)
return result;

108
lib/request.c Normal file
View File

@ -0,0 +1,108 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 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
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#include "urldata.h"
#include "dynbuf.h"
#include "doh.h"
#include "request.h"
#include "sendf.h"
#include "url.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
CURLcode Curl_req_init(struct SingleRequest *req)
{
memset(req, 0, sizeof(*req));
Curl_bufq_init2(&req->sendbuf, UPLOADBUFFER_DEFAULT, 1,
BUFQ_OPT_SOFT_LIMIT);
return CURLE_OK;
}
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data)
{
req->start = Curl_now();
Curl_cw_reset(data);
return CURLE_OK;
}
CURLcode Curl_req_done(struct SingleRequest *req,
struct Curl_easy *data, bool aborted)
{
(void)req;
/* TODO: add flush handling for client output */
(void)aborted;
Curl_cw_reset(data);
return CURLE_OK;
}
void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data)
{
/* This is a bit ugly. `req->p` is a union and we assume we can
* free this safely without leaks. */
Curl_safefree(req->p.http);
Curl_safefree(req->newurl);
Curl_cw_reset(data);
Curl_bufq_reset(&req->sendbuf);
if(data->set.upload_buffer_size != req->sendbuf.chunk_size) {
Curl_bufq_free(&req->sendbuf);
Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
BUFQ_OPT_SOFT_LIMIT);
}
#ifndef CURL_DISABLE_DOH
if(req->doh) {
Curl_close(&req->doh->probe[0].easy);
Curl_close(&req->doh->probe[1].easy);
}
#endif
}
void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
{
/* This is a bit ugly. `req->p` is a union and we assume we can
* free this safely without leaks. */
Curl_safefree(req->p.http);
Curl_safefree(req->newurl);
Curl_bufq_free(&req->sendbuf);
Curl_cw_reset(data);
#ifndef CURL_DISABLE_DOH
if(req->doh) {
Curl_close(&req->doh->probe[0].easy);
Curl_close(&req->doh->probe[1].easy);
Curl_dyn_free(&req->doh->probe[0].serverdoh);
Curl_dyn_free(&req->doh->probe[1].serverdoh);
curl_slist_free_all(req->doh->headers);
Curl_safefree(req->doh);
}
#endif
}

192
lib/request.h Normal file
View File

@ -0,0 +1,192 @@
#ifndef HEADER_CURL_REQUEST_H
#define HEADER_CURL_REQUEST_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 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
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
/* This file is for lib internal stuff */
#include "curl_setup.h"
#include "bufq.h"
/* forward declarations */
struct UserDefined;
enum expect100 {
EXP100_SEND_DATA, /* enough waiting, just send the body now */
EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
EXP100_SENDING_REQUEST, /* still sending the request but will wait for
the 100 header once done with the request */
EXP100_FAILED /* used on 417 Expectation Failed */
};
enum upgrade101 {
UPGR101_INIT, /* default state */
UPGR101_WS, /* upgrade to WebSockets requested */
UPGR101_H2, /* upgrade to HTTP/2 requested */
UPGR101_RECEIVED, /* 101 response received */
UPGR101_WORKING /* talking upgraded protocol */
};
/*
* Request specific data in the easy handle (Curl_easy). Previously,
* these members were on the connectdata struct but since a conn struct may
* now be shared between different Curl_easys, we store connection-specific
* data here. This struct only keeps stuff that's interesting for *this*
* request, as it will be cleared between multiple ones
*/
struct SingleRequest {
curl_off_t size; /* -1 if unknown at this point */
curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
-1 means unlimited */
curl_off_t bytecount; /* total number of bytes read */
curl_off_t writebytecount; /* number of bytes written */
curl_off_t pendingheader; /* this many bytes left to send is actually
header and not body */
struct curltime start; /* transfer started at this time */
unsigned int headerbytecount; /* received server headers (not CONNECT
headers) */
unsigned int allheadercount; /* all received headers (server + CONNECT) */
unsigned int deductheadercount; /* this amount of bytes doesn't count when
we check if anything has been transferred
at the end of a connection. We use this
counter to make only a 100 reply (without
a following second response code) result
in a CURLE_GOT_NOTHING error code */
int headerline; /* counts header lines to better track the
first one */
curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' or
'RTSP/1.? XXX' line */
int keepon;
struct curltime start100; /* time stamp to wait for the 100 code from */
enum expect100 exp100; /* expect 100 continue state */
enum upgrade101 upgr101; /* 101 upgrade state */
/* Client Writer stack, handles trasnfer- and content-encodings, protocol
* checks, pausing by client callbacks. */
struct Curl_cwriter *writer_stack;
struct bufq sendbuf; /* data which needs to be send to the server */
time_t timeofdoc;
long bodywrites;
char *location; /* This points to an allocated version of the Location:
header data */
char *newurl; /* Set to the new URL to use when a redirect or a retry is
wanted */
/* 'upload_present' is used to keep a byte counter of how much data there is
still left in the buffer, aimed for upload. */
ssize_t upload_present;
/* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
buffer, so the next read should read from where this pointer points to,
and the 'upload_present' contains the number of bytes available at this
position */
char *upload_fromhere;
/* Allocated protocol-specific data. Each protocol handler makes sure this
points to data it needs. */
union {
struct FILEPROTO *file;
struct FTP *ftp;
struct HTTP *http;
struct IMAP *imap;
struct ldapreqinfo *ldap;
struct MQTT *mqtt;
struct POP3 *pop3;
struct RTSP *rtsp;
struct smb_request *smb;
struct SMTP *smtp;
struct SSHPROTO *ssh;
struct TELNET *telnet;
} p;
#ifndef CURL_DISABLE_DOH
struct dohdata *doh; /* DoH specific data for this request */
#endif
char fread_eof[2]; /* the body read callback (index 0) returned EOF or
the trailer read callback (index 1) returned EOF */
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;
#endif
BIT(header); /* incoming data has HTTP header */
BIT(content_range); /* set TRUE if Content-Range: was found */
BIT(download_done); /* set to TRUE when download is complete */
BIT(eos_written); /* iff EOS has been written to client */
BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
upload and we're uploading the last chunk */
BIT(ignorebody); /* we read a response-body but we ignore it! */
BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
204 or 304 */
BIT(chunk); /* if set, this is a chunked transfer-encoding */
BIT(ignore_cl); /* ignore content-length */
BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
on upload */
BIT(getheader); /* TRUE if header parsing is wanted */
BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
specific upload buffers. See readmoredata() in http.c
for details. */
BIT(no_body); /* the response has no body */
BIT(authneg); /* TRUE when the auth phase has started, which means
that we are creating a request with an auth header,
but it is not the final request in the auth
negotiation. */
};
/**
* Initialize the state of the request for first use.
*/
CURLcode Curl_req_init(struct SingleRequest *req);
/**
* The request is about to start.
*/
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data);
/**
* The request is done. If not aborted, make sure that buffers are
* flushed to the client.
* @param req the request
* @param data the transfer
* @param aborted TRUE iff the request was aborted/errored
*/
CURLcode Curl_req_done(struct SingleRequest *req,
struct Curl_easy *data, bool aborted);
/**
* Free the state of the request, not usable afterwards.
*/
void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data);
/**
* Reset the state of the request for new use, given the
* settings.
*/
void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data);
#endif /* HEADER_CURL_REQUEST_H */

View File

@ -310,7 +310,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
}
if(rtspreq == RTSPREQ_RECEIVE) {
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
return result;
}
@ -573,7 +573,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
return result;
}
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
/* Increment the CSeq on success */
data->state.rtsp_next_client_CSeq++;

View File

@ -61,79 +61,6 @@
static CURLcode do_init_stack(struct Curl_easy *data);
/*
* Curl_nwrite() is an internal write function that sends data to the
* server. Works with a socket index for the connection.
*
* If the write would block (CURLE_AGAIN), it returns CURLE_OK and
* (*nwritten == 0). Otherwise we return regular CURLcode value.
*/
CURLcode Curl_nwrite(struct Curl_easy *data,
int sockindex,
const void *buf,
size_t blen,
ssize_t *pnwritten)
{
ssize_t nwritten;
CURLcode result = CURLE_OK;
struct connectdata *conn;
DEBUGASSERT(sockindex >= 0 && sockindex < 2);
DEBUGASSERT(pnwritten);
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
conn = data->conn;
#ifdef CURLDEBUG
{
/* Allow debug builds to override this logic to force short sends
*/
char *p = getenv("CURL_SMALLSENDS");
if(p) {
size_t altsize = (size_t)strtoul(p, NULL, 10);
if(altsize)
blen = CURLMIN(blen, altsize);
}
}
#endif
nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
if(result == CURLE_AGAIN) {
nwritten = 0;
result = CURLE_OK;
}
else if(result) {
nwritten = -1; /* make sure */
}
else {
DEBUGASSERT(nwritten >= 0);
}
*pnwritten = nwritten;
return result;
}
/*
* Curl_write() is an internal write function that sends data to the
* server. Works with plain sockets, SCP, SSL or kerberos.
*
* If the write would block (CURLE_AGAIN), we return CURLE_OK and
* (*written == 0). Otherwise we return regular CURLcode value.
*/
CURLcode Curl_write(struct Curl_easy *data,
curl_socket_t sockfd,
const void *mem,
size_t len,
ssize_t *written)
{
struct connectdata *conn;
int num;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
conn = data->conn;
num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
return Curl_nwrite(data, num, mem, len, written);
}
/* Curl_client_write() sends data to the write callback(s)
The bit pattern defines to what "streams" to write to. Body and/or header.
@ -163,7 +90,7 @@ CURLcode Curl_client_write(struct Curl_easy *data,
return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
}
void Curl_client_cleanup(struct Curl_easy *data)
void Curl_cw_reset(struct Curl_easy *data)
{
struct Curl_cwriter *writer = data->req.writer_stack;
@ -499,40 +426,3 @@ void Curl_cwriter_remove_by_name(struct Curl_easy *data,
}
}
/*
* Internal read-from-socket function. This is meant to deal with plain
* sockets, SSL sockets and kerberos sockets.
*
* Returns a regular CURLcode value.
*/
CURLcode Curl_read(struct Curl_easy *data, /* transfer */
curl_socket_t sockfd, /* read from this socket */
char *buf, /* store read data here */
size_t sizerequested, /* max amount to read */
ssize_t *n) /* amount bytes read */
{
CURLcode result = CURLE_RECV_ERROR;
ssize_t nread = 0;
size_t bytesfromsocket = 0;
char *buffertofill = NULL;
struct connectdata *conn = data->conn;
/* Set 'num' to 0 or 1, depending on which socket that has been sent here.
If it is the second socket, we set num to 1. Otherwise to 0. This lets
us use the correct ssl handle. */
int num = (sockfd == conn->sock[SECONDARYSOCKET]);
*n = 0; /* reset amount to zero */
bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
buffertofill = buf;
nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
if(nread < 0)
goto out;
*n += nread;
result = CURLE_OK;
out:
return result;
}

View File

@ -61,7 +61,7 @@ CURLcode Curl_client_write(struct Curl_easy *data, int type, const char *ptr,
/**
* Free all resources related to client writing.
*/
void Curl_client_cleanup(struct Curl_easy *data);
void Curl_cw_reset(struct Curl_easy *data);
/**
* Client Writers - a chain passing transfer BODY data to the client.
@ -175,22 +175,4 @@ void Curl_cwriter_def_close(struct Curl_easy *data,
struct Curl_cwriter *writer);
/* internal read-function, does plain socket, SSL and krb4 */
CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
char *buf, size_t buffersize,
ssize_t *n);
/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
CURLcode Curl_write(struct Curl_easy *data,
curl_socket_t sockfd,
const void *mem, size_t len,
ssize_t *written);
/* internal write-function, using sockindex for connection destination */
CURLcode Curl_nwrite(struct Curl_easy *data,
int sockindex,
const void *buf,
size_t blen,
ssize_t *pnwritten);
#endif /* HEADER_CURL_SENDF_H */

View File

@ -485,7 +485,6 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
{
struct connectdata *conn = data->conn;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
struct smb_conn *smbc = &conn->proto.smbc;
char *buf = smbc->recv_buf;
ssize_t bytes_read;
@ -494,7 +493,7 @@ static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
size_t len = MAX_MESSAGE_SIZE - smbc->got;
CURLcode result;
result = Curl_read(data, sockfd, buf + smbc->got, len, &bytes_read);
result = Curl_xfer_recv(data, buf + smbc->got, len, &bytes_read);
if(result)
return result;
@ -568,8 +567,7 @@ static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
ssize_t bytes_written;
CURLcode result;
result = Curl_nwrite(data, FIRSTSOCKET, data->state.ulbuf,
len, &bytes_written);
result = Curl_xfer_send(data, data->state.ulbuf, len, &bytes_written);
if(result)
return result;
@ -594,9 +592,8 @@ static CURLcode smb_flush(struct Curl_easy *data)
if(!smbc->send_size)
return CURLE_OK;
result = Curl_nwrite(data, FIRSTSOCKET,
data->state.ulbuf + smbc->sent,
len, &bytes_written);
result = Curl_xfer_send(data, data->state.ulbuf + smbc->sent, len,
&bytes_written);
if(result)
return result;

View File

@ -1164,7 +1164,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* SMTP upload */
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
smtp_state(data, SMTP_STOP);
@ -1196,7 +1196,6 @@ static CURLcode smtp_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int smtpcode;
struct smtp_conn *smtpc = &conn->proto.smtpc;
struct pingpong *pp = &smtpc->pp;
@ -1212,7 +1211,7 @@ static CURLcode smtp_statemachine(struct Curl_easy *data,
do {
/* Read the response from the server */
result = Curl_pp_readresp(data, sock, pp, &smtpcode, &nread);
result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &smtpcode, &nread);
if(result)
return result;
@ -1434,7 +1433,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
return CURLE_OUT_OF_MEMORY;
/* Send the end of block data */
result = Curl_write(data, conn->writesockfd, eob, len, &bytes_written);
result = Curl_xfer_send(data, eob, len, &bytes_written);
if(result) {
free(eob);
return result;
@ -1595,7 +1594,7 @@ static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
if(smtp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
return CURLE_OK;
}

View File

@ -1270,8 +1270,8 @@ static CURLcode send_telnet_data(struct Curl_easy *data,
break;
default: /* write! */
bytes_written = 0;
result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written,
outlen - total_written, &bytes_written);
result = Curl_xfer_send(data, outbuf + total_written,
outlen - total_written, &bytes_written);
total_written += bytes_written;
break;
}
@ -1464,7 +1464,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
if(events.lNetworkEvents & FD_READ) {
/* read data from network */
result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread);
result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
/* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
@ -1545,7 +1545,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
default: /* read! */
if(pfd[0].revents & POLLIN) {
/* read data from network */
result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread);
result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
/* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
@ -1635,7 +1635,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
#endif
/* mark this as "no further transfer wanted" */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
return result;
}

View File

@ -1240,7 +1240,7 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
/* Tell curl we're done */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
}
else {
/* no timeouts to handle, check our socket */
@ -1263,7 +1263,7 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
/* Tell curl we're done */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
}
/* if rc == 0, then select() timed out */
}

View File

@ -448,7 +448,7 @@ static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
return 0;
}
*err = Curl_read(data, data->conn->sockfd, buf, blen, &nread);
*err = Curl_xfer_recv(data, buf, blen, &nread);
if(*err)
return -1;
DEBUGASSERT(nread >= 0);
@ -770,12 +770,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
that instead of reading more data */
}
if(!Curl_bufq_is_empty(&k->sendbuf)) {
DEBUGASSERT(0);
}
/* write to socket (send away data) */
result = Curl_write(data,
conn->writesockfd, /* socket to send to */
k->upload_fromhere, /* buffer pointer */
k->upload_present, /* buffer size */
&bytes_written); /* actually sent */
result = Curl_xfer_send(data,
k->upload_fromhere, /* buffer pointer */
k->upload_present, /* buffer size */
&bytes_written); /* actually sent */
if(result)
return result;
@ -1590,11 +1592,10 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
}
/*
* Curl_setup_transfer() is called to setup some basic properties for the
* Curl_xfer_setup() is called to setup some basic properties for the
* upcoming transfer.
*/
void
Curl_setup_transfer(
void Curl_xfer_setup(
struct Curl_easy *data, /* transfer */
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
@ -1610,6 +1611,7 @@ Curl_setup_transfer(
DEBUGASSERT(conn != NULL);
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
(http->sending == HTTPSEND_REQUEST));
@ -1727,3 +1729,51 @@ CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
(void)premature;
return Curl_cw_out_done(data);
}
CURLcode Curl_xfer_send(struct Curl_easy *data,
const void *buf, size_t blen,
ssize_t *pnwritten)
{
CURLcode result;
int sockindex;
if(!data || !data->conn)
return CURLE_FAILED_INIT;
/* FIXME: would like to enable this, but some protocols (MQTT) do not
* setup the transfer correctly, it seems
if(data->conn->writesockfd == CURL_SOCKET_BAD) {
failf(data, "transfer not setup for sending");
DEBUGASSERT(0);
return CURLE_SEND_ERROR;
} */
sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
(data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
result = Curl_conn_send(data, sockindex, buf, blen, pnwritten);
if(result == CURLE_AGAIN) {
result = CURLE_OK;
*pnwritten = 0;
}
return result;
}
CURLcode Curl_xfer_recv(struct Curl_easy *data,
char *buf, size_t blen,
ssize_t *pnrcvd)
{
int sockindex;
if(!data || !data->conn)
return CURLE_FAILED_INIT;
/* FIXME: would like to enable this, but some protocols (MQTT) do not
* setup the transfer correctly, it seems
if(data->conn->sockfd == CURL_SOCKET_BAD) {
failf(data, "transfer not setup for receiving");
DEBUGASSERT(0);
return CURLE_RECV_ERROR;
} */
sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) &&
(data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]));
if(data->set.buffer_size > 0 && (size_t)data->set.buffer_size < blen)
blen = (size_t)data->set.buffer_size;
return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
}

View File

@ -75,8 +75,7 @@ CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
bool is_eos, bool *done);
/* This sets up a forthcoming transfer */
void
Curl_setup_transfer (struct Curl_easy *data,
void Curl_xfer_setup(struct Curl_easy *data,
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */
@ -91,4 +90,22 @@ Curl_setup_transfer (struct Curl_easy *data,
*/
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature);
/**
* Send data on the socket/connection filter designated
* for transfer's outgoing data.
* Will return CURLE_OK on blocking with (*pnwritten == 0).
*/
CURLcode Curl_xfer_send(struct Curl_easy *data,
const void *buf, size_t blen,
ssize_t *pnwritten);
/**
* Receive data on the socket/connection filter designated
* for transfer's incoming data.
* Will return CURLE_AGAIN on blocking with (*pnrcvd == 0).
*/
CURLcode Curl_xfer_recv(struct Curl_easy *data,
char *buf, size_t blen,
ssize_t *pnrcvd);
#endif /* HEADER_CURL_TRANSFER_H */

View File

@ -261,7 +261,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
free(data->state.range);
/* freed here just in case DONE wasn't called */
Curl_free_request_state(data);
Curl_req_free(&data->req, data);
/* Close down all open SSL info and sessions */
Curl_ssl_close_all(data);
@ -269,10 +269,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.scratch);
Curl_ssl_free_certinfo(data);
/* Cleanup possible redirect junk */
free(data->req.newurl);
data->req.newurl = NULL;
if(data->state.referer_alloc) {
Curl_safefree(data->state.referer);
data->state.referer_alloc = FALSE;
@ -325,15 +321,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.proxyuser);
Curl_safefree(data->state.aptr.proxypasswd);
#ifndef CURL_DISABLE_DOH
if(data->req.doh) {
Curl_dyn_free(&data->req.doh->probe[0].serverdoh);
Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
curl_slist_free_all(data->req.doh->headers);
Curl_safefree(data->req.doh);
}
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
@ -519,9 +506,17 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
result = Curl_req_init(&data->req);
if(result) {
DEBUGF(fprintf(stderr, "Error: request init failed\n"));
free(data);
return result;
}
result = Curl_resolver_init(data, &data->state.async.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
Curl_req_free(&data->req, data);
free(data);
return result;
}
@ -545,6 +540,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
Curl_req_free(&data->req, data);
free(data);
data = NULL;
}
@ -2054,24 +2050,6 @@ static CURLcode setup_connection_internals(struct Curl_easy *data,
return CURLE_OK;
}
/*
* Curl_free_request_state() should free temp data that was allocated in the
* Curl_easy for this single request.
*/
void Curl_free_request_state(struct Curl_easy *data)
{
Curl_safefree(data->req.p.http);
Curl_safefree(data->req.newurl);
#ifndef CURL_DISABLE_DOH
if(data->req.doh) {
Curl_close(&data->req.doh->probe[0].easy);
Curl_close(&data->req.doh->probe[1].easy);
}
#endif
Curl_client_cleanup(data);
}
#ifndef CURL_DISABLE_PROXY
@ -3609,7 +3587,7 @@ static CURLcode create_conn(struct Curl_easy *data,
(void)conn->handler->done(data, result, FALSE);
goto out;
}
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
}
/* since we skip do_init() */
@ -3620,10 +3598,10 @@ static CURLcode create_conn(struct Curl_easy *data,
#endif
/* Setup filter for network connections */
conn->recv[FIRSTSOCKET] = Curl_conn_recv;
conn->send[FIRSTSOCKET] = Curl_conn_send;
conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
conn->send[SECONDARYSOCKET] = Curl_conn_send;
conn->recv[FIRSTSOCKET] = Curl_cf_recv;
conn->send[FIRSTSOCKET] = Curl_cf_send;
conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
conn->send[SECONDARYSOCKET] = Curl_cf_send;
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
/* Complete the easy's SSL configuration for connection cache matching */
@ -3866,7 +3844,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
*asyncp = FALSE; /* assume synchronous resolves by default */
/* init the single-transfer specific data */
Curl_free_request_state(data);
Curl_req_reset(&data->req, data);
memset(&data->req, 0, sizeof(struct SingleRequest));
data->req.size = data->req.maxdownload = -1;
data->req.no_body = data->set.opt_no_body;
@ -3935,12 +3913,14 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
/* in HTTP lingo, no body means using the HEAD request... */
data->state.httpreq = HTTPREQ_HEAD;
k->start = Curl_now(); /* start time */
result = Curl_req_start(&data->req, data);
if(result)
return result;
k->header = TRUE; /* assume header */
k->bytecount = 0;
k->ignorebody = FALSE;
Curl_client_cleanup(data);
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);

View File

@ -41,7 +41,6 @@ void Curl_disconnect(struct Curl_easy *data,
struct connectdata *, bool dead_connection);
CURLcode Curl_setup_conn(struct Curl_easy *data,
bool *protocol_done);
void Curl_free_request_state(struct Curl_easy *data);
CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);

View File

@ -143,6 +143,7 @@ typedef unsigned int curl_prot_t;
#include "splay.h"
#include "dynbuf.h"
#include "dynhds.h"
#include "request.h"
/* return the count of bytes sent, or -1 on error */
typedef ssize_t (Curl_send)(struct Curl_easy *data, /* transfer */
@ -616,22 +617,6 @@ struct easy_pollset {
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
};
enum expect100 {
EXP100_SEND_DATA, /* enough waiting, just send the body now */
EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
EXP100_SENDING_REQUEST, /* still sending the request but will wait for
the 100 header once done with the request */
EXP100_FAILED /* used on 417 Expectation Failed */
};
enum upgrade101 {
UPGR101_INIT, /* default state */
UPGR101_WS, /* upgrade to WebSockets requested */
UPGR101_H2, /* upgrade to HTTP/2 requested */
UPGR101_RECEIVED, /* 101 response received */
UPGR101_WORKING /* talking upgraded protocol */
};
enum doh_slots {
/* Explicit values for first two symbols so as to match hard-coded
* constants in existing code
@ -650,111 +635,6 @@ enum doh_slots {
DOH_PROBE_SLOTS
};
/*
* Request specific data in the easy handle (Curl_easy). Previously,
* these members were on the connectdata struct but since a conn struct may
* now be shared between different Curl_easys, we store connection-specific
* data here. This struct only keeps stuff that's interesting for *this*
* request, as it will be cleared between multiple ones
*/
struct SingleRequest {
curl_off_t size; /* -1 if unknown at this point */
curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
-1 means unlimited */
curl_off_t bytecount; /* total number of bytes read */
curl_off_t writebytecount; /* number of bytes written */
curl_off_t pendingheader; /* this many bytes left to send is actually
header and not body */
struct curltime start; /* transfer started at this time */
unsigned int headerbytecount; /* received server headers (not CONNECT
headers) */
unsigned int allheadercount; /* all received headers (server + CONNECT) */
unsigned int deductheadercount; /* this amount of bytes doesn't count when
we check if anything has been transferred
at the end of a connection. We use this
counter to make only a 100 reply (without
a following second response code) result
in a CURLE_GOT_NOTHING error code */
int headerline; /* counts header lines to better track the
first one */
curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' or
'RTSP/1.? XXX' line */
int keepon;
struct curltime start100; /* time stamp to wait for the 100 code from */
enum expect100 exp100; /* expect 100 continue state */
enum upgrade101 upgr101; /* 101 upgrade state */
/* Client Writer stack, handles trasnfer- and content-encodings, protocol
* checks, pausing by client callbacks. */
struct Curl_cwriter *writer_stack;
time_t timeofdoc;
long bodywrites;
char *location; /* This points to an allocated version of the Location:
header data */
char *newurl; /* Set to the new URL to use when a redirect or a retry is
wanted */
/* 'upload_present' is used to keep a byte counter of how much data there is
still left in the buffer, aimed for upload. */
ssize_t upload_present;
/* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
buffer, so the next read should read from where this pointer points to,
and the 'upload_present' contains the number of bytes available at this
position */
char *upload_fromhere;
/* Allocated protocol-specific data. Each protocol handler makes sure this
points to data it needs. */
union {
struct FILEPROTO *file;
struct FTP *ftp;
struct HTTP *http;
struct IMAP *imap;
struct ldapreqinfo *ldap;
struct MQTT *mqtt;
struct POP3 *pop3;
struct RTSP *rtsp;
struct smb_request *smb;
struct SMTP *smtp;
struct SSHPROTO *ssh;
struct TELNET *telnet;
} p;
#ifndef CURL_DISABLE_DOH
struct dohdata *doh; /* DoH specific data for this request */
#endif
char fread_eof[2]; /* the body read callback (index 0) returned EOF or
the trailer read callback (index 1) returned EOF */
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;
#endif
BIT(header); /* incoming data has HTTP header */
BIT(content_range); /* set TRUE if Content-Range: was found */
BIT(download_done); /* set to TRUE when download is complete */
BIT(eos_written); /* iff EOS has been written to client */
BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
upload and we're uploading the last chunk */
BIT(ignorebody); /* we read a response-body but we ignore it! */
BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
204 or 304 */
BIT(chunk); /* if set, this is a chunked transfer-encoding */
BIT(ignore_cl); /* ignore content-length */
BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
on upload */
BIT(getheader); /* TRUE if header parsing is wanted */
BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
specific upload buffers. See readmoredata() in http.c
for details. */
BIT(no_body); /* the response has no body */
BIT(authneg); /* TRUE when the auth phase has started, which means
that we are creating a request with an auth header,
but it is not the final request in the auth
negotiation. */
};
/*
* Specific protocol handler.
*/

View File

@ -1349,9 +1349,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
/* store this original bitmask setup to use later on if we can't
@ -1575,7 +1575,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->sftp_dir = NULL;
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
state(data, SSH_STOP);
break;
@ -1720,14 +1720,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
@ -1849,9 +1849,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
/* upload data */
Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, data->req.size, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
/* store this original bitmask setup to use later on if we can't
@ -1893,9 +1893,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/* download data */
bytecount = ssh_scp_request_get_size(sshc->scp_session);
data->req.maxdownload = (curl_off_t) bytecount;
Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns

View File

@ -2195,9 +2195,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
@ -2448,7 +2448,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshp->readdir_longentry);
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
state(data, SSH_STOP);
break;
@ -2590,14 +2590,14 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
@ -2741,9 +2741,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* upload data */
data->req.size = data->state.infilesize;
Curl_pgrsSetUploadSize(data, data->state.infilesize);
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
@ -2812,9 +2812,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* download data */
bytecount = (curl_off_t)sb.st_size;
data->req.maxdownload = (curl_off_t)sb.st_size;
Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
@ -3193,12 +3193,13 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer,
struct connectdata *conn = data->conn;
Curl_recv *backup = conn->recv[0];
struct ssh_conn *ssh = &conn->proto.sshc;
int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
/* swap in the TLS reader function for this call only, and then swap back
the SSH one again */
conn->recv[0] = ssh->tls_recv;
result = Curl_read(data, sock, buffer, length, &nread);
result = Curl_conn_recv(data, socknum, buffer, length, &nread);
conn->recv[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */
@ -3217,12 +3218,13 @@ static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
struct connectdata *conn = data->conn;
Curl_send *backup = conn->send[0];
struct ssh_conn *ssh = &conn->proto.sshc;
int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
/* swap in the TLS writer function for this call only, and then swap back
the SSH one again */
conn->send[0] = ssh->tls_send;
result = Curl_write(data, sock, buffer, length, &nwrite);
result = Curl_conn_send(data, socknum, buffer, length, &nwrite);
conn->send[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */

View File

@ -678,9 +678,9 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
@ -778,14 +778,14 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
Curl_xfer_setup(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
/* not set by Curl_xfer_setup to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns

View File

@ -1020,8 +1020,12 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
while(Curl_bufq_peek(&ws->sendbuf, &out, &outlen)) {
if(data->set.connect_only)
result = Curl_senddata(data, out, outlen, &n);
else
result = Curl_write(data, data->conn->writesockfd, out, outlen, &n);
else {
result = Curl_xfer_send(data, out, outlen, &n);
if(!result && !n && outlen)
result = CURLE_AGAIN;
}
if(result) {
if(result == CURLE_AGAIN) {
if(!complete) {
@ -1086,8 +1090,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
/* raw mode sends exactly what was requested, and this is from within
the write callback */
if(Curl_is_in_callback(data)) {
result = Curl_write(data, data->conn->writesockfd, buffer, buflen,
&nwritten);
result = Curl_xfer_send(data, buffer, buflen, &nwritten);
}
else
result = Curl_senddata(data, buffer, buflen, &nwritten);
@ -1104,7 +1107,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
return result;
/* TODO: the current design does not allow partial writes, afaict.
* It is not clear who the application is supposed to react. */
* It is not clear how the application is supposed to react. */
space = Curl_bufq_space(&ws->sendbuf);
DEBUGF(infof(data, "curl_ws_send(len=%zu), sendbuf len=%zu space %zu",
buflen, Curl_bufq_len(&ws->sendbuf), space));

View File

@ -84,8 +84,6 @@ UNITTEST_START
"Curl_free() did not set to NULL");
}
Curl_free_request_state(empty);
rc = Curl_close(&empty);
fail_unless(rc == CURLE_OK, "Curl_close() failed");