POP3: fixed escaped dot not being striped out

Changed the eob detection to work across the whole of the buffer so that
lines that begin with a dot (which the server will have escaped) are
passed to the client application correctly.
This commit is contained in:
Steve Holme 2011-11-30 18:23:09 +00:00 committed by Daniel Stenberg
parent c92234c3bc
commit bdb647814e

View File

@ -1040,61 +1040,75 @@ CURLcode Curl_pop3_write(struct connectdata *conn,
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct SingleRequest *k = &data->req; struct SingleRequest *k = &data->req;
/* Detect the end-of-body marker, which is 5 bytes:
0d 0a 2e 0d 0a. This marker can of course be spread out
over up to 5 different data chunks.
*/
struct pop3_conn *pop3c = &conn->proto.pop3c; struct pop3_conn *pop3c = &conn->proto.pop3c;
bool strip_dot = FALSE;
size_t last = 0;
size_t i; size_t i;
/* since the EOB string must be within the last 5 bytes, get the index /* Search through the buffer looking for the end-of-body marker which is
position of where to start to scan for it */ 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
size_t checkstart = (nread>POP3_EOB_LEN)?nread-POP3_EOB_LEN:0; the eob so the server will have prefixed it with an extra dot which we
need to strip out. Additionally the marker could of course be spread out
if(checkstart) { over 5 different data chunks */
/* write out the first piece, if any */ for(i = 0; i < nread; i++) {
result = Curl_client_write(conn, CLIENTWRITE_BODY, str, checkstart);
if(result)
return result;
pop3c->eob=0;
}
for(i=checkstart; i<nread; i++) {
size_t prev = pop3c->eob; size_t prev = pop3c->eob;
switch(str[i]) { switch(str[i]) {
case 0x0d: case 0x0d:
if((pop3c->eob == 0) || (pop3c->eob == 3)) if(pop3c->eob == 0) {
pop3c->eob++;
if(i) {
/* Write out the body part that didn't match */
result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
i - last);
if(result)
return result;
last = i;
}
}
else if(pop3c->eob == 3)
pop3c->eob++; pop3c->eob++;
else else
/* if it wasn't 0 or 3, it restarts the pattern match again */ /* If the character match wasn't at position 0 or 3 then restart the
pop3c->eob=1; pattern matching */
pop3c->eob = 1;
break; break;
case 0x0a: case 0x0a:
if((pop3c->eob == 1) || (pop3c->eob == 4)) if(pop3c->eob == 1 || pop3c->eob == 4)
pop3c->eob++; pop3c->eob++;
else else
pop3c->eob=0; /* If the character match wasn't at position 1 or 4 then start the
search again */
pop3c->eob = 0;
break; break;
case 0x2e: case 0x2e:
if(pop3c->eob == 2) if(pop3c->eob == 2)
pop3c->eob++; pop3c->eob++;
else else if(pop3c->eob == 3) {
pop3c->eob=0; /* We have an extra dot after the CRLF which we need to strip off */
break; strip_dot = TRUE;
default:
pop3c->eob=0;
break;
}
if(pop3c->eob == POP3_EOB_LEN) {
/* full match, the transfer is done! */
k->keepon &= ~KEEP_RECV;
pop3c->eob = 0; pop3c->eob = 0;
return CURLE_OK;
} }
else if(prev && (prev >= pop3c->eob)) { else
/* If the character match wasn't at position 2 then start the search
again */
pop3c->eob = 0;
break;
/* strip can only be non-zero for the very first mismatch after CRLF and default:
then both prev and strip are equal and nothing will be output pop3c->eob = 0;
break;
}
/* Did we have a partial match which has subsequently failed? */
if(prev && prev >= pop3c->eob) {
/* Strip can only be non-zero for the very first mismatch after CRLF
and then both prev and strip are equal and nothing will be output
below */ below */
while(prev && pop3c->strip) { while(prev && pop3c->strip) {
prev--; prev--;
@ -1102,27 +1116,34 @@ CURLcode Curl_pop3_write(struct connectdata *conn,
} }
if(prev) { if(prev) {
/* write out the body part that didn't match */ /* If the partial match was the CRLF and dot then only write the CRLF
as the server would have inserted the dot */
result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
prev); strip_dot ? prev - 1 : prev);
if(result) if(result)
return result; return result;
last = i;
strip_dot = FALSE;
} }
} }
} }
if(pop3c->eob == POP3_EOB_LEN) {
/* We have a full match so the transfer is done! */
k->keepon &= ~KEEP_RECV;
pop3c->eob = 0;
return CURLE_OK;
}
if(pop3c->eob) if(pop3c->eob)
/* while EOB is matching, don't output it! */ /* While EOB is matching nothing should be output */
return CURLE_OK; return CURLE_OK;
while(nread && pop3c->strip) { if(nread - last) {
nread--; result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
pop3c->strip--; nread - last);
str++;
}
if(nread) {
result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread);
} }
return result; return result;