summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/url.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/url.c')
-rw-r--r--Utilities/cmcurl/lib/url.c156
1 files changed, 104 insertions, 52 deletions
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index caa28f5..87446db 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -140,6 +140,19 @@ static CURLcode parse_login_details(const char *login, const size_t len,
char **optionsptr);
static unsigned int get_protocol_family(unsigned int protocol);
+#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
+#define READBUFFER_MAX CURL_MAX_READ_SIZE
+#define READBUFFER_MIN 1024
+
+/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
+ * more than just a few bytes to play with. Don't let it become too small or
+ * bad things will happen.
+ */
+#if READBUFFER_SIZE < READBUFFER_MIN
+# error READBUFFER_SIZE is too small
+#endif
+
+
/*
* Protocol table.
*/
@@ -607,6 +620,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
set->expect_100_timeout = 1000L; /* Wait for a second by default. */
set->sep_headers = TRUE; /* separated header lists by default */
+ set->buffer_size = READBUFFER_SIZE;
Curl_http2_init_userset(set);
return result;
@@ -644,7 +658,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
/* We do some initial setup here, all those fields that can't be just 0 */
- data->state.buffer = malloc(BUFSIZE + 1);
+ data->state.buffer = malloc(READBUFFER_SIZE + 1);
if(!data->state.buffer) {
DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
result = CURLE_OUT_OF_MEMORY;
@@ -1009,8 +1023,8 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
* other - POST is kept as POST after 301 and 302
*/
- int postRedir = curlx_sltosi(va_arg(param, long));
- data->set.keep_post = postRedir & CURL_REDIR_POST_ALL;
+ arg = va_arg(param, long);
+ data->set.keep_post = arg & CURL_REDIR_POST_ALL;
}
break;
@@ -2061,13 +2075,19 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
/*
* Set what local port to bind the socket to when performing an operation.
*/
- data->set.localport = curlx_sltous(va_arg(param, long));
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.localport = curlx_sltous(arg);
break;
case CURLOPT_LOCALPORTRANGE:
/*
* Set number of local ports to try, starting with CURLOPT_LOCALPORT.
*/
- data->set.localportrange = curlx_sltosi(va_arg(param, long));
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.localportrange = curlx_sltosi(arg);
break;
case CURLOPT_KRBLEVEL:
/*
@@ -2284,22 +2304,26 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* The application kindly asks for a differently sized receive buffer.
* If it seems reasonable, we'll use it.
*/
- data->set.buffer_size = va_arg(param, long);
-
- if(data->set.buffer_size > MAX_BUFSIZE)
- data->set.buffer_size = MAX_BUFSIZE; /* huge internal default */
- else if(data->set.buffer_size < 1)
- data->set.buffer_size = BUFSIZE;
+ arg = va_arg(param, long);
- /* Resize only if larger than default buffer size. */
- if(data->set.buffer_size > BUFSIZE) {
- data->state.buffer = realloc(data->state.buffer,
- data->set.buffer_size + 1);
- if(!data->state.buffer) {
+ if(arg > READBUFFER_MAX)
+ arg = READBUFFER_MAX;
+ else if(arg < 1)
+ arg = READBUFFER_SIZE;
+ else if(arg < READBUFFER_MIN)
+ arg = READBUFFER_MIN;
+
+ /* Resize if new size */
+ if(arg != data->set.buffer_size) {
+ char *newbuff = realloc(data->state.buffer, arg + 1);
+ if(!newbuff) {
DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
result = CURLE_OUT_OF_MEMORY;
}
+ else
+ data->state.buffer = newbuff;
}
+ data->set.buffer_size = arg;
break;
@@ -2592,7 +2616,10 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* know that an unsigned int will always hold the value so we blindly
* typecast to this type
*/
- data->set.scope_id = curlx_sltoui(va_arg(param, long));
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 0xf))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.scope_id = curlx_sltoui(arg);
break;
case CURLOPT_PROTOCOLS:
@@ -2794,13 +2821,17 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
break;
case CURLOPT_TLSAUTH_TYPE:
- if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP")))
+ argptr = va_arg(param, char *);
+ if(!argptr ||
+ strncasecompare(argptr, "SRP", strlen("SRP")))
data->set.ssl.authtype = CURL_TLSAUTH_SRP;
else
data->set.ssl.authtype = CURL_TLSAUTH_NONE;
break;
case CURLOPT_PROXY_TLSAUTH_TYPE:
- if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP")))
+ argptr = va_arg(param, char *);
+ if(!argptr ||
+ strncasecompare(argptr, "SRP", strlen("SRP")))
data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP;
else
data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
@@ -2935,8 +2966,7 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
conn_reset_postponed_data(conn, 1);
}
#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
-/* Use "do-nothing" macros instead of functions when workaround not used */
-#define conn_reset_postponed_data(c,n) do {} WHILE_FALSE
+/* Use "do-nothing" macro instead of function when workaround not used */
#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
@@ -2993,6 +3023,7 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
Curl_safefree(conn->master_buffer);
+ Curl_safefree(conn->connect_buffer);
conn_reset_all_postponed_data(conn);
@@ -3100,12 +3131,16 @@ static bool SocketIsDead(curl_socket_t sock)
}
/*
- * IsPipeliningPossible() returns TRUE if the options set would allow
- * pipelining/multiplexing and the connection is using a HTTP protocol.
+ * IsPipeliningPossible()
+ *
+ * Return a bitmask with the available pipelining and multiplexing options for
+ * the given requested connection.
*/
-static bool IsPipeliningPossible(const struct Curl_easy *handle,
- const struct connectdata *conn)
+static int IsPipeliningPossible(const struct Curl_easy *handle,
+ const struct connectdata *conn)
{
+ int avail = 0;
+
/* If a HTTP protocol and pipelining is enabled */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(!conn->bits.protoconnstart || !conn->bits.close)) {
@@ -3115,14 +3150,14 @@ static bool IsPipeliningPossible(const struct Curl_easy *handle,
(handle->set.httpreq == HTTPREQ_GET ||
handle->set.httpreq == HTTPREQ_HEAD))
/* didn't ask for HTTP/1.0 and a GET or HEAD */
- return TRUE;
+ avail |= CURLPIPE_HTTP1;
if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) &&
(handle->set.httpversion >= CURL_HTTP_VERSION_2))
/* allows HTTP/2 */
- return TRUE;
+ avail |= CURLPIPE_MULTIPLEX;
}
- return FALSE;
+ return avail;
}
int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
@@ -3409,7 +3444,7 @@ ConnectionExists(struct Curl_easy *data,
struct connectdata *check;
struct connectdata *chosen = 0;
bool foundPendingCandidate = FALSE;
- bool canPipeline = IsPipeliningPossible(data, needle);
+ int canpipe = IsPipeliningPossible(data, needle);
struct connectbundle *bundle;
#ifdef USE_NTLM
@@ -3425,10 +3460,10 @@ ConnectionExists(struct Curl_easy *data,
*force_reuse = FALSE;
*waitpipe = FALSE;
- /* We can't pipe if the site is blacklisted */
- if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) {
- canPipeline = FALSE;
- }
+ /* We can't pipeline if the site is blacklisted */
+ if((canpipe & CURLPIPE_HTTP1) &&
+ Curl_pipeline_site_blacklisted(data, needle))
+ canpipe &= ~ CURLPIPE_HTTP1;
/* Look up the bundle with all the connections to this
particular host */
@@ -3448,8 +3483,8 @@ ConnectionExists(struct Curl_easy *data,
(bundle->multiuse == BUNDLE_MULTIPLEX ?
"can multiplex" : "serially")));
- /* We can't pipe if we don't know anything about the server */
- if(canPipeline) {
+ /* We can't pipeline if we don't know anything about the server */
+ if(canpipe) {
if(bundle->multiuse <= BUNDLE_UNKNOWN) {
if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
infof(data, "Server doesn't support multi-use yet, wait\n");
@@ -3458,18 +3493,18 @@ ConnectionExists(struct Curl_easy *data,
}
infof(data, "Server doesn't support multi-use (yet)\n");
- canPipeline = FALSE;
+ canpipe = 0;
}
if((bundle->multiuse == BUNDLE_PIPELINING) &&
!Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) {
/* not asked for, switch off */
infof(data, "Could pipeline, but not asked to!\n");
- canPipeline = FALSE;
+ canpipe = 0;
}
else if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
!Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) {
infof(data, "Could multiplex, but not asked to!\n");
- canPipeline = FALSE;
+ canpipe = 0;
}
}
@@ -3490,20 +3525,21 @@ ConnectionExists(struct Curl_easy *data,
pipeLen = check->send_pipe.size + check->recv_pipe.size;
- if(canPipeline) {
+ if(canpipe) {
if(check->bits.protoconnstart && check->bits.close)
continue;
if(!check->bits.multiplex) {
- /* If not multiplexing, make sure the pipe has only GET requests */
+ /* If not multiplexing, make sure the connection is fine for HTTP/1
+ pipelining */
struct Curl_easy* sh = gethandleathead(&check->send_pipe);
struct Curl_easy* rh = gethandleathead(&check->recv_pipe);
if(sh) {
- if(!IsPipeliningPossible(sh, check))
+ if(!(IsPipeliningPossible(sh, check) & CURLPIPE_HTTP1))
continue;
}
else if(rh) {
- if(!IsPipeliningPossible(rh, check))
+ if(!(IsPipeliningPossible(rh, check) & CURLPIPE_HTTP1))
continue;
}
}
@@ -3611,7 +3647,7 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if(!canPipeline && check->inuse)
+ if(!canpipe && check->inuse)
/* this request can't be pipelined but the checked connection is
already in use so we skip it */
continue;
@@ -3742,7 +3778,7 @@ ConnectionExists(struct Curl_easy *data,
continue;
}
#endif
- if(canPipeline) {
+ if(canpipe) {
/* We can pipeline if we want to. Let's continue looking for
the optimal connection to use, i.e the shortest pipe that is not
blacklisted. */
@@ -4203,7 +4239,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) &&
!conn->master_buffer) {
/* Allocate master_buffer to be used for HTTP/1 pipelining */
- conn->master_buffer = calloc(BUFSIZE, sizeof(char));
+ conn->master_buffer = calloc(MASTERBUF_SIZE, sizeof(char));
if(!conn->master_buffer)
goto error;
}
@@ -4430,6 +4466,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
#endif
protop = "file"; /* protocol string */
+ *prot_missing = !url_has_scheme;
}
else {
/* clear path */
@@ -4593,14 +4630,30 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
size_t plen = strlen(path); /* new path, should be 1 byte longer than
the original */
- size_t urllen = strlen(data->change.url); /* original URL length */
-
size_t prefixlen = strlen(conn->host.name);
- if(!*prot_missing)
- prefixlen += strlen(protop) + strlen("://");
+ if(!*prot_missing) {
+ size_t protolen = strlen(protop);
+
+ if(curl_strnequal(protop, data->change.url, protolen))
+ prefixlen += protolen;
+ else {
+ failf(data, "<url> malformed");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ if(curl_strnequal("://", &data->change.url[protolen], 3))
+ prefixlen += 3;
+ /* only file: is allowed to omit one or both slashes */
+ else if(curl_strnequal("file:", data->change.url, 5))
+ prefixlen += 1 + (data->change.url[5] == '/');
+ else {
+ failf(data, "<url> malformed");
+ return CURLE_URL_MALFORMAT;
+ }
+ }
- reurl = malloc(urllen + 2); /* 2 for zerobyte + slash */
+ reurl = malloc(prefixlen + plen + 1);
if(!reurl)
return CURLE_OUT_OF_MEMORY;
@@ -6961,7 +7014,6 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
k->bytecount = 0;
k->buf = data->state.buffer;
- k->uploadbuf = data->state.uploadbuffer;
k->hbufp = data->state.headerbuff;
k->ignorebody=FALSE;
@@ -6985,7 +7037,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
* Returns the family as a single bit protocol identifier.
*/
-unsigned int get_protocol_family(unsigned int protocol)
+static unsigned int get_protocol_family(unsigned int protocol)
{
unsigned int family;