curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
- int result;
+ int socketstate = 0;
timediff_t timeout_ms;
ssize_t nread;
int ftpcode;
+ bool response = FALSE;
*received = FALSE;
}
/* First check whether there is a cached response from server */
- if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
+ if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) {
/* Data connection could not be established, let's return */
infof(data, "There is negative response in cache while serv connect");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
- result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
+ if(pp->overflow)
+ /* there is pending control data still in the buffer to read */
+ response = TRUE;
+ else
+ socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
/* see if the connection request is already here */
- switch(result) {
+ switch(socketstate) {
case -1: /* error */
/* let's die here */
failf(data, "Error while waiting for server connect");
case 0: /* Server connect is not received yet */
break; /* loop */
default:
-
- if(result & CURL_CSELECT_IN2) {
+ if(socketstate & CURL_CSELECT_IN2) {
infof(data, "Ready to accept data connection from server");
*received = TRUE;
}
- else if(result & CURL_CSELECT_IN) {
- infof(data, "Ctrl conn has data while waiting for data conn");
- (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
-
- if(ftpcode/100 > 3)
- return CURLE_FTP_ACCEPT_FAILED;
+ else if(socketstate & CURL_CSELECT_IN)
+ response = TRUE;
+ break;
+ }
+ if(response) {
+ infof(data, "Ctrl conn has data while waiting for data conn");
+ (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
- return CURLE_WEIRD_SERVER_REPLY;
- }
+ if(ftpcode/100 > 3)
+ return CURLE_FTP_ACCEPT_FAILED;
- break;
- } /* switch() */
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
return CURLE_OK;
}
#ifdef HAVE_GSSAPI
{
struct connectdata *conn = data->conn;
- char * const buf = data->state.buffer;
+ char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
/* handle the security-oriented responses 6xx ***/
switch(code) {
*
*/
- if(pp->cache && (cache_skip < 2)) {
+ if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
/*
* There's a cache left since before. We then skipping the wait for
* socket action, unless this is the same cache like the previous round
if(result)
break;
- if(!nread && pp->cache)
+ if(!nread && Curl_dyn_len(&pp->recvbuf))
/* bump cache skip counter as on repeated skips we must wait for more
data */
cache_skip++;
struct Curl_dns_entry *addr = NULL;
enum resolve_t rc;
unsigned short connectport; /* the local port connect() should use! */
- char *str = &data->state.buffer[4]; /* start on the first letter */
+ struct pingpong *pp = &ftpc->pp;
+ char *str =
+ Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */
/* if we come here again, make sure the former name is cleared */
Curl_safefree(ftpc->newhost);
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
- if(ftp_213_date(&data->state.buffer[4],
- &year, &month, &day, &hour, &minute, &second)) {
+ struct pingpong *pp = &ftpc->pp;
+ char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4;
+ if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
msnprintf(timebuf, sizeof(timebuf),
{
CURLcode result = CURLE_OK;
curl_off_t filesize = -1;
- char *buf = data->state.buffer;
+ char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
+ size_t len = data->conn->proto.ftpc.pp.nfinal;
/* get the size from the ascii string: */
if(ftpcode == 213) {
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
- char *fdigit = strchr(start, '\r');
+ char *fdigit = memchr(start, '\r', len);
if(fdigit) {
- do
+ fdigit--;
+ if(*fdigit == '\n')
+ fdigit--;
+ while(ISDIGIT(fdigit[-1]) && (fdigit > start))
fdigit--;
- while(ISDIGIT(*fdigit) && (fdigit > start));
- if(!ISDIGIT(*fdigit))
- fdigit++;
}
else
fdigit = start;
*
* Example D above makes this parsing a little tricky */
char *bytes;
- char *buf = data->state.buffer;
+ char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
bytes = strstr(buf, " bytes");
if(bytes) {
long in = (long)(--bytes-buf);
case FTP_AUTH:
/* we have gotten the response to a previous AUTH command */
- if(pp->cache_size)
+ if(pp->overflow)
return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
/* RFC2228 (page 5) says:
case FTP_PWD:
if(ftpcode == 257) {
- char *ptr = &data->state.buffer[4]; /* start on the first letter */
- const size_t buf_size = data->set.buffer_size;
+ char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
+ letter */
bool entry_extracted = FALSE;
struct dynbuf out;
Curl_dyn_init(&out, 1000);
*/
/* scan for the first double-quote for non-standard responses */
- while(ptr < &data->state.buffer[buf_size]
- && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
+ while(*ptr != '\n' && *ptr != '\0' && *ptr != '"')
ptr++;
if('\"' == *ptr) {
case FTP_SYST:
if(ftpcode == 215) {
- char *ptr = &data->state.buffer[4]; /* start on the first letter */
+ char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
+ letter */
char *os;
char *start;
conn->bits.ftp_use_control_ssl = TRUE;
}
- Curl_pp_setup(pp); /* once per transfer */
- Curl_pp_init(data, pp); /* init the generic pingpong data */
+ Curl_pp_init(pp); /* once per transfer */
/* When we connect, we start in the state where we await the 220
response */
*/
static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = data->state.buffer;
- size_t len = strlen(message);
+ char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+ size_t len = data->conn->proto.imapc.pp.nfinal;
if(len > 2) {
/* Find the start of the message */
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct imap_conn *imapc = &conn->proto.imapc;
- const char *line = data->state.buffer;
+ const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf);
(void)instate; /* no use for this yet */
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.imapc.pp.cache_size)
+ if(data->conn->proto.imapc.pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
if(imapcode != IMAP_RESP_OK) {
imapstate instate)
{
CURLcode result = CURLE_OK;
- char *line = data->state.buffer;
- size_t len = strlen(line);
+ char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+ size_t len = data->conn->proto.imapc.pp.nfinal;
(void)instate; /* No use for this yet */
- if(imapcode == '*') {
- /* Temporarily add the LF character back and send as body to the client */
- line[len] = '\n';
- result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
- line[len] = '\0';
- }
+ if(imapcode == '*')
+ result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
else if(imapcode != IMAP_RESP_OK)
result = CURLE_QUOTE_ERROR;
else
struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
struct imap_conn *imapc = &conn->proto.imapc;
- const char *line = data->state.buffer;
+ const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
(void)instate; /* no use for this yet */
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
struct pingpong *pp = &imapc->pp;
- const char *ptr = data->state.buffer;
+ const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+ size_t len = data->conn->proto.imapc.pp.nfinal;
bool parsed = FALSE;
curl_off_t size = 0;
/* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
the continuation data contained within the curly brackets */
- while(*ptr && (*ptr != '{'))
- ptr++;
-
- if(*ptr == '{') {
+ ptr = memchr(ptr, '{', len);
+ if(ptr) {
char *endptr;
- if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
- if(endptr - ptr > 1 && endptr[0] == '}' &&
- endptr[1] == '\r' && endptr[2] == '\0')
- parsed = TRUE;
- }
+ if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
+ (endptr - ptr > 1 && *endptr == '}'))
+ parsed = TRUE;
}
if(parsed) {
size);
Curl_pgrsSetDownloadSize(data, size);
- if(pp->cache) {
- /* At this point there is a bunch of data in the header "cache" that is
- actually body content, send it as body and then skip it. Do note
- that there may even be additional "headers" after the body. */
- size_t chunk = pp->cache_size;
+ if(pp->overflow) {
+ /* At this point there is a data in the receive buffer that is body
+ content, send it as body and then skip it. Do note that there may
+ even be additional "headers" after the body. */
+ size_t chunk = pp->overflow;
+
+ /* keep only the overflow */
+ Curl_dyn_tail(&pp->recvbuf, chunk);
+ pp->nfinal = 0; /* done */
if(chunk > (size_t)size)
/* The conversion from curl_off_t to size_t is always fine here */
imap_state(data, IMAP_STOP);
return CURLE_OK;
}
- result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk);
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&pp->recvbuf), chunk);
if(result)
return result;
infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
" bytes are left for transfer", chunk, size - chunk);
- /* Have we used the entire cache or just part of it?*/
- if(pp->cache_size > chunk) {
- /* Only part of it so shrink the cache to fit the trailing data */
- memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
- pp->cache_size -= chunk;
+ /* Have we used the entire overflow or just part of it?*/
+ if(pp->overflow > chunk) {
+ /* remember the remaining trailing overflow data */
+ pp->overflow -= chunk;
+ Curl_dyn_tail(&pp->recvbuf, pp->overflow);
}
else {
+ pp->overflow = 0; /* handled */
/* Free the cache */
- Curl_safefree(pp->cache);
-
- /* Reset the cache size */
- pp->cache_size = 0;
+ Curl_dyn_reset(&pp->recvbuf);
}
}
Curl_sasl_init(&imapc->sasl, data, &saslimap);
Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
- /* Initialise the pingpong layer */
- Curl_pp_setup(pp);
- Curl_pp_init(data, pp);
+ Curl_pp_init(pp);
/* Parse the URL options */
result = imap_parse_url_options(conn);
if(Curl_conn_data_pending(data, FIRSTSOCKET))
rc = 1;
- else if(Curl_pp_moredata(pp))
+ else if(pp->overflow)
/* We are receiving and there is data in the cache so just read it */
rc = 1;
else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
}
/* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp)
+void Curl_pp_init(struct pingpong *pp)
{
- DEBUGASSERT(data);
pp->nread_resp = 0;
- pp->linestart_resp = data->state.buffer;
- pp->pending_resp = TRUE;
pp->response = Curl_now(); /* start response time-out now! */
-}
-
-/* setup for the coming transfer */
-void Curl_pp_setup(struct pingpong *pp)
-{
+ pp->pending_resp = TRUE;
Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
+ Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
}
/***********************************************************************
if(result)
return result;
+ pp->pending_resp = TRUE;
write_len = Curl_dyn_len(&pp->sendbuf);
s = Curl_dyn_ptr(&pp->sendbuf);
- Curl_pp_init(data, pp);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
return result;
}
+static CURLcode pingpong_read(struct Curl_easy *data,
+ curl_socket_t sockfd,
+ char *buffer,
+ size_t buflen,
+ ssize_t *nread)
+{
+ CURLcode result;
+#ifdef HAVE_GSSAPI
+ enum protection_level prot = data->conn->data_prot;
+ data->conn->data_prot = PROT_CLEAR;
+#endif
+ result = Curl_read(data, sockfd, buffer, buflen, nread);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
+ data->conn->data_prot = (unsigned char)prot;
+#endif
+ return result;
+}
+
/*
* Curl_pp_readresp()
*
int *code, /* return the server code if done */
size_t *size) /* size of the response */
{
- ssize_t perline; /* count bytes per line */
- bool keepon = TRUE;
- ssize_t gotbytes;
- char *ptr;
struct connectdata *conn = data->conn;
- char * const buf = data->state.buffer;
CURLcode result = CURLE_OK;
*code = 0; /* 0 for errors or not done */
*size = 0;
- ptr = buf + pp->nread_resp;
+ if(pp->nfinal) {
+ /* a previous call left this many bytes in the beginning of the buffer as
+ that was the final line; now ditch that */
+ size_t full = Curl_dyn_len(&pp->recvbuf);
- /* number of bytes in the current line, so far */
- perline = (ssize_t)(ptr-pp->linestart_resp);
+ /* trim off the "final" leading part */
+ Curl_dyn_tail(&pp->recvbuf, full - pp->nfinal);
- while((pp->nread_resp < (size_t)data->set.buffer_size) &&
- (keepon && !result)) {
+ pp->nfinal = 0; /* now gone */
+ }
+ if(!pp->overflow) {
+ ssize_t gotbytes = 0;
+ char buffer[900];
- if(pp->cache) {
- /* we had data in the "cache", copy that instead of doing an actual
- * read
- *
- * pp->cache_size is cast to ssize_t here. This should be safe, because
- * it would have been populated with something of size int to begin
- * with, even though its datatype may be larger than an int.
- */
- if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) {
- failf(data, "cached response data too big to handle");
- return CURLE_WEIRD_SERVER_REPLY;
- }
- memcpy(ptr, pp->cache, pp->cache_size);
- gotbytes = (ssize_t)pp->cache_size;
- free(pp->cache); /* free the cache */
- pp->cache = NULL; /* clear the pointer */
- pp->cache_size = 0; /* zero the size just in case */
- }
- else {
-#ifdef HAVE_GSSAPI
- enum protection_level prot = conn->data_prot;
- conn->data_prot = PROT_CLEAR;
-#endif
- DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <=
- (buf + data->set.buffer_size + 1));
- result = Curl_read(data, sockfd, ptr,
- data->set.buffer_size - pp->nread_resp,
- &gotbytes);
-#ifdef HAVE_GSSAPI
- DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
- conn->data_prot = (unsigned char)prot;
-#endif
- if(result == CURLE_AGAIN)
- return CURLE_OK; /* return */
+ result = pingpong_read(data, sockfd, buffer, sizeof(buffer), &gotbytes);
+ if(result == CURLE_AGAIN)
+ return CURLE_OK;
- if(result)
- /* Set outer result variable to this error. */
- keepon = FALSE;
- }
+ if(result)
+ return result;
- if(!keepon)
- ;
- else if(gotbytes <= 0) {
- keepon = FALSE;
- result = CURLE_RECV_ERROR;
+ if(gotbytes <= 0) {
failf(data, "response reading failed (errno: %d)", SOCKERRNO);
+ return CURLE_RECV_ERROR;
}
- else {
- /* we got a whole chunk of data, which can be anything from one
- * byte to a set of lines and possible just a piece of the last
- * line */
- ssize_t i;
- ssize_t clipamount = 0;
- bool restart = FALSE;
-
- data->req.headerbytecount += (unsigned int)gotbytes;
-
- pp->nread_resp += gotbytes;
- for(i = 0; i < gotbytes; ptr++, i++) {
- perline++;
- if(*ptr == '\n') {
- /* a newline is CRLF in pp-talk, so the CR is ignored as
- the line isn't really terminated until the LF comes */
-
- /* output debug output if that is requested */
+
+ result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes);
+ if(result)
+ return result;
+
+ data->req.headerbytecount += (unsigned int)gotbytes;
+
+ pp->nread_resp += gotbytes;
+ }
+
+ do {
+ char *line = Curl_dyn_ptr(&pp->recvbuf);
+ char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
+ if(nl) {
+ /* a newline is CRLF in pp-talk, so the CR is ignored as
+ the line isn't really terminated until the LF comes */
+ size_t length = nl - line + 1;
+
+ /* output debug output if that is requested */
#ifdef HAVE_GSSAPI
- if(!conn->sec_complete)
+ if(!conn->sec_complete)
#endif
- Curl_debug(data, CURLINFO_HEADER_IN,
- pp->linestart_resp, (size_t)perline);
-
- /*
- * We pass all response-lines to the callback function registered
- * for "headers". The response lines can be seen as a kind of
- * headers.
- */
- result = Curl_client_write(data, CLIENTWRITE_INFO,
- pp->linestart_resp, perline);
- if(result)
- return result;
-
- if(pp->endofresp(data, conn, pp->linestart_resp, perline, code)) {
- /* This is the end of the last line, copy the last line to the
- start of the buffer and null-terminate, for old times sake */
- size_t n = ptr - pp->linestart_resp;
- memmove(buf, pp->linestart_resp, n);
- buf[n] = 0; /* null-terminate */
- keepon = FALSE;
- pp->linestart_resp = ptr + 1; /* advance pointer */
- i++; /* skip this before getting out */
-
- *size = pp->nread_resp; /* size of the response */
- pp->nread_resp = 0; /* restart */
- break;
- }
- perline = 0; /* line starts over here */
- pp->linestart_resp = ptr + 1;
- }
- }
+ Curl_debug(data, CURLINFO_HEADER_IN, line, length);
- if(!keepon && (i != gotbytes)) {
- /* We found the end of the response lines, but we didn't parse the
- full chunk of data we have read from the server. We therefore need
- to store the rest of the data to be checked on the next invoke as
- it may actually contain another end of response already! */
- clipamount = gotbytes - i;
- restart = TRUE;
- DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
- "server response left",
- (int)clipamount));
- }
- else if(keepon) {
-
- if((perline == gotbytes) &&
- (gotbytes > (ssize_t)data->set.buffer_size/2)) {
- /* We got an excessive line without newlines and we need to deal
- with it. We keep the first bytes of the line then we throw
- away the rest. */
- infof(data, "Excessive server response line length received, "
- "%zd bytes. Stripping", gotbytes);
- restart = TRUE;
-
- /* we keep 40 bytes since all our pingpong protocols are only
- interested in the first piece */
- clipamount = 40;
- }
- else if(pp->nread_resp > (size_t)data->set.buffer_size/2) {
- /* We got a large chunk of data and there's potentially still
- trailing data to take care of, so we put any such part in the
- "cache", clear the buffer to make space and restart. */
- clipamount = perline;
- restart = TRUE;
- }
- }
- else if(i == gotbytes)
- restart = TRUE;
-
- if(clipamount) {
- pp->cache_size = clipamount;
- pp->cache = Curl_memdup(pp->linestart_resp, pp->cache_size);
- if(!pp->cache)
- return CURLE_OUT_OF_MEMORY;
- }
- if(restart) {
- /* now reset a few variables to start over nicely from the start of
- the big buffer */
- pp->nread_resp = 0; /* start over from scratch in the buffer */
- ptr = pp->linestart_resp = buf;
- perline = 0;
+ /*
+ * Pass all response-lines to the callback function registered for
+ * "headers". The response lines can be seen as a kind of headers.
+ */
+ result = Curl_client_write(data, CLIENTWRITE_INFO, line, length);
+ if(result)
+ return result;
+
+ if(pp->endofresp(data, conn, line, length, code)) {
+ /* When at "end of response", keep the endofresp line first in the
+ buffer since it will be accessed outside (by pingpong
+ parsers). Store the overflow counter to inform about additional
+ data in this buffer after the endofresp line. */
+ pp->nfinal = length;
+ if(Curl_dyn_len(&pp->recvbuf) > length)
+ pp->overflow = Curl_dyn_len(&pp->recvbuf) - length;
+ else
+ pp->overflow = 0;
+ *size = pp->nread_resp; /* size of the response */
+ pp->nread_resp = 0; /* restart */
+ break;
}
+ if(Curl_dyn_len(&pp->recvbuf) > length)
+ /* keep the remaining piece */
+ Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length);
+ else
+ Curl_dyn_reset(&pp->recvbuf);
+ }
+ else {
+ /* without a newline, there is no overflow */
+ pp->overflow = 0;
+ break;
+ }
- } /* there was data */
-
- } /* while there's buffer left and loop is requested */
+ } while(1); /* while there's buffer left to scan */
pp->pending_resp = FALSE;
CURLcode Curl_pp_disconnect(struct pingpong *pp)
{
Curl_dyn_free(&pp->sendbuf);
- Curl_safefree(pp->cache);
+ Curl_dyn_free(&pp->recvbuf);
return CURLE_OK;
}
bool Curl_pp_moredata(struct pingpong *pp)
{
- return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
- TRUE : FALSE;
+ return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf));
}
#endif
* It holds response cache and non-blocking sending data.
*/
struct pingpong {
- char *cache; /* data cache between getresponse()-calls */
- size_t cache_size; /* size of cache in bytes */
size_t nread_resp; /* number of bytes currently read of a server response */
- char *linestart_resp; /* line start pointer for the server response
- reader function */
bool pending_resp; /* set TRUE when a server response is pending or in
progress, and is cleared once the last response is
read */
- char *sendthis; /* allocated pointer to a buffer that is to be sent to the
- server */
+ char *sendthis; /* pointer to a buffer that is to be sent to the server */
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
size_t sendsize; /* total size of the sendthis buffer */
struct curltime response; /* set to Curl_now() when a command has been sent
timediff_t response_time; /* When no timeout is given, this is the amount of
milliseconds we await for a server response. */
struct dynbuf sendbuf;
+ struct dynbuf recvbuf;
+ size_t overflow; /* number of bytes left after a final response line */
+ size_t nfinal; /* number of bytes in the final response line, which
+ after a match is first in the receice buffer */
/* Function pointers the protocols MUST implement and provide for the
pingpong layer to function */
bool block, bool disconnecting);
/* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp);
-
-/* setup for the transfer */
-void Curl_pp_setup(struct pingpong *pp);
+void Curl_pp_init(struct pingpong *pp);
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
*/
static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = data->state.buffer;
- size_t len = strlen(message);
+ char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
+ size_t len = data->conn->proto.pop3c.pp.nfinal;
if(len > 2) {
/* Find the start of the message */
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
- const char *line = data->state.buffer;
- size_t len = strlen(line);
+ const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
+ size_t len = data->conn->proto.pop3c.pp.nfinal;
(void)instate; /* no use for this yet */
failf(data, "Got unexpected pop3-server response");
result = CURLE_WEIRD_SERVER_REPLY;
}
- else {
+ else if(len > 3) {
/* Does the server support APOP authentication? */
- if(len >= 4 && line[len - 2] == '>') {
- /* Look for the APOP timestamp */
- size_t i;
- for(i = 3; i < len - 2; ++i) {
- if(line[i] == '<') {
- /* Calculate the length of the timestamp */
- size_t timestamplen = len - 1 - i;
- char *at;
- if(!timestamplen)
- break;
-
- /* dupe the timestamp */
- pop3c->apoptimestamp = Curl_memdup0(&line[i], timestamplen);
- if(!pop3c->apoptimestamp) {
- result = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- /* If the timestamp does not contain '@' it is not (as required by
- RFC-1939) conformant to the RFC-822 message id syntax, and we
- therefore do not use APOP authentication. */
- at = strchr(pop3c->apoptimestamp, '@');
- if(!at)
- Curl_safefree(pop3c->apoptimestamp);
- else
- /* Store the APOP capability */
- pop3c->authtypes |= POP3_TYPE_APOP;
- break;
- }
+ char *lt;
+ char *gt = NULL;
+
+ /* Look for the APOP timestamp */
+ lt = memchr(line, '<', len);
+ if(lt)
+ /* search the remainder for '>' */
+ gt = memchr(lt, '>', len - (lt - line));
+ if(gt) {
+ /* the length of the timestamp, including the brackets */
+ size_t timestamplen = gt - lt + 1;
+ char *at = memchr(lt, '@', timestamplen);
+ /* If the timestamp does not contain '@' it is not (as required by
+ RFC-1939) conformant to the RFC-822 message id syntax, and we
+ therefore do not use APOP authentication. */
+ if(at) {
+ /* dupe the timestamp */
+ pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen);
+ if(!pop3c->apoptimestamp)
+ return CURLE_OUT_OF_MEMORY;
+ /* Store the APOP capability */
+ pop3c->authtypes |= POP3_TYPE_APOP;
}
}
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
- const char *line = data->state.buffer;
- size_t len = strlen(line);
+ const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
+ size_t len = data->conn->proto.pop3c.pp.nfinal;
(void)instate; /* no use for this yet */
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.pop3c.pp.cache_size)
+ if(data->conn->proto.pop3c.pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
if(pop3code != '+') {
/* POP3 download */
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
- if(pp->cache) {
- /* The header "cache" contains a bunch of data that is actually body
- content so send it as such. Note that there may even be additional
- "headers" after the body */
+ if(pp->overflow) {
+ /* The recv buffer contains data that is actually body content so send
+ it as such. Note that there may even be additional "headers" after
+ the body */
+
+ /* keep only the overflow */
+ Curl_dyn_tail(&pp->recvbuf, pp->overflow);
+ pp->nfinal = 0; /* done */
if(!data->req.no_body) {
- result = Curl_pop3_write(data, pp->cache, pp->cache_size);
+ result = Curl_pop3_write(data, Curl_dyn_ptr(&pp->recvbuf),
+ Curl_dyn_len(&pp->recvbuf));
if(result)
return result;
}
- /* Free the cache */
- Curl_safefree(pp->cache);
-
- /* Reset the cache size */
- pp->cache_size = 0;
+ /* reset the buffer */
+ Curl_dyn_reset(&pp->recvbuf);
+ pp->overflow = 0;
}
}
+ else
+ pp->overflow = 0;
/* End of DO phase */
pop3_state(data, POP3_STOP);
Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */
- Curl_pp_setup(pp);
- Curl_pp_init(data, pp);
+ Curl_pp_init(pp);
/* Parse the URL options */
result = pop3_parse_url_options(conn);
*/
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = data->state.buffer;
- size_t len = strlen(message);
+ char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
+ size_t len = data->conn->proto.smtpc.pp.nfinal;
if(len > 4) {
/* Find the start of the message */
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.smtpc.pp.cache_size)
+ if(data->conn->proto.smtpc.pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
if(smtpcode != 220) {
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *line = data->state.buffer;
- size_t len = strlen(line);
+ const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf);
+ size_t len = smtpc->pp.nfinal;
(void)instate; /* no use for this yet */
{
CURLcode result = CURLE_OK;
struct SMTP *smtp = data->req.p.smtp;
- char *line = data->state.buffer;
- size_t len = strlen(line);
+ char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
+ size_t len = data->conn->proto.smtpc.pp.nfinal;
(void)instate; /* no use for this yet */
result = CURLE_WEIRD_SERVER_REPLY;
}
else {
- /* Temporarily add the LF character back and send as body to the client */
- if(!data->req.no_body) {
- line[len] = '\n';
- result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
- line[len] = '\0';
- }
+ if(!data->req.no_body)
+ result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
if(smtpcode != 1) {
if(smtp->rcpt) {
Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
- Curl_pp_setup(pp);
- Curl_pp_init(data, pp);
+ Curl_pp_init(pp);
/* Parse the URL options */
result = smtp_parse_url_options(conn);
static CURLcode smtp_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
*done = FALSE; /* default to false */
/* Parse the custom request */
<name>
FTP dir list PASV with slow response
</name>
-<command>
+<command option="binary-trace">
ftp://%HOSTIP:%FTPPORT/
</command>
</client>