Commit 5e6ffe35 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

(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.
parent d7cd7610
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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 */
+64 −2
Original line number Diff line number Diff line
@@ -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
@@ -840,7 +902,7 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
                        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;
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
 test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096   \
 test1097 test560 test561 test1098 test1099 test562 test563 test1100       \
 test564 test1101 test1102 test1103 test1104 test299 test310 test311       \
 test312 test1105 test565 test800 test1106 test801 test566 test802
 test312 test1105 test565 test800 test1106 test801 test566 test802 test803

filecheck:
	@mkdir test-place; \
+6 −2
Original line number Diff line number Diff line
@@ -38,11 +38,15 @@ EHLO user
MAIL FROM:802@from
RCPT TO:802@foo
DATA
QUIT
</protocol>
<upload>
From: different
To: another

body
QUIT
</protocol>

.
</upload>
</verify>
</testcase>
Loading