summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/sendf.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/sendf.c')
-rw-r--r--Utilities/cmcurl/sendf.c467
1 files changed, 317 insertions, 150 deletions
diff --git a/Utilities/cmcurl/sendf.c b/Utilities/cmcurl/sendf.c
index fae2ff3..500bf66 100644
--- a/Utilities/cmcurl/sendf.c
+++ b/Utilities/cmcurl/sendf.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -43,16 +43,25 @@
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
-#include "connect.h" /* for the Curl_ourerrno() proto */
+#include "connect.h" /* for the Curl_sockerrno() proto */
+#include "sslgen.h"
+#include "ssh.h"
+#include "multiif.h"
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
#include <curl/mprintf.h>
#ifdef HAVE_KRB4
-#include "security.h"
+#include "krb4.h"
+#else
+#define Curl_sec_send(a,b,c,d) -1
+#define Curl_sec_read(a,b,c,d) -1
#endif
+
#include <string.h>
-#include "curl_memory.h"
+#include "memory.h"
+#include "strerror.h"
+#include "easyif.h" /* for the Curl_convert_from_network prototype */
/* The last #include file should be: */
#include "memdebug.h"
@@ -88,10 +97,10 @@ struct curl_slist *curl_slist_append(struct curl_slist *list,
new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
if (new_item) {
- char *cuDup = strdup(data);
- if(cuDup) {
+ char *dup = strdup(data);
+ if(dup) {
new_item->next = NULL;
- new_item->data = cuDup;
+ new_item->data = dup;
}
else {
free(new_item);
@@ -132,17 +141,102 @@ void curl_slist_free_all(struct curl_slist *list)
} while (next);
}
+#ifdef CURL_DO_LINEEND_CONV
+/*
+ * 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 SessionHandle *data,
+ char *startPtr, size_t size)
+{
+ char *inPtr, *outPtr;
+
+ /* sanity check */
+ if ((startPtr == NULL) || (size < 1)) {
+ return(size);
+ }
+
+ if (data->state.prev_block_had_trailing_cr == TRUE) {
+ /* 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 */
+ memcpy(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++;
+ inPtr++;
+ }
+ 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_infof() is for info message along the way */
void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
{
if(data && data->set.verbose) {
va_list ap;
+ size_t len;
char print_buffer[1024 + 1];
va_start(ap, fmt);
vsnprintf(print_buffer, 1024, fmt, ap);
va_end(ap);
- Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer), NULL);
+ len = strlen(print_buffer);
+ Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
}
}
@@ -153,25 +247,24 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
{
va_list ap;
+ size_t len;
va_start(ap, fmt);
+
+ vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
+
if(data->set.errorbuffer && !data->state.errorbuf) {
- vsnprintf(data->set.errorbuffer, CURL_ERROR_SIZE, fmt, ap);
+ snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
data->state.errorbuf = TRUE; /* wrote error string */
-
- if(data->set.verbose) {
- size_t len = strlen(data->set.errorbuffer);
- bool doneit=FALSE;
- if(len < CURL_ERROR_SIZE - 1) {
- doneit = TRUE;
- data->set.errorbuffer[len] = '\n';
- data->set.errorbuffer[++len] = '\0';
- }
- Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len, NULL);
- if(doneit)
- /* cut off the newline again */
- data->set.errorbuffer[--len]=0;
+ }
+ if(data->set.verbose) {
+ len = strlen(data->state.buffer);
+ if(len < BUFSIZE - 1) {
+ data->state.buffer[len] = '\n';
+ data->state.buffer[++len] = '\0';
}
+ Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
}
+
va_end(ap);
}
@@ -182,7 +275,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
struct SessionHandle *data = conn->data;
ssize_t bytes_written;
size_t write_len;
- CURLcode res;
+ CURLcode res = CURLE_OK;
char *s;
char *sptr;
va_list ap;
@@ -204,8 +297,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
break;
if(data->set.verbose)
- Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written,
- conn->host.dispname);
+ Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
if((size_t)bytes_written != write_len) {
/* if not all was written at once, we must advance the pointer, decrease
@@ -222,9 +314,40 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
return res;
}
+static ssize_t Curl_plain_send(struct connectdata *conn,
+ int num,
+ void *mem,
+ size_t len)
+{
+ curl_socket_t sockfd = conn->sock[num];
+ ssize_t bytes_written = swrite(sockfd, mem, len);
+
+ if(-1 == bytes_written) {
+ int err = Curl_sockerrno();
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == err)
+#else
+ /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We therefor
+ treat both error codes the same here */
+ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+#endif
+ )
+ /* this is just a case of EWOULDBLOCK */
+ bytes_written=0;
+ else
+ failf(conn->data, "Send failure: %s",
+ Curl_strerror(conn, err));
+ }
+ return bytes_written;
+}
+
/*
- * Curl_write() is an internal write function that sends plain (binary) data
- * to the server. Works with plain sockets, SSL or kerberos.
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
*/
CURLcode Curl_write(struct connectdata *conn,
curl_socket_t sockfd,
@@ -234,84 +357,22 @@ CURLcode Curl_write(struct connectdata *conn,
{
ssize_t bytes_written;
CURLcode retcode;
-
-#ifdef USE_SSLEAY
- /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
- If it is the second socket, we set num to 1. Otherwise to 0. This lets
- us use the correct ssl handle. */
int num = (sockfd == conn->sock[SECONDARYSOCKET]);
- /* SSL_write() is said to return 'int' while write() and send() returns
- 'size_t' */
- if (conn->ssl[num].use) {
- int err;
- char error_buffer[120]; /* OpenSSL documents that this must be at least
- 120 bytes long. */
- unsigned long sslerror;
- int rc = SSL_write(conn->ssl[num].handle, mem, (int)len);
-
- if(rc < 0) {
- err = SSL_get_error(conn->ssl[num].handle, rc);
-
- switch(err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* The operation did not complete; the same TLS/SSL I/O function
- should be called again later. This is basicly an EWOULDBLOCK
- equivalent. */
- *written = 0;
- return CURLE_OK;
- case SSL_ERROR_SYSCALL:
- failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n",
- Curl_ourerrno());
- return CURLE_SEND_ERROR;
- case SSL_ERROR_SSL:
- /* A failure in the SSL library occurred, usually a protocol error.
- The OpenSSL error queue contains more information on the error. */
- sslerror = ERR_get_error();
- failf(conn->data, "SSL_write() error: %s\n",
- ERR_error_string(sslerror, error_buffer));
- return CURLE_SEND_ERROR;
- }
- /* a true error */
- failf(conn->data, "SSL_write() return error %d\n", err);
- return CURLE_SEND_ERROR;
- }
- bytes_written = rc;
- }
- else {
-#else
- (void)conn;
-#endif
-#ifdef HAVE_KRB4
- if(conn->sec_complete) {
- bytes_written = Curl_sec_write(conn, sockfd, mem, len);
- }
- else
-#endif /* HAVE_KRB4 */
- {
- bytes_written = (ssize_t)swrite(sockfd, mem, len);
- }
- if(-1 == bytes_written) {
- int err = Curl_ourerrno();
- if(
-#ifdef WSAEWOULDBLOCK
- /* This is how Windows does it */
- (WSAEWOULDBLOCK == err)
-#else
- /* As pointed out by Christophe Demory on March 11 2003, errno
- may be EWOULDBLOCK or on some systems EAGAIN when it returned
- due to its inability to send off data without blocking. We
- therefor treat both error codes the same here */
- (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
-#endif
- )
- /* this is just a case of EWOULDBLOCK */
- bytes_written=0;
- }
-#ifdef USE_SSLEAY
- }
-#endif
+ if (conn->ssl[num].use)
+ /* only TRUE if SSL enabled */
+ bytes_written = Curl_ssl_send(conn, num, mem, len);
+#ifdef USE_LIBSSH2
+ else if (conn->protocol & PROT_SCP)
+ bytes_written = Curl_scp_send(conn, num, mem, len);
+ else if (conn->protocol & PROT_SFTP)
+ bytes_written = Curl_sftp_send(conn, num, mem, len);
+#endif /* !USE_LIBSSH2 */
+ else if(conn->sec_complete)
+ /* only TRUE if krb4 enabled */
+ bytes_written = Curl_sec_send(conn, num, mem, len);
+ else
+ bytes_written = Curl_plain_send(conn, num, mem, len);
*written = bytes_written;
retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
@@ -324,23 +385,53 @@ CURLcode Curl_write(struct connectdata *conn,
The bit pattern defines to what "streams" to write to. Body and/or header.
The defines are in sendf.h of course.
*/
-CURLcode Curl_client_write(struct SessionHandle *data,
+CURLcode Curl_client_write(struct connectdata *conn,
int type,
char *ptr,
size_t len)
{
+ struct SessionHandle *data = conn->data;
size_t wrote;
+ if (data->state.cancelled) {
+ /* We just suck everything into a black hole */
+ return CURLE_OK;
+ }
+
if(0 == len)
len = strlen(ptr);
if(type & CLIENTWRITE_BODY) {
- wrote = data->set.fwrite(ptr, 1, len, data->set.out);
+ if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') {
+#ifdef CURL_DOES_CONVERSIONS
+ /* convert from the network encoding */
+ size_t rc;
+ rc = Curl_convert_from_network(data, ptr, len);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(rc != CURLE_OK)
+ return rc;
+#endif /* CURL_DOES_CONVERSIONS */
+
+#ifdef CURL_DO_LINEEND_CONV
+ /* convert end-of-line markers */
+ len = convert_lineends(data, ptr, len);
+#endif /* CURL_DO_LINEEND_CONV */
+ }
+ /* If the previous block of data ended with CR and this block of data is
+ just a NL, then the length might be zero */
+ if (len) {
+ wrote = data->set.fwrite(ptr, 1, len, data->set.out);
+ }
+ else {
+ wrote = len;
+ }
+
if(wrote != len) {
failf (data, "Failed writing body");
return CURLE_WRITE_ERROR;
}
}
+
if((type & CLIENTWRITE_HEADER) &&
(data->set.fwrite_header || data->set.writeheader) ) {
/*
@@ -350,6 +441,9 @@ CURLcode Curl_client_write(struct SessionHandle *data,
curl_write_callback writeit=
data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite;
+ /* Note: The header is in the host encoding
+ regardless of the ftp transfer mode (ASCII/Image) */
+
wrote = writeit(ptr, 1, len, data->set.writeheader);
if(wrote != len) {
failf (data, "Failed writing header");
@@ -360,6 +454,10 @@ CURLcode Curl_client_write(struct SessionHandle *data,
return CURLE_OK;
}
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
/*
* Internal read-from-socket function. This is meant to deal with plain
* sockets, SSL sockets and kerberos sockets.
@@ -370,11 +468,15 @@ CURLcode Curl_client_write(struct SessionHandle *data,
int Curl_read(struct connectdata *conn, /* connection data */
curl_socket_t sockfd, /* read from this socket */
char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
+ size_t sizerequested, /* max amount to read */
ssize_t *n) /* amount bytes read */
{
ssize_t nread;
-#ifdef USE_SSLEAY
+ size_t bytesfromsocket = 0;
+ char *buffertofill = NULL;
+ bool pipelining = (bool)(conn->data->multi &&
+ Curl_multi_canPipeline(conn->data->multi));
+
/* Set 'num' to 0 or 1, depending on which socket that has been sent here.
If it is the second socket, we set num to 1. Otherwise to 0. This lets
us use the correct ssl handle. */
@@ -382,61 +484,75 @@ int Curl_read(struct connectdata *conn, /* connection data */
*n=0; /* reset amount to zero */
- if (conn->ssl[num].use) {
- nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, (int)buffersize);
-
- if(nread < 0) {
- /* failed SSL_read */
- int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
-
- switch(err) {
- case SSL_ERROR_NONE: /* this is not an error */
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- break;
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_read() */
- return -1; /* basicly EWOULDBLOCK */
- default:
- /* openssl/ssl.h says "look at error stack/return value/errno" */
- {
- char error_buffer[120]; /* OpenSSL documents that this must be at
- least 120 bytes long. */
- unsigned long sslerror = ERR_get_error();
- failf(conn->data, "SSL read: %s, errno %d",
- ERR_error_string(sslerror, error_buffer),
- Curl_ourerrno() );
- }
- return CURLE_RECV_ERROR;
- }
+ /* If session can pipeline, check connection buffer */
+ if(pipelining) {
+ size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested);
+
+ /* Copy from our master buffer first if we have some unread data there*/
+ if (bytestocopy > 0) {
+ memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
+ conn->read_pos += bytestocopy;
+ conn->bits.stream_was_rewound = FALSE;
+
+ *n = (ssize_t)bytestocopy;
+ return CURLE_OK;
}
+ /* If we come here, it means that there is no data to read from the buffer,
+ * so we read from the socket */
+ bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer));
+ buffertofill = conn->master_buffer;
}
else {
-#else
- (void)conn;
-#endif
- *n=0; /* reset amount to zero */
-#ifdef HAVE_KRB4
+ bytesfromsocket = MIN((long)sizerequested, conn->data->set.buffer_size ?
+ conn->data->set.buffer_size : BUFSIZE);
+ buffertofill = buf;
+ }
+
+ if(conn->ssl[num].use) {
+ nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket);
+
+ if(nread == -1) {
+ return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
+ }
+ }
+#ifdef USE_LIBSSH2
+ else if (conn->protocol & PROT_SCP) {
+ nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket);
+ /* TODO: return CURLE_OK also for nread <= 0
+ read failures and timeouts ? */
+ }
+ else if (conn->protocol & PROT_SFTP) {
+ nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket);
+ }
+#endif /* !USE_LIBSSH2 */
+ else {
if(conn->sec_complete)
- nread = Curl_sec_read(conn, sockfd, buf, buffersize);
+ nread = Curl_sec_read(conn, sockfd, buffertofill,
+ bytesfromsocket);
else
-#endif
- nread = sread(sockfd, buf, buffersize);
+ nread = sread(sockfd, buffertofill, bytesfromsocket);
if(-1 == nread) {
- int err = Curl_ourerrno();
-#ifdef WIN32
+ int err = Curl_sockerrno();
+#ifdef USE_WINSOCK
if(WSAEWOULDBLOCK == err)
#else
if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
#endif
return -1;
}
+ }
+
+ if (nread >= 0) {
+ if(pipelining) {
+ memcpy(buf, conn->master_buffer, nread);
+ conn->buf_len = nread;
+ conn->read_pos = nread;
+ }
-#ifdef USE_SSLEAY
+ *n += nread;
}
-#endif /* USE_SSLEAY */
- *n = nread;
+
return CURLE_OK;
}
@@ -447,6 +563,46 @@ static int showit(struct SessionHandle *data, curl_infotype type,
static const char * const s_infotype[CURLINFO_END] = {
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+#ifdef CURL_DOES_CONVERSIONS
+ char buf[BUFSIZE+1];
+ size_t conv_size = 0;
+
+ switch(type) {
+ case CURLINFO_HEADER_OUT:
+ /* assume output headers are ASCII */
+ /* copy the data into my buffer so the original is unchanged */
+ if (size > BUFSIZE) {
+ size = BUFSIZE; /* truncate if necessary */
+ buf[BUFSIZE] = '\0';
+ }
+ conv_size = size;
+ memcpy(buf, ptr, size);
+ /* Special processing is needed for this block if it
+ * contains both headers and data (separated by CRLFCRLF).
+ * We want to convert just the headers, leaving the data as-is.
+ */
+ if(size > 4) {
+ size_t i;
+ for(i = 0; i < size-4; i++) {
+ if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
+ /* convert everthing through this CRLFCRLF but no further */
+ conv_size = i + 4;
+ break;
+ }
+ }
+ }
+
+ Curl_convert_from_network(data, buf, conv_size);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* we might as well continue even if it fails... */
+ ptr = buf; /* switch pointer to use my buffer instead */
+ break;
+ default:
+ /* leave everything else as-is */
+ break;
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
if(data->set.fdebug)
return (*data->set.fdebug)(data, type, ptr, size,
data->set.debugdata);
@@ -457,6 +613,12 @@ static int showit(struct SessionHandle *data, curl_infotype type,
case CURLINFO_HEADER_IN:
fwrite(s_infotype[type], 2, 1, data->set.err);
fwrite(ptr, size, 1, data->set.err);
+#ifdef CURL_DOES_CONVERSIONS
+ if(size != conv_size) {
+ /* we had untranslated data so we need an explicit newline */
+ fwrite("\n", 1, 1, data->set.err);
+ }
+#endif
break;
default: /* nada */
break;
@@ -465,18 +627,22 @@ static int showit(struct SessionHandle *data, curl_infotype type,
}
int Curl_debug(struct SessionHandle *data, curl_infotype type,
- char *ptr, size_t size, char *host)
+ char *ptr, size_t size,
+ struct connectdata *conn)
{
int rc;
- if(data->set.printhost && host) {
+ if(data->set.printhost && conn && conn->host.dispname) {
char buffer[160];
const char *t=NULL;
+ const char *w="Data";
switch (type) {
case CURLINFO_HEADER_IN:
+ w = "Header";
case CURLINFO_DATA_IN:
t = "from";
break;
case CURLINFO_HEADER_OUT:
+ w = "Header";
case CURLINFO_DATA_OUT:
t = "to";
break;
@@ -485,7 +651,8 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
}
if(t) {
- snprintf(buffer, sizeof(buffer), "[Data %s %s]", t, host);
+ snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
+ conn->host.dispname);
rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
if(rc)
return rc;