(SMTP) support DATA better in the server and make sure to "escape" CRLF.CRLF

sequences in uploaded data. The test server doesn't "decode" escaped dot-lines
but instead test cases must be written to take them into account. Added test
case 803 to verify dot-escaping.
This commit is contained in:
Daniel Stenberg 2009-12-30 21:52:27 +00:00
parent d7cd761047
commit 5e6ffe353a
7 changed files with 206 additions and 5 deletions

View file

@ -639,6 +639,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
struct SessionHandle *data = conn->data;
struct FTP *smtp = data->state.proto.smtp;
CURLcode result=CURLE_OK;
ssize_t bytes_written;
(void)premature;
if(!smtp)
@ -653,6 +654,15 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
conn->bits.close = TRUE; /* marked for closure */
result = status; /* use the already set error code */
}
else
/* TODO: make this work even when the socket is EWOULDBLOCK in this call! */
/* write to socket (send away data) */
result = Curl_write(conn,
conn->writesockfd, /* socket to send to */
SMTP_EOB, /* buffer pointer */
SMTP_EOB_LEN, /* buffer size */
&bytes_written); /* actually sent away */
/* clear these for next connection */
smtp->transfer = FTPTRANSFER_BODY;

View file

@ -58,4 +58,8 @@ extern const struct Curl_handler Curl_handler_smtps;
#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
#define SMTP_EOB_LEN 5
/* if found in data, replace it with this string instead */
#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
#define SMTP_EOB_REPL_LEN 4
#endif /* __SMTP_H */

View file

@ -784,6 +784,68 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
/* store number of bytes available for upload */
data->req.upload_present = nread;
#ifndef CURL_DISABLE_SMTP
if(conn->protocol & PROT_SMTP) {
/* When sending SMTP payload, we must detect CRLF.CRLF sequences in
* the data and make sure it is sent as CRLF..CRLF instead, as
* otherwise it will wrongly be detected as end of data by the server.
*/
struct smtp_conn *smtpc = &conn->proto.smtpc;
if(data->state.scratch == NULL)
data->state.scratch = malloc(2*BUFSIZE);
if(data->state.scratch == NULL) {
failf (data, "Failed to alloc scratch buffer!");
return CURLE_OUT_OF_MEMORY;
}
/* This loop can be improved by some kind of Boyer-Moore style of
approach but that is saved for later... */
for(i = 0, si = 0; i < nread; i++, si++) {
int left = nread - i;
if(left>= (SMTP_EOB_LEN-smtpc->eob)) {
if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
SMTP_EOB_LEN-smtpc->eob)) {
/* It matched, copy the replacement data to the target buffer
instead. Note that the replacement does not contain the
trailing CRLF but we instead continue to match on that one
to deal with repeated sequences. Like CRLF.CRLF.CRLF etc
*/
memcpy(&data->state.scratch[si], SMTP_EOB_REPL,
SMTP_EOB_REPL_LEN);
si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments
it */
i+=SMTP_EOB_LEN-smtpc->eob-1-2;
smtpc->eob = 0; /* start over */
continue;
}
}
else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
left)) {
/* the last piece of the data matches the EOB so we can't send that
until we know the rest of it */
smtpc->eob += left;
break;
}
data->state.scratch[si] = data->req.upload_fromhere[i];
} /* for() */
if(si != nread) {
/* only use the new buffer if we replaced something */
nread = si;
/* upload from the new (replaced) buffer instead */
data->req.upload_fromhere = data->state.scratch;
/* set the new amount too */
data->req.upload_present = nread;
}
}
else
#endif /* CURL_DISABLE_SMTP */
/* convert LF to CRLF if so asked */
if((!sending_http_headers) &&
#ifdef CURL_DO_LINEEND_CONV
@ -837,10 +899,10 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
/* write to socket (send away data) */
result = Curl_write(conn,
conn->writesockfd, /* socket to send to */
conn->writesockfd, /* socket to send to */
data->req.upload_fromhere, /* buffer pointer */
data->req.upload_present, /* buffer size */
&bytes_written); /* actually send away */
&bytes_written); /* actually sent */
if(result)
return result;