* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, 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
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * are also available at https://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
#include "url.h"
#include "getinfo.h"
#include "vtls/vtls.h"
-#include "http_digest.h"
-#include "curl_ntlm.h"
-#include "http_negotiate.h"
-#include "share.h"
-#include "curl_memory.h"
#include "select.h"
#include "multiif.h"
#include "connect.h"
#include "non-ascii.h"
+#include "curl_printf.h"
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
+/* The last #include files should be: */
+#include "curl_memory.h"
#include "memdebug.h"
/*
/* this function returns a size_t, so we typecast to int to prevent warnings
with picky compilers */
- nread = (int)conn->fread_func(data->req.upload_fromhere, 1,
- buffersize, conn->fread_in);
+ nread = (int)data->state.fread_func(data->req.upload_fromhere, 1,
+ buffersize, data->state.in);
if(nread == CURL_READFUNC_ABORT) {
failf(data, "operation aborted by callback");
result = Curl_convert_to_network(data, data->req.upload_fromhere, length);
/* Curl_convert_to_network calls failf if unsuccessful */
if(result)
- return(result);
+ return result;
#endif /* CURL_DOES_CONVERSIONS */
if((nread - hexlen) == 0)
/* If no CURLOPT_READFUNCTION is used, we know that we operate on a
given FILE * stream and we can actually attempt to rewind that
ourselves with fseek() */
- if(data->set.fread_func == (curl_read_callback)fread) {
- if(-1 != fseek(data->set.in, 0, SEEK_SET))
+ if(data->state.fread_func == (curl_read_callback)fread) {
+ if(-1 != fseek(data->state.in, 0, SEEK_SET))
/* successful rewind */
return CURLE_OK;
}
TRUE. The thing is if we read everything, then http2_recv won't
be called and we cannot signal the HTTP/2 stream has closed. As
a workaround, we return nonzero here to call http2_recv. */
- ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20 &&
- conn->proto.httpc.closed);
+ ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20);
#else
Curl_ssl_data_pending(conn, FIRSTSOCKET);
#endif
size_t excess = 0; /* excess bytes read */
bool is_empty_data = FALSE;
bool readmore = FALSE; /* used by RTP to signal for more data */
+ int maxloops = 100;
*done = FALSE;
data->set.buffer_size : BUFSIZE;
size_t bytestoread = buffersize;
- if(k->size != -1 && !k->header) {
+ if(
+#if defined(USE_NGHTTP2)
+ /* For HTTP/2, read data without caring about the content
+ length. This is safe because body in HTTP/2 is always
+ segmented thanks to its framing layer. Meanwhile, we have to
+ call Curl_read to ensure that http2_handle_stream_close is
+ called when we read all incoming bytes for a particular
+ stream. */
+ !((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ conn->httpversion == 20) &&
+#endif
+ k->size != -1 && !k->header) {
/* make sure we don't read "too much" if we can help it since we
might be pipelining and then someone else might want to read what
follows! */
else {
/* read nothing but since we wanted nothing we consider this an OK
situation to proceed from */
+ DEBUGF(infof(data, "readwrite_data: we're done!\n"));
nread = 0;
}
/* We've stopped dealing with input, get out of the do-while loop */
if(nread > 0) {
- if(Curl_multi_pipeline_enabled(conn->data->multi)) {
+ if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
infof(data,
"Rewinding stream by : %zd"
" bytes on url %s (zero-length body)\n",
if(dataleft != 0) {
infof(conn->data, "Leftovers after chunking: %zu bytes\n",
dataleft);
- if(Curl_multi_pipeline_enabled(conn->data->multi)) {
+ if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
/* only attempt the rewind if we truly are pipelining */
infof(conn->data, "Rewinding %zu bytes\n",dataleft);
read_rewind(conn, dataleft);
excess = (size_t)(k->bytecount + nread - k->maxdownload);
if(excess > 0 && !k->ignorebody) {
- if(Curl_multi_pipeline_enabled(conn->data->multi)) {
+ if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
/* The 'excess' amount below can't be more than BUFSIZE which
always will fit in a size_t */
infof(data,
result = Curl_unencode_gzip_write(conn, k, nread);
break;
- case COMPRESS:
default:
failf (data, "Unrecognized content encoding type. "
"libcurl understands `identity', `deflate' and `gzip' "
k->keepon &= ~KEEP_RECV;
}
- } while(data_pending(conn));
+ } while(data_pending(conn) && maxloops--);
if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
conn->bits.close ) {
*didwhat |= KEEP_SEND;
- /*
- * We loop here to do the READ and SEND loop until we run out of
- * data to send or until we get EWOULDBLOCK back
- *
- * FIXME: above comment is misleading. Currently no looping is
- * actually done in do-while loop below.
- */
do {
/* only read more data if there's no upload data already
if(!data->set.crlf) {
/* we're here only because FTP is in ASCII mode...
bump infilesize for the LF we just added */
- data->state.infilesize++;
+ if(data->state.infilesize != -1)
+ data->state.infilesize++;
}
}
else
* be read and written to/from the connection.
*/
CURLcode Curl_readwrite(struct connectdata *conn,
+ struct SessionHandle *data,
bool *done)
{
- struct SessionHandle *data = conn->data;
struct SingleRequest *k = &data->req;
CURLcode result;
int didwhat=0;
else
fd_write = CURL_SOCKET_BAD;
+ if(conn->data->state.drain) {
+ select_res |= CURL_CSELECT_IN;
+ DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n"));
+ }
+
if(!select_res) /* Call for select()/poll() only, if read/write/error
status is not known. */
select_res = Curl_socket_ready(fd_read, fd_write, 0);
* the next packet at the adjusted rate. We should wait
* longer when using larger packets, for instance.
*/
- rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps);
+ rv = ((curl_off_t)(pkt_size * 1000) / rate_bps);
/* Catch rounding errors and always slow down at least 1ms if
* we are running too fast.
return (long)rv;
}
+/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
+ which means this gets called once for each subsequent redirect etc */
+void Curl_init_CONNECT(struct SessionHandle *data)
+{
+ data->state.fread_func = data->set.fread_func_set;
+ data->state.in = data->set.in_set;
+}
+
/*
- * Curl_pretransfer() is called immediately before a transfer starts.
+ * Curl_pretransfer() is called immediately before a transfer starts, and only
+ * once for one transfer no matter if it has redirects or do multi-pass
+ * authentication etc.
*/
CURLcode Curl_pretransfer(struct SessionHandle *data)
{
Curl_safefree(data->info.wouldredirect);
data->info.wouldredirect = NULL;
+ if(data->set.httpreq == HTTPREQ_PUT)
+ data->state.infilesize = data->set.filesize;
+ else
+ data->state.infilesize = data->set.postfieldsize;
+
/* If there is a list of cookie files to read, do it now! */
if(data->change.cookielist)
Curl_cookie_loadfiles(data);
#endif
Curl_initinfo(data); /* reset session-specific information "variables" */
+ Curl_pgrsResetTimesSizes(data);
Curl_pgrsStartNow(data);
if(data->set.timeout)
*/
static size_t strlen_url(const char *url)
{
- const char *ptr;
+ const unsigned char *ptr;
size_t newlen=0;
bool left=TRUE; /* left side of the ? */
- for(ptr=url; *ptr; ptr++) {
+ for(ptr=(unsigned char *)url; *ptr; ptr++) {
switch(*ptr) {
case '?':
left=FALSE;
/* fall through */
default:
+ if(*ptr >= 0x80)
+ newlen += 2;
newlen++;
break;
case ' ':
{
/* we must add this with whitespace-replacing */
bool left=TRUE;
- const char *iptr;
+ const unsigned char *iptr;
char *optr = output;
- for(iptr = url; /* read from here */
+ for(iptr = (unsigned char *)url; /* read from here */
*iptr; /* until zero byte */
iptr++) {
switch(*iptr) {
left=FALSE;
/* fall through */
default:
- *optr++=*iptr;
+ if(*iptr >= 0x80) {
+ snprintf(optr, 4, "%%%02x", *iptr);
+ optr += 3;
+ }
+ else
+ *optr++=*iptr;
break;
case ' ':
if(left) {
if(type == FOLLOW_REDIR) {
if((data->set.maxredirs != -1) &&
(data->set.followlocation >= data->set.maxredirs)) {
- failf(data,"Maximum (%ld) redirects followed", data->set.maxredirs);
+ failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
return CURLE_TOO_MANY_REDIRECTS;
}
newurl = absolute;
}
else {
+ /* The new URL MAY contain space or high byte values, that means a mighty
+ stupid redirect URL but we still make an effort to do "right". */
+ char *newest;
+ size_t newlen = strlen_url(newurl);
+
/* This is an absolute URL, don't allow the custom port number */
disallowport = TRUE;
- if(strchr(newurl, ' ')) {
- /* This new URL contains at least one space, this is a mighty stupid
- redirect but we still make an effort to do "right". */
- char *newest;
- size_t newlen = strlen_url(newurl);
-
- newest = malloc(newlen+1); /* get memory for this */
- if(!newest)
- return CURLE_OUT_OF_MEMORY;
- strcpy_url(newest, newurl); /* create a space-free URL */
+ newest = malloc(newlen+1); /* get memory for this */
+ if(!newest)
+ return CURLE_OUT_OF_MEMORY;
+ strcpy_url(newest, newurl); /* create a space-free URL */
- free(newurl); /* that was no good */
- newurl = newest; /* use this instead now */
- }
+ free(newurl); /* that was no good */
+ newurl = newest; /* use this instead now */
}