Curl_safefree(ftpc->newhost);
}
+#ifdef CURL_DO_LINEEND_CONV
+/***********************************************************************
+ *
+ * Lineend Conversions
+ * On ASCII transfers, e.g. directory listings, we might get lines
+ * ending in '\r\n' and we prefer just '\n'.
+ * We might also get a lonely '\r' which we convert into a '\n'.
+ */
+struct ftp_cw_lc_ctx {
+ struct Curl_cwriter super;
+ bool newline_pending;
+};
+
+static CURLcode ftp_cw_lc_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t blen)
+{
+ static char nl = '\n';
+ struct ftp_cw_lc_ctx *ctx = (struct ftp_cw_lc_ctx *)writer;
+
+ if(!(type & CLIENTWRITE_BODY) ||
+ data->conn->proto.ftpc.transfertype != 'A')
+ return Curl_cwriter_write(data, writer->next, type, buf, blen);
+
+ /* ASCII mode BODY data, convert lineends */
+ while(blen) {
+ /* do not pass EOS when writing parts */
+ int chunk_type = (type & ~CLIENTWRITE_EOS);
+ const char *cp;
+ size_t chunk_len;
+ CURLcode result;
+
+ if(ctx->newline_pending) {
+ if(buf[0] != '\n') {
+ /* previous chunk ended in '\r' and we do not see a '\n' in this one,
+ * need to write a newline. */
+ result = Curl_cwriter_write(data, writer->next, chunk_type, &nl, 1);
+ if(result)
+ return result;
+ }
+ /* either we just wrote the newline or it is part of the next
+ * chunk of bytes we write. */
+ data->state.crlf_conversions++;
+ ctx->newline_pending = FALSE;
+ }
+
+ cp = memchr(buf, '\r', blen);
+ if(!cp)
+ break;
+
+ /* write the bytes before the '\r', excluding the '\r' */
+ chunk_len = cp - buf;
+ if(chunk_len) {
+ result = Curl_cwriter_write(data, writer->next, chunk_type,
+ buf, chunk_len);
+ if(result)
+ return result;
+ }
+ /* skip the '\r', we now have a newline pending */
+ buf = cp + 1;
+ blen = blen - chunk_len - 1;
+ ctx->newline_pending = TRUE;
+ }
+
+ /* Any remaining data does not contain a '\r' */
+ if(blen) {
+ DEBUGASSERT(!ctx->newline_pending);
+ return Curl_cwriter_write(data, writer->next, type, buf, blen);
+ }
+ else if(type & CLIENTWRITE_EOS) {
+ /* EndOfStream, if we have a trailing cr, now is the time to write it */
+ if(ctx->newline_pending) {
+ ctx->newline_pending = FALSE;
+ data->state.crlf_conversions++;
+ return Curl_cwriter_write(data, writer->next, type, &nl, 1);
+ }
+ /* Always pass on the EOS type indicator */
+ return Curl_cwriter_write(data, writer->next, type, buf, 0);
+ }
+ return CURLE_OK;
+}
+
+static const struct Curl_cwtype ftp_cw_lc = {
+ "ftp-lineconv",
+ NULL,
+ Curl_cwriter_def_init,
+ ftp_cw_lc_write,
+ Curl_cwriter_def_close,
+ sizeof(struct ftp_cw_lc_ctx)
+};
+
+#endif /* CURL_DO_LINEEND_CONV */
/***********************************************************************
*
* AcceptServerConnect()
*done = FALSE; /* default to false */
ftpc->wait_data_conn = FALSE; /* default to no such wait */
+#ifdef CURL_DO_LINEEND_CONV
+ {
+ /* FTP data may need conversion. */
+ struct Curl_cwriter *ftp_lc_writer;
+
+ result = Curl_cwriter_create(&ftp_lc_writer, data, &ftp_cw_lc,
+ CURL_CW_CONTENT_DECODE);
+ if(result)
+ return result;
+
+ result = Curl_cwriter_add(data, ftp_lc_writer);
+ if(result) {
+ Curl_cwriter_free(data, ftp_lc_writer);
+ return result;
+ }
+ }
+#endif /* CURL_DO_LINEEND_CONV */
+
if(data->state.wildcardmatch) {
result = wc_statemach(data);
if(data->wildcard->state == CURLWC_SKIP ||
static CURLcode do_init_stack(struct Curl_easy *data);
-#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
-/*
- * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
- * (\n), with special processing for CRLF sequences that are split between two
- * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
- * size of the data is returned.
- */
-static size_t convert_lineends(struct Curl_easy *data,
- char *startPtr, size_t size)
-{
- char *inPtr, *outPtr;
-
- /* sanity check */
- if(!startPtr || (size < 1)) {
- return size;
- }
-
- if(data->state.prev_block_had_trailing_cr) {
- /* The previous block of incoming data
- had a trailing CR, which was turned into a LF. */
- if(*startPtr == '\n') {
- /* This block of incoming data starts with the
- previous block's LF so get rid of it */
- memmove(startPtr, startPtr + 1, size-1);
- size--;
- /* and it wasn't a bare CR but a CRLF conversion instead */
- data->state.crlf_conversions++;
- }
- data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
- }
-
- /* find 1st CR, if any */
- inPtr = outPtr = memchr(startPtr, '\r', size);
- if(inPtr) {
- /* at least one CR, now look for CRLF */
- while(inPtr < (startPtr + size-1)) {
- /* note that it's size-1, so we'll never look past the last byte */
- if(memcmp(inPtr, "\r\n", 2) == 0) {
- /* CRLF found, bump past the CR and copy the NL */
- inPtr++;
- *outPtr = *inPtr;
- /* keep track of how many CRLFs we converted */
- data->state.crlf_conversions++;
- }
- else {
- if(*inPtr == '\r') {
- /* lone CR, move LF instead */
- *outPtr = '\n';
- }
- else {
- /* not a CRLF nor a CR, just copy whatever it is */
- *outPtr = *inPtr;
- }
- }
- outPtr++;
- inPtr++;
- } /* end of while loop */
-
- if(inPtr < startPtr + size) {
- /* handle last byte */
- if(*inPtr == '\r') {
- /* deal with a CR at the end of the buffer */
- *outPtr = '\n'; /* copy a NL instead */
- /* note that a CRLF might be split across two blocks */
- data->state.prev_block_had_trailing_cr = TRUE;
- }
- else {
- /* copy last byte */
- *outPtr = *inPtr;
- }
- outPtr++;
- }
- if(outPtr < startPtr + size)
- /* tidy up by null terminating the now shorter data */
- *outPtr = '\0';
-
- return (outPtr - startPtr);
- }
- return size;
-}
-#endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
-
/*
* Curl_nwrite() is an internal write function that sends data to the
* server. Works with a socket index for the connection.
The bit pattern defines to what "streams" to write to. Body and/or header.
The defines are in sendf.h of course.
-
- If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
- local character encoding. This is a problem and should be changed in
- the future to leave the original data alone.
*/
CURLcode Curl_client_write(struct Curl_easy *data,
int type, char *buf, size_t blen)
{
CURLcode result;
-#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
- /* FTP data may need conversion. */
- if((type & CLIENTWRITE_BODY) &&
- (data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
- data->conn->proto.ftpc.transfertype == 'A') {
- /* convert end-of-line markers */
- blen = convert_lineends(data, buf, blen);
- }
-#endif
/* it is one of those, at least */
DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
/* BODY is only BODY (with optional EOS) */