mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 15:48:49 -05:00
Introducing curl_easy_pause() and new magic return codes for both the read
and the write callbacks that now can make a connection's reading and/or writing get paused.
This commit is contained in:
parent
5e1c9e90d9
commit
de23b98522
5
CHANGES
5
CHANGES
@ -6,6 +6,11 @@
|
||||
|
||||
Changelog
|
||||
|
||||
Daniel S (8 Jan 2008)
|
||||
- Introducing curl_easy_pause() and new magic return codes for both the read
|
||||
and the write callbacks that now can make a connection's reading and/or
|
||||
writing get paused.
|
||||
|
||||
Daniel S (6 Jan 2008)
|
||||
- Jeff Johnson filed bug report #1863171
|
||||
(http://curl.haxx.se/bug/view.cgi?id=1863171) where he pointed out that
|
||||
|
@ -1,9 +1,9 @@
|
||||
Curl and libcurl 7.17.2
|
||||
Curl and libcurl 7.18.0
|
||||
|
||||
Public curl releases: 103
|
||||
Command line options: 125
|
||||
curl_easy_setopt() options: 148
|
||||
Public functions in libcurl: 55
|
||||
Public functions in libcurl: 56
|
||||
Public web site mirrors: 42
|
||||
Known libcurl bindings: 36
|
||||
Contributors: 597
|
||||
@ -16,6 +16,7 @@ This release includes the following changes:
|
||||
keep-alive enabled by default
|
||||
o --socks4a added (proxy type CURLPROXY_SOCKS4A for libcurl)
|
||||
o --socks5-hostname added (CURLPROXY_SOCKS5_HOSTNAME for libcurl)
|
||||
o curl_easy_pause() added
|
||||
|
||||
This release includes the following bugfixes:
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
.\" * $Id$
|
||||
.\" **************************************************************************
|
||||
.\"
|
||||
.TH curl 1 "5 Jan 2008" "Curl 7.17.2" "Curl Manual"
|
||||
.TH curl 1 "5 Jan 2008" "Curl 7.18.0" "Curl Manual"
|
||||
.SH NAME
|
||||
curl \- transfer a URL
|
||||
.SH SYNOPSIS
|
||||
@ -256,7 +256,7 @@ If this option is used several times, the ones following the first will append
|
||||
data. As described in \fI-d/--data\fP.
|
||||
.IP "--data-urlencode <data>"
|
||||
(HTTP) This posts data, similar to the other --data options with the exception
|
||||
that this performs URL encoding. (Added in 7.17.2)
|
||||
that this performs URL encoding. (Added in 7.18.0)
|
||||
|
||||
To be CGI compliant, the <data> part should begin with a \fIname\fP followed
|
||||
by a separator and a content specification. The <data> part can be passed to
|
||||
@ -1077,7 +1077,7 @@ mutually exclusive.
|
||||
If this option is used several times, the last one will be used.
|
||||
.IP "--socks4a <host[:port]>"
|
||||
Use the specified SOCKS4a proxy. If the port number is not specified, it is
|
||||
assumed at port 1080. (Added in 7.17.2)
|
||||
assumed at port 1080. (Added in 7.18.0)
|
||||
|
||||
This option overrides any previous use of \fI-x/--proxy\fP, as they are
|
||||
mutually exclusive.
|
||||
@ -1086,7 +1086,7 @@ If this option is used several times, the last one will be used.
|
||||
.IP "--socks5-hostname <host[:port]>"
|
||||
Use the specified SOCKS5 proxy (and let the proxy resolve the host name). If
|
||||
the port number is not specified, it is assumed at port 1080. (Added in
|
||||
7.17.2)
|
||||
7.18.0)
|
||||
|
||||
This option overrides any previous use of \fI-x/--proxy\fP, as they are
|
||||
mutually exclusive.
|
||||
|
@ -18,7 +18,8 @@ man_MANS = curl_easy_cleanup.3 curl_easy_getinfo.3 curl_easy_init.3 \
|
||||
curl_multi_strerror.3 curl_share_strerror.3 curl_global_init_mem.3 \
|
||||
libcurl-tutorial.3 curl_easy_reset.3 curl_easy_escape.3 \
|
||||
curl_easy_unescape.3 curl_multi_setopt.3 curl_multi_socket.3 \
|
||||
curl_multi_timeout.3 curl_formget.3 curl_multi_assign.3
|
||||
curl_multi_timeout.3 curl_formget.3 curl_multi_assign.3 \
|
||||
curl_easy_pause.3
|
||||
|
||||
HTMLPAGES = curl_easy_cleanup.html curl_easy_getinfo.html \
|
||||
curl_easy_init.html curl_easy_perform.html curl_easy_setopt.html \
|
||||
@ -36,7 +37,7 @@ HTMLPAGES = curl_easy_cleanup.html curl_easy_getinfo.html \
|
||||
curl_share_strerror.html curl_global_init_mem.html libcurl-tutorial.html \
|
||||
curl_easy_reset.html curl_easy_escape.html curl_easy_unescape.html \
|
||||
curl_multi_setopt.html curl_multi_socket.html curl_multi_timeout.html \
|
||||
curl_formget.html curl_multi_assign.html
|
||||
curl_formget.html curl_multi_assign.html curl_easy_pause.html
|
||||
|
||||
PDFPAGES = curl_easy_cleanup.pdf curl_easy_getinfo.pdf curl_easy_init.pdf \
|
||||
curl_easy_perform.pdf curl_easy_setopt.pdf curl_easy_duphandle.pdf \
|
||||
@ -53,7 +54,7 @@ PDFPAGES = curl_easy_cleanup.pdf curl_easy_getinfo.pdf curl_easy_init.pdf \
|
||||
curl_share_strerror.pdf curl_global_init_mem.pdf libcurl-tutorial.pdf \
|
||||
curl_easy_reset.pdf curl_easy_escape.pdf curl_easy_unescape.pdf \
|
||||
curl_multi_setopt.pdf curl_multi_socket.pdf curl_multi_timeout.pdf \
|
||||
curl_formget.pdf curl_multi_assign.pdf
|
||||
curl_formget.pdf curl_multi_assign.pdf curl_easy_pause.pdf
|
||||
|
||||
CLEANFILES = $(HTMLPAGES) $(PDFPAGES)
|
||||
|
||||
|
63
docs/libcurl/curl_easy_pause.3
Normal file
63
docs/libcurl/curl_easy_pause.3
Normal file
@ -0,0 +1,63 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_easy_pause 3 "17 Dec 2007" "libcurl 7.18.0" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_pause - pause and unpause a connection
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
|
||||
.BI "CURLcode curl_easy_pause(CURL *"handle ", int "bitmask " );"
|
||||
|
||||
.SH DESCRIPTION
|
||||
Using this function, you can explicitly mark a running connection to get
|
||||
paused, and you can unpause a connection that was previously paused.
|
||||
|
||||
A connection can made to pause by using this function or by letting the read
|
||||
or the write callbacks return the proper magic return code
|
||||
(\fICURL_READFUNC_PAUSE\fP and \fICURL_WRITEFUNC_PAUSE\fP).
|
||||
|
||||
NOTE: while it may feel tempting, take care and notice that you cannot call
|
||||
this function from another thread.
|
||||
|
||||
When this function is called to unpause reading, the chance is high that you
|
||||
will get your write callback called before this function returns.
|
||||
|
||||
The \fBhandle\fP argument is of course identifying the handle that operates on
|
||||
the connection you want to pause or unpause.
|
||||
|
||||
The \fBbitmask\fP argument is a set of bits that sets the new state of the
|
||||
connection. The following bits can be used:
|
||||
.IP CURLPAUSE_RECV
|
||||
Pause receiving data. There will be no data received on this conneciton until
|
||||
this function is called again without this bit set. Thus, the write callback
|
||||
(\fICURLOPT_WRITEFUNCTION\fP) won't be called.
|
||||
.IP CURLPAUSE_SEND
|
||||
Pause sending data. There will be no data sent on this connection until this
|
||||
function is called again without this bit set. Thus, the read callback
|
||||
(\fICURLOPT_READFUNCTION\fP) won't be called.
|
||||
.IP CURLPAUSE_ALL
|
||||
Convenience define that pauses both directions.
|
||||
.IP CURLPAUSE_CONT
|
||||
Convenience define that unpauses both directions
|
||||
.SH RETURN VALUE
|
||||
CURLE_OK (zero) means that the option was set properly, and a non-zero return
|
||||
code means something wrong occurred after the new state was set. See the
|
||||
\fIlibcurl-errors(3)\fP man page for the full list with descriptions.
|
||||
.SH AVAILABILITY
|
||||
This function was added in libcurl 7.18.0. Before this version, there was no
|
||||
explicit support for pausing transfers.
|
||||
.SH "MEMORY USE"
|
||||
When pausing a read by returning the magic return code from a write callback,
|
||||
the read data is already in libcurl's internal buffers so it'll have to keep
|
||||
it in an allocated buffer until the reading is again unpaused using this
|
||||
function.
|
||||
|
||||
If the downloaded data is compressed and is asked to get uncompressed
|
||||
automatially on download, libcurl will continue to uncompress the entire
|
||||
downloaded chunk and it will cache the data uncompressed. This has the side-
|
||||
effect that if you download something that is compressed a lot, it can result
|
||||
in a very large data amount needing to be allocated to save the data during
|
||||
the pause. This said, you should probably consider not using paused reading if
|
||||
you allow libcurl to uncompress data automatically.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_easy_cleanup "(3), " curl_easy_reset "(3)"
|
@ -21,7 +21,7 @@
|
||||
.\" * $Id$
|
||||
.\" **************************************************************************
|
||||
.\"
|
||||
.TH curl_easy_setopt 3 "5 Jan 2008" "libcurl 7.17.2" "libcurl Manual"
|
||||
.TH curl_easy_setopt 3 "5 Jan 2008" "libcurl 7.18.0" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_setopt \- set options for a curl easy handle
|
||||
.SH SYNOPSIS
|
||||
@ -95,6 +95,10 @@ of bytes actually taken care of. If that amount differs from the amount passed
|
||||
to your function, it'll signal an error to the library and it will abort the
|
||||
transfer and return \fICURLE_WRITE_ERROR\fP.
|
||||
|
||||
From 7.18.0, the function can return CURL_WRITEFUNC_PAUSE which then will
|
||||
cause writing to this connection to become paused. See
|
||||
\fIcurl_easy_pause(3)\fP for further details.
|
||||
|
||||
This function may be called with zero bytes data if the transfered file is
|
||||
empty.
|
||||
|
||||
@ -142,6 +146,10 @@ The read callback may return \fICURL_READFUNC_ABORT\fP to stop the current
|
||||
operation immediately, resulting in a \fICURLE_ABORTED_BY_CALLBACK\fP error
|
||||
code from the transfer (Added in 7.12.1)
|
||||
|
||||
From 7.18.0, the function can return CURL_READFUNC_PAUSE which then will cause
|
||||
reading from this connection to become paused. See \fIcurl_easy_pause(3)\fP
|
||||
for further details.
|
||||
|
||||
If you set the callback pointer to NULL, or doesn't set it at all, the default
|
||||
internal read function will be used. It is simply doing an fread() on the FILE
|
||||
* stream set with \fICURLOPT_READDATA\fP.
|
||||
@ -431,8 +439,8 @@ specified in the proxy string \fICURLOPT_PROXY\fP.
|
||||
.IP CURLOPT_PROXYTYPE
|
||||
Pass a long with this option to set type of the proxy. Available options for
|
||||
this are \fICURLPROXY_HTTP\fP, \fICURLPROXY_SOCKS4\fP (added in 7.15.2),
|
||||
\fICURLPROXY_SOCKS5\fP, \fICURLPROXY_SOCKS4A\fP (added in 7.17.2) and
|
||||
\fICURLPROXY_SOCKS5_HOSTNAME\fP (added in 7.17.2). The HTTP type is
|
||||
\fICURLPROXY_SOCKS5\fP, \fICURLPROXY_SOCKS4A\fP (added in 7.18.0) and
|
||||
\fICURLPROXY_SOCKS5_HOSTNAME\fP (added in 7.18.0). The HTTP type is
|
||||
default. (Added in 7.10)
|
||||
.IP CURLOPT_HTTPPROXYTUNNEL
|
||||
Set the parameter to non-zero to get the library to tunnel all operations
|
||||
@ -443,8 +451,8 @@ don't want this tunneling option.
|
||||
Set the parameter to 1 to get the library to resolve the host name locally
|
||||
instead of passing it to the proxy to resolve, when using a SOCKS5 proxy.
|
||||
|
||||
Note that libcurl before 7.17.2 always resolved the host name locally even
|
||||
when SOCKS5 was used. (Added in 7.17.2)
|
||||
Note that libcurl before 7.18.0 always resolved the host name locally even
|
||||
when SOCKS5 was used. (Added in 7.18.0)
|
||||
.IP CURLOPT_INTERFACE
|
||||
Pass a char * as parameter. This set the interface name to use as outgoing
|
||||
network interface. The name can be an interface name, an IP address or a host
|
||||
@ -1080,7 +1088,7 @@ transfer mode (binary or ASCII) for FTP transfers done via an HTTP proxy, by
|
||||
appending ;type=a or ;type=i to the URL. Without this setting, or it being
|
||||
set to 0 (zero, the default), \fICURLOPT_TRANSFERTEXT\fP has no effect when
|
||||
doing FTP via a proxy. Beware that not all proxies support this feature.
|
||||
(Added in 7.17.2)
|
||||
(Added in 7.18.0)
|
||||
.IP CURLOPT_CRLF
|
||||
Convert Unix newlines to CRLF newlines on transfers.
|
||||
.IP CURLOPT_RANGE
|
||||
|
@ -230,7 +230,9 @@ typedef int (*curl_progress_callback)(void *clientp,
|
||||
time for those who feel adventurous. */
|
||||
#define CURL_MAX_WRITE_SIZE 16384
|
||||
#endif
|
||||
|
||||
/* This is a magic return code for the write callback that, when returned,
|
||||
will signal libcurl to pause receving on the current transfer. */
|
||||
#define CURL_WRITEFUNC_PAUSE 0x10000001
|
||||
typedef size_t (*curl_write_callback)(char *buffer,
|
||||
size_t size,
|
||||
size_t nitems,
|
||||
@ -239,6 +241,9 @@ typedef size_t (*curl_write_callback)(char *buffer,
|
||||
/* This is a return code for the read callback that, when returned, will
|
||||
signal libcurl to immediately abort the current transfer. */
|
||||
#define CURL_READFUNC_ABORT 0x10000000
|
||||
/* This is a return code for the read callback that, when returned, will
|
||||
signal libcurl to pause sending data on the current transfer. */
|
||||
#define CURL_READFUNC_PAUSE 0x10000001
|
||||
typedef size_t (*curl_read_callback)(char *buffer,
|
||||
size_t size,
|
||||
size_t nitems,
|
||||
@ -257,7 +262,7 @@ struct curl_sockaddr {
|
||||
int family;
|
||||
int socktype;
|
||||
int protocol;
|
||||
unsigned int addrlen; /* addrlen was a socklen_t type before 7.17.2 but it
|
||||
unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
|
||||
turned really ugly and painful on the systems that
|
||||
lack this type */
|
||||
struct sockaddr addr;
|
||||
@ -499,10 +504,10 @@ typedef enum {
|
||||
CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
|
||||
in 7.10 */
|
||||
CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
|
||||
CURLPROXY_SOCKS4A = 6, /* added in 7.17.2 */
|
||||
CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
|
||||
CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
|
||||
host name rather than the IP address. added
|
||||
in 7.17.2 */
|
||||
in 7.18.0 */
|
||||
} curl_proxytype; /* this enum was added in 7.10 */
|
||||
|
||||
#define CURLAUTH_NONE 0 /* nothing */
|
||||
@ -1749,6 +1754,26 @@ CURL_EXTERN const char *curl_easy_strerror(CURLcode);
|
||||
*/
|
||||
CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
|
||||
|
||||
/*
|
||||
* NAME curl_easy_pause()
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* The curl_easy_pause function pauses or unpauses transfers. Select the new
|
||||
* state by setting the bitmask, use the convenience defines below.
|
||||
*
|
||||
*/
|
||||
CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
|
||||
|
||||
#define CURLPAUSE_RECV (1<<0)
|
||||
#define CURLPAUSE_RECV_CONT (0)
|
||||
|
||||
#define CURLPAUSE_SEND (1<<2)
|
||||
#define CURLPAUSE_SEND_CONT (0)
|
||||
|
||||
#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND)
|
||||
#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2008, 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
|
||||
@ -28,13 +28,13 @@
|
||||
|
||||
/* This is the version number of the libcurl package from which this header
|
||||
file origins: */
|
||||
#define LIBCURL_VERSION "7.17.2-CVS"
|
||||
#define LIBCURL_VERSION "7.18.0-CVS"
|
||||
|
||||
/* The numeric version number is also available "in parts" by using these
|
||||
defines: */
|
||||
#define LIBCURL_VERSION_MAJOR 7
|
||||
#define LIBCURL_VERSION_MINOR 17
|
||||
#define LIBCURL_VERSION_PATCH 2
|
||||
#define LIBCURL_VERSION_MINOR 18
|
||||
#define LIBCURL_VERSION_PATCH 0
|
||||
|
||||
/* This is the numeric version of the libcurl version number, meant for easier
|
||||
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
|
||||
@ -51,7 +51,7 @@
|
||||
and it is always a greater number in a more recent release. It makes
|
||||
comparisons with greater than and less than work.
|
||||
*/
|
||||
#define LIBCURL_VERSION_NUM 0x071102
|
||||
#define LIBCURL_VERSION_NUM 0x071200
|
||||
|
||||
/*
|
||||
* This is the date and time when the full source package was created. The
|
||||
|
101
lib/easy.c
101
lib/easy.c
@ -744,6 +744,107 @@ void curl_easy_reset(CURL *curl)
|
||||
data->set.new_directory_perms = 0755; /* Default permissions */
|
||||
}
|
||||
|
||||
/*
|
||||
* curl_easy_pause() allows an application to pause or unpause a specific
|
||||
* transfer and direction. This function sets the full new state for the
|
||||
* current connection this easy handle operates on.
|
||||
*
|
||||
* NOTE: if you have the receiving paused and you call this function to remove
|
||||
* the pausing, you may get your write callback called at this point.
|
||||
*
|
||||
* Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
|
||||
*/
|
||||
CURLcode curl_easy_pause(CURL *curl, int action)
|
||||
{
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
struct SingleRequest *k = &data->req;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* first switch off both pause bits */
|
||||
int newstate = k->keepon &~ (KEEP_READ_PAUSE| KEEP_WRITE_PAUSE);
|
||||
|
||||
/* set the new desired pause bits */
|
||||
newstate |= ((action & CURLPAUSE_RECV)?KEEP_READ_PAUSE:0) |
|
||||
((action & CURLPAUSE_SEND)?KEEP_WRITE_PAUSE:0);
|
||||
|
||||
/* put it back in the keepon */
|
||||
k->keepon = newstate;
|
||||
|
||||
if(!(newstate & KEEP_READ_PAUSE) && data->state.tempwrite) {
|
||||
/* we have a buffer for writing that we now seem to be able to deliver since
|
||||
the receive pausing is lifted! */
|
||||
|
||||
/* get the pointer, type and length in local copies since the function may
|
||||
return PAUSE again and then we'll get a new copy allocted and stored in
|
||||
the tempwrite variables */
|
||||
char *tempwrite = data->state.tempwrite;
|
||||
size_t tempsize = data->state.tempwritesize;
|
||||
int temptype = data->state.tempwritetype;
|
||||
size_t chunklen;
|
||||
|
||||
/* clear tempwrite here just to make sure it gets cleared if there's no
|
||||
further use of it, and make sure we don't clear it after the function
|
||||
invoke as it may have been set to a new value by then */
|
||||
data->state.tempwrite = NULL;
|
||||
|
||||
/* since the write callback API is define to never exceed
|
||||
CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
|
||||
have more data than that in our buffer here, we must loop sending the
|
||||
data in multiple calls until there's no data left or we get another
|
||||
pause returned.
|
||||
|
||||
A tricky part is that the function we call will "buffer" the data
|
||||
itself when it pauses on a particular buffer, so we may need to do some
|
||||
extra trickery if we get a pause return here.
|
||||
*/
|
||||
do {
|
||||
chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
|
||||
|
||||
result = Curl_client_write(data->state.current_conn,
|
||||
temptype, tempwrite, chunklen);
|
||||
if(!result)
|
||||
/* failures abort the loop at once */
|
||||
break;
|
||||
|
||||
if(data->state.tempwrite && (tempsize - chunklen)) {
|
||||
/* Ouch, the reading is again paused and the block we send is now
|
||||
"cached". If this is the final chunk we can leave it like this, but
|
||||
if we have more chunks that is cached after this, we need to free
|
||||
the newly cached one and put back a version that is truly the entire
|
||||
contents that is saved for later
|
||||
*/
|
||||
char *newptr;
|
||||
|
||||
free(data->state.tempwrite); /* free the one just cached as it isn't
|
||||
enough */
|
||||
|
||||
/* note that tempsize is still the size as before the callback was
|
||||
used, and thus the whole piece of data to keep */
|
||||
newptr = malloc(tempsize);
|
||||
if(!newptr) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
/* tempwrite will be freed further down */
|
||||
break;
|
||||
}
|
||||
data->state.tempwrite = newptr; /* store new pointer */
|
||||
memcpy(newptr, tempwrite, tempsize);
|
||||
data->state.tempwritesize = tempsize; /* store new size */
|
||||
/* tempwrite will be freed further down */
|
||||
break; /* go back to pausing until further notice */
|
||||
}
|
||||
else {
|
||||
tempsize -= chunklen; /* left after the call above */
|
||||
tempwrite += chunklen; /* advance the pointer */
|
||||
}
|
||||
|
||||
} while((result == CURLE_OK) && tempsize);
|
||||
|
||||
free(tempwrite); /* this is unconditionally no longer used */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CURL_DOES_CONVERSIONS
|
||||
/*
|
||||
* Curl_convert_to_network() is an internal function
|
||||
|
@ -1255,13 +1255,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
k = &easy->easy_handle->req;
|
||||
|
||||
if(!(k->keepon & KEEP_READ)) {
|
||||
/* We're done reading */
|
||||
easy->easy_conn->readchannel_inuse = FALSE;
|
||||
/* We're done reading */
|
||||
easy->easy_conn->readchannel_inuse = FALSE;
|
||||
}
|
||||
|
||||
if(!(k->keepon & KEEP_WRITE)) {
|
||||
/* We're done writing */
|
||||
easy->easy_conn->writechannel_inuse = FALSE;
|
||||
/* We're done writing */
|
||||
easy->easy_conn->writechannel_inuse = FALSE;
|
||||
}
|
||||
|
||||
if(easy->result) {
|
||||
|
74
lib/sendf.c
74
lib/sendf.c
@ -376,6 +376,36 @@ CURLcode Curl_write(struct connectdata *conn,
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static CURLcode pausewrite(struct SessionHandle *data,
|
||||
int type, /* what type of data */
|
||||
char *ptr,
|
||||
size_t len)
|
||||
{
|
||||
/* signalled to pause sending on this connection, but since we have data
|
||||
we want to send we need to dup it to save a copy for when the sending
|
||||
is again enabled */
|
||||
struct SingleRequest *k = &data->req;
|
||||
char *dupl = malloc(len);
|
||||
if(!dupl)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(dupl, ptr, len);
|
||||
|
||||
/* store this information in the state struct for later use */
|
||||
data->state.tempwrite = dupl;
|
||||
data->state.tempwritesize = len;
|
||||
data->state.tempwritetype = type;
|
||||
|
||||
/* mark the connection as RECV paused */
|
||||
k->keepon |= KEEP_READ_PAUSE;
|
||||
|
||||
DEBUGF(infof(data, "Pausing with %d bytes in buffer for type %02x\n",
|
||||
(int)len, type));
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* client_write() sends data to the write callback(s)
|
||||
|
||||
The bit pattern defines to what "streams" to write to. Body and/or header.
|
||||
@ -390,8 +420,37 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
||||
size_t wrote;
|
||||
|
||||
if(data->state.cancelled) {
|
||||
/* We just suck everything into a black hole */
|
||||
return CURLE_OK;
|
||||
/* We just suck everything into a black hole */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* If reading is actually paused, we're forced to append this chunk of data
|
||||
to the already held data, but only if it is the same type as otherwise it
|
||||
can't work and it'll return error instead. */
|
||||
if(data->req.keepon & KEEP_READ_PAUSE) {
|
||||
size_t newlen;
|
||||
char *newptr;
|
||||
if(type != data->state.tempwritetype)
|
||||
/* major internal confusion */
|
||||
return CURLE_RECV_ERROR;
|
||||
|
||||
/* figure out the new size of the data to save */
|
||||
newlen = len + data->state.tempwritesize;
|
||||
/* allocate the new memory area */
|
||||
newptr = malloc(newlen);
|
||||
if(!newptr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
/* copy the previously held data to the new area */
|
||||
memcpy(newptr, data->state.tempwrite, data->state.tempwritesize);
|
||||
/* copy the new data to the end of the new area */
|
||||
memcpy(newptr + data->state.tempwritesize, ptr, len);
|
||||
/* free the old data */
|
||||
free(data->state.tempwrite);
|
||||
/* update the pointer and the size */
|
||||
data->state.tempwrite = newptr;
|
||||
data->state.tempwritesize = newlen;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(0 == len)
|
||||
@ -422,8 +481,11 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
||||
wrote = len;
|
||||
}
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||
return pausewrite(data, type, ptr, len);
|
||||
|
||||
if(wrote != len) {
|
||||
failf (data, "Failed writing body");
|
||||
failf(data, "Failed writing body (%d != %d)", (int)wrote, (int)len);
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
}
|
||||
@ -441,6 +503,12 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
||||
regardless of the ftp transfer mode (ASCII/Image) */
|
||||
|
||||
wrote = writeit(ptr, 1, len, data->set.writeheader);
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||
/* here we pass in the HEADER bit only since if this was body as well
|
||||
then it was passed already and clearly that didn't trigger the pause,
|
||||
so this is saved for later with the HEADER bit only */
|
||||
return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
|
||||
|
||||
if(wrote != len) {
|
||||
failf (data, "Failed writing header");
|
||||
return CURLE_WRITE_ERROR;
|
||||
|
@ -134,6 +134,14 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
|
||||
failf(data, "operation aborted by callback\n");
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
else if(nread == CURL_READFUNC_PAUSE) {
|
||||
struct SingleRequest *k = &data->req;
|
||||
k->keepon |= KEEP_READ_PAUSE; /* mark reading as paused */
|
||||
return 0; /* nothing was read */
|
||||
}
|
||||
else if((size_t)nread > buffersize)
|
||||
/* the read function returned a too large value */
|
||||
return CURLE_READ_ERROR;
|
||||
|
||||
if(!conn->bits.forbidchunk && conn->bits.upload_chunky) {
|
||||
/* if chunked Transfer-Encoding */
|
||||
@ -330,7 +338,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
/* only use the proper socket if the *_HOLD bit is not set simultaneously as
|
||||
then we are in rate limiting state in that transfer direction */
|
||||
|
||||
if((k->keepon & (KEEP_READ|KEEP_READ_HOLD)) == KEEP_READ) {
|
||||
if((k->keepon & KEEP_READBITS) == KEEP_READ) {
|
||||
fd_read = conn->sockfd;
|
||||
#if defined(USE_LIBSSH2)
|
||||
if(conn->protocol & (PROT_SCP|PROT_SFTP))
|
||||
@ -339,7 +347,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
} else
|
||||
fd_read = CURL_SOCKET_BAD;
|
||||
|
||||
if((k->keepon & (KEEP_WRITE|KEEP_WRITE_HOLD)) == KEEP_WRITE)
|
||||
if((k->keepon & KEEP_WRITEBITS) == KEEP_WRITE)
|
||||
fd_write = conn->writesockfd;
|
||||
else
|
||||
fd_write = CURL_SOCKET_BAD;
|
||||
@ -1425,9 +1433,11 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
else
|
||||
nread = 0; /* we're done uploading/reading */
|
||||
|
||||
/* the signed int typecase of nread of for systems that has
|
||||
unsigned size_t */
|
||||
if(nread<=0) {
|
||||
if(!nread && (k->keepon & KEEP_READ_PAUSE)) {
|
||||
/* this is a paused transfer */
|
||||
break;
|
||||
}
|
||||
else if(nread<=0) {
|
||||
/* done */
|
||||
k->keepon &= ~KEEP_WRITE; /* we're done writing */
|
||||
writedone = TRUE;
|
||||
@ -1635,7 +1645,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||
}
|
||||
|
||||
/* Now update the "done" boolean we return */
|
||||
*done = (bool)(0 == (k->keepon&(KEEP_READ|KEEP_WRITE)));
|
||||
*done = (bool)(0 == (k->keepon&(KEEP_READ|KEEP_WRITE|KEEP_READ_PAUSE|KEEP_WRITE_PAUSE)));
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@ -1660,7 +1670,8 @@ int Curl_single_getsock(const struct connectdata *conn,
|
||||
/* simple check but we might need two slots */
|
||||
return GETSOCK_BLANK;
|
||||
|
||||
if(data->req.keepon & KEEP_READ) {
|
||||
/* don't include HOLD and PAUSE connections */
|
||||
if((data->req.keepon & KEEP_READBITS) == KEEP_READ) {
|
||||
|
||||
DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
|
||||
|
||||
@ -1668,7 +1679,8 @@ int Curl_single_getsock(const struct connectdata *conn,
|
||||
sock[sockindex] = conn->sockfd;
|
||||
}
|
||||
|
||||
if(data->req.keepon & KEEP_WRITE) {
|
||||
/* don't include HOLD and PAUSE connections */
|
||||
if((data->req.keepon & KEEP_WRITEBITS) == KEEP_WRITE) {
|
||||
|
||||
if((conn->sockfd != conn->writesockfd) ||
|
||||
!(data->req.keepon & KEEP_READ)) {
|
||||
@ -1751,10 +1763,17 @@ Transfer(struct connectdata *conn)
|
||||
k->keepon |= KEEP_READ_HOLD; /* hold it */
|
||||
}
|
||||
|
||||
/* The *_HOLD logic is necessary since even though there might be no
|
||||
traffic during the select interval, we still call Curl_readwrite() for
|
||||
the timeout case and if we limit transfer speed we must make sure that
|
||||
this function doesn't transfer anything while in HOLD status. */
|
||||
/* pause logic. Don't check descriptors for paused connections */
|
||||
if(k->keepon & KEEP_READ_PAUSE)
|
||||
fd_read = CURL_SOCKET_BAD;
|
||||
if(k->keepon & KEEP_WRITE_PAUSE)
|
||||
fd_write = CURL_SOCKET_BAD;
|
||||
|
||||
/* The *_HOLD and *_PAUSE logic is necessary since even though there might
|
||||
be no traffic during the select interval, we still call
|
||||
Curl_readwrite() for the timeout case and if we limit transfer speed we
|
||||
must make sure that this function doesn't transfer anything while in
|
||||
HOLD status. */
|
||||
|
||||
switch (Curl_socket_ready(fd_read, fd_write, 1000)) {
|
||||
case -1: /* select() error, stop reading */
|
||||
|
@ -4433,6 +4433,13 @@ CURLcode Curl_done(struct connectdata **connp,
|
||||
|
||||
Curl_pgrsDone(conn); /* done with the operation */
|
||||
|
||||
/* if the transfer was completed in a paused state there can be buffered
|
||||
data left to write and then kill */
|
||||
if(data->state.tempwrite) {
|
||||
free(data->state.tempwrite);
|
||||
data->state.tempwrite = NULL;
|
||||
}
|
||||
|
||||
/* for ares-using, make sure all possible outstanding requests are properly
|
||||
cancelled before we proceed */
|
||||
ares_cancel(data->state.areschannel);
|
||||
|
@ -629,12 +629,18 @@ struct hostname {
|
||||
*/
|
||||
|
||||
#define KEEP_NONE 0
|
||||
#define KEEP_READ 1 /* there is or may be data to read */
|
||||
#define KEEP_WRITE 2 /* there is or may be data to write */
|
||||
#define KEEP_READ_HOLD 4 /* when set, no reading should be done but there
|
||||
might still be data to read */
|
||||
#define KEEP_WRITE_HOLD 8 /* when set, no writing should be done but there
|
||||
might still be data to write */
|
||||
#define KEEP_READ (1<<0) /* there is or may be data to read */
|
||||
#define KEEP_WRITE (1<<1) /* there is or may be data to write */
|
||||
#define KEEP_READ_HOLD (1<<2) /* when set, no reading should be done but there
|
||||
might still be data to read */
|
||||
#define KEEP_WRITE_HOLD (1<<3) /* when set, no writing should be done but there
|
||||
might still be data to write */
|
||||
#define KEEP_READ_PAUSE (1<<4) /* reading is paused */
|
||||
#define KEEP_WRITE_PAUSE (1<<5) /* writing is paused */
|
||||
|
||||
#define KEEP_READBITS (KEEP_READ | KEEP_READ_HOLD | KEEP_READ_PAUSE)
|
||||
#define KEEP_WRITEBITS (KEEP_WRITE | KEEP_WRITE_HOLD | KEEP_WRITE_PAUSE)
|
||||
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
typedef enum {
|
||||
@ -1126,10 +1132,13 @@ struct UrlState {
|
||||
following not keep sending user+password... This is
|
||||
strdup() data.
|
||||
*/
|
||||
|
||||
struct curl_ssl_session *session; /* array of 'numsessions' size */
|
||||
long sessionage; /* number of the most recent session */
|
||||
|
||||
char *tempwrite; /* allocated buffer to keep data in when a write
|
||||
callback returns to make the connection paused */
|
||||
size_t tempwritesize; /* size of the 'tempwrite' allocated buffer */
|
||||
int tempwritetype; /* type of the 'tempwrite' buffer as a bitmask that is
|
||||
used with Curl_client_write() */
|
||||
char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */
|
||||
bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
|
||||
This must be set to FALSE every time _easy_perform() is
|
||||
|
Loading…
Reference in New Issue
Block a user