mirror of
https://github.com/curl/curl.git
synced 2026-08-26 04:43:35 +03:00
ftp: do lineend conversions in client writer
- remove the ftp special handling from sendf.c - let ftp_do() add a client writer that does the linened conversions - change the lineend conversion to no longer modify the passed buffer, but write smaller chunks to the next cwriter instead. The inefficiency of this will be mitigated once we add output buffering for all client writes. Closes #12878
This commit is contained in:
parent
6984aa3a45
commit
e7fd32b9ac
3 changed files with 110 additions and 97 deletions
110
lib/ftp.c
110
lib/ftp.c
|
|
@ -255,6 +255,98 @@ static void freedirs(struct ftp_conn *ftpc)
|
|||
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()
|
||||
|
|
@ -4035,6 +4127,24 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done)
|
|||
*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 ||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue