summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Fuller <jim@webcomposite.com>2018-11-01 19:16:15 +0100
committerDaniel Stenberg <daniel@haxx.se>2018-11-09 15:47:28 +0100
commit5c4fe0d8264a4a4f591d79cefe9676b099bdecf2 (patch)
treed33052e3032909ef366f705e9876780aec64b72f
parent073332b52515391338cff7bbe407d126fdf9c893 (diff)
downloadcurl-5c4fe0d8264a4a4f591d79cefe9676b099bdecf2.tar.gz
setopt: add CURLOPT_CURLU
Allows an application to pass in a pre-parsed URL via a URL handle. Closes #3227
-rw-r--r--docs/examples/Makefile.inc3
-rw-r--r--docs/examples/urlapi.c72
-rw-r--r--docs/libcurl/curl_easy_setopt.32
-rw-r--r--docs/libcurl/opts/CURLOPT_CURLU.361
-rw-r--r--docs/libcurl/opts/Makefile.inc1
-rw-r--r--docs/libcurl/symbols-in-versions1
-rw-r--r--include/curl/curl.h3
-rw-r--r--include/curl/typecheck-gcc.h1
-rw-r--r--lib/setopt.c6
-rw-r--r--lib/transfer.c15
-rw-r--r--lib/url.c19
-rw-r--r--lib/urldata.h1
-rw-r--r--tests/data/Makefile.inc2
-rw-r--r--tests/data/test65850
-rw-r--r--tests/libtest/Makefile.inc6
-rw-r--r--tests/libtest/lib658.c76
16 files changed, 310 insertions, 9 deletions
diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc
index f51871f06..8dd55b9df 100644
--- a/docs/examples/Makefile.inc
+++ b/docs/examples/Makefile.inc
@@ -34,7 +34,8 @@ check_PROGRAMS = 10-at-a-time anyauthput cookie_interface debug fileupload \
imap-tls imap-multi url2file sftpget ftpsget postinmemory http2-download \
http2-upload http2-serverpush getredirect ftpuploadfrommem \
ftpuploadresume sslbackend postit2-formadd multi-formadd \
- shared-connection-cache sftpuploadresume http2-pushinmemory parseurl
+ shared-connection-cache sftpuploadresume http2-pushinmemory parseurl \
+ urlapi
# These examples require external dependencies that may not be commonly
# available on POSIX systems, so don't bother attempting to compile them here.
diff --git a/docs/examples/urlapi.c b/docs/examples/urlapi.c
new file mode 100644
index 000000000..594f9420d
--- /dev/null
+++ b/docs/examples/urlapi.c
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2018, 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 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
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/* <DESC>
+ * Set working URL with CURLU *.
+ * </DESC>
+ */
+#include <stdio.h>
+#include <curl/curl.h>
+
+#if !CURL_AT_LEAST_VERSION(7, 62, 0)
+#error "this example requires curl 7.62.0 or later"
+#endif
+
+int main(void)
+{
+ CURL *curl;
+ CURLcode res;
+
+ CURLU *urlp;
+ CURLUcode uc;
+
+ /* get a curl handle */
+ curl = curl_easy_init();
+
+ /* init Curl URL */
+ urlp = curl_url();
+ uc = curl_url_set(urlp, CURLUPART_URL,
+ "http://example.com/path/index.html", 0);
+
+ if(uc) {
+ fprintf(stderr, "curl_url_set() failed: %in", uc);
+ goto cleanup;
+ }
+
+ if(curl) {
+ /* set urlp to use as working URL */
+ curl_easy_setopt(curl, CURLOPT_CURLU, urlp);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ res = curl_easy_perform(curl);
+ /* Check for errors */
+ if(res != CURLE_OK)
+ fprintf(stderr, "curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(res));
+
+ goto cleanup;
+ }
+
+ cleanup:
+ curl_url_cleanup(urlp);
+ curl_easy_cleanup(curl);
+ return 0;
+}
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index bde52f999..f4b89c2f8 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -407,6 +407,8 @@ Range requests. See \fICURLOPT_RANGE(3)\fP
Resume a transfer. See \fICURLOPT_RESUME_FROM(3)\fP
.IP CURLOPT_RESUME_FROM_LARGE
Resume a transfer. See \fICURLOPT_RESUME_FROM_LARGE(3)\fP
+.IP CURLOPT_CURLU
+Set URL to work on with CURLU *. See \fICURLOPT_CURLU(3)\fP
.IP CURLOPT_CUSTOMREQUEST
Custom request/method. See \fICURLOPT_CUSTOMREQUEST(3)\fP
.IP CURLOPT_FILETIME
diff --git a/docs/libcurl/opts/CURLOPT_CURLU.3 b/docs/libcurl/opts/CURLOPT_CURLU.3
new file mode 100644
index 000000000..5c762c9a1
--- /dev/null
+++ b/docs/libcurl/opts/CURLOPT_CURLU.3
@@ -0,0 +1,61 @@
+.\" **************************************************************************
+.\" * _ _ ____ _
+.\" * Project ___| | | | _ \| |
+.\" * / __| | | | |_) | |
+.\" * | (__| |_| | _ <| |___
+.\" * \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2018, 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 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
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_CURLU 3 "28 Oct 2018" "libcurl 7.63.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_CURLU \- set URL with CURLU *
+.SH SYNOPSIS
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CURLU, void *pointer);
+.SH DESCRIPTION
+Pass in a pointer to the \fIURL\fP to work with. The parameter should be a
+CURLU *. Setting \fICURLOPT_CURLU(3)\fP will explicitly override \fICURLOPT_URL(3)\fP.
+
+.SH DEFAULT
+The default value of this parameter is NULL.
+.SH PROTOCOLS
+All
+.SH EXAMPLE
+.nf
+CURL *handle = curl_easy_init();
+CURLU *urlp = curl_url();
+int res = 0;
+if(curl) {
+
+ res = curl_url_set(urlp, CURLUPART_URL, "http://example.com", 0);
+
+ curl_easy_setopt(handle, CURLOPT_CURLU, urlp);
+
+ ret = curl_easy_perform(handle);
+
+ curl_url_cleanup(urlp);
+ curl_easy_cleanup(handle);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.63.0.
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLOPT_URL "(3), "
+.BR curl_url "(3), " curl_url_get "(3), " curl_url_set "(3), "
diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc
index 117842dc3..e58db5f4a 100644
--- a/docs/libcurl/opts/Makefile.inc
+++ b/docs/libcurl/opts/Makefile.inc
@@ -111,6 +111,7 @@ man_MANS = \
CURLOPT_CRLF.3 \
CURLOPT_CRLFILE.3 \
CURLOPT_CUSTOMREQUEST.3 \
+ CURLOPT_CURLU.3 \
CURLOPT_DEBUGDATA.3 \
CURLOPT_DEBUGFUNCTION.3 \
CURLOPT_DEFAULT_PROTOCOL.3 \
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 2ca08ea3f..6c17c384c 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -371,6 +371,7 @@ CURLOPT_COOKIESESSION 7.9.7
CURLOPT_COPYPOSTFIELDS 7.17.1
CURLOPT_CRLF 7.1
CURLOPT_CRLFILE 7.19.0
+CURLOPT_CURLU 7.63.0
CURLOPT_CUSTOMREQUEST 7.1
CURLOPT_DEBUGDATA 7.9.6
CURLOPT_DEBUGFUNCTION 7.9.6
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 0b66f1462..5177e3571 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1872,6 +1872,9 @@ typedef enum {
/* Time in ms between connection upkeep calls for long-lived connections. */
CINIT(UPKEEP_INTERVAL_MS, LONG, 281),
+ /* Specify URL using CURL URL API. */
+ CINIT(CURLU, OBJECTPOINT, 282),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h
index 244336204..01df7b15f 100644
--- a/include/curl/typecheck-gcc.h
+++ b/include/curl/typecheck-gcc.h
@@ -363,6 +363,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SSL_CTX_DATA || \
(option) == CURLOPT_WRITEDATA || \
(option) == CURLOPT_RESOLVER_START_DATA || \
+ (option) == CURLOPT_CURLU || \
0)
/* evaluates to true if option takes a POST data argument (void* or char*) */
diff --git a/lib/setopt.c b/lib/setopt.c
index 22956a20f..1627aba6d 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -1204,6 +1204,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.low_speed_time = arg;
break;
+ case CURLOPT_CURLU:
+ /*
+ * pass CURLU to set URL
+ */
+ data->set.uh = va_arg(param, CURLU *);
+ break;
case CURLOPT_URL:
/*
* The URL to fetch.
diff --git a/lib/transfer.c b/lib/transfer.c
index de6043d7d..32ca5a496 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -1353,17 +1353,30 @@ void Curl_init_CONNECT(struct Curl_easy *data)
CURLcode Curl_pretransfer(struct Curl_easy *data)
{
CURLcode result;
- if(!data->change.url) {
+
+ if(!data->change.url && !data->set.uh) {
/* we can't do anything without URL */
failf(data, "No URL set!");
return CURLE_URL_MALFORMAT;
}
+
/* since the URL may have been redirected in a previous use of this handle */
if(data->change.url_alloc) {
/* the already set URL is allocated, free it first! */
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
+
+ if(!data->change.url && data->set.uh) {
+ CURLUcode uc;
+ uc = curl_url_get(data->set.uh,
+ CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
+ if(uc) {
+ failf(data, "No URL set!");
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+
data->change.url = data->set.str[STRING_SET_URL];
/* Init the SSL session ID cache here. We do it here since we want to do it
diff --git a/lib/url.c b/lib/url.c
index dd9fa2617..6118177d6 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2026,7 +2026,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
Curl_up_free(data); /* cleanup previous leftovers first */
/* parse the URL */
- uh = data->state.uh = curl_url();
+ if(data->set.uh) {
+ uh = data->set.uh;
+ }
+ else {
+ uh = data->state.uh = curl_url();
+ }
+
if(!uh)
return CURLE_OUT_OF_MEMORY;
@@ -2043,15 +2049,17 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
data->change.url_alloc = TRUE;
}
- uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
+ if(!data->set.uh) {
+ uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
(data->set.disallow_username_in_url ?
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
- if(uc) {
- DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
- return Curl_uc_to_curlcode(uc);
+ if(uc) {
+ DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
+ return Curl_uc_to_curlcode(uc);
+ }
}
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
@@ -2193,6 +2201,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OK;
}
+
/*
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
diff --git a/lib/urldata.h b/lib/urldata.h
index 11a6a22c6..eae73a19f 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1728,6 +1728,7 @@ struct UserDefined {
bool doh_get; /* use GET for DoH requests, instead of POST */
multidone_func fmultidone;
struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
+ CURLU *uh; /* URL handle for the current parsed URL */
};
struct Names {
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 669a482de..e58fb27fb 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -83,7 +83,7 @@ test617 test618 test619 test620 test621 test622 test623 test624 test625 \
test626 test627 test628 test629 test630 test631 test632 test633 test634 \
test635 test636 test637 test638 test639 test640 test641 test642 \
test643 test644 test645 test646 test647 test648 test649 test650 test651 \
-test652 test653 test654 test655 test656 \
+test652 test653 test654 test655 test656 test658 \
\
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
test709 test710 test711 test712 test713 test714 test715 \
diff --git a/tests/data/test658 b/tests/data/test658
new file mode 100644
index 000000000..c75293c6d
--- /dev/null
+++ b/tests/data/test658
@@ -0,0 +1,50 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+</keywords>
+</info>
+<reply>
+<data nocheck="yes">
+HTTP/1.1 200 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+</reply>
+<client>
+<server>
+http
+</server>
+<tool>
+lib658
+</tool>
+<name>
+HTTP GET
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/658
+</command>
+</client>
+
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /658 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</verify>
+
+</testcase>
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 7a3cd1665..6dc7511f1 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -21,7 +21,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib559 lib560 lib562 lib564 lib565 lib566 lib567 lib568 lib569 lib570 \
lib571 lib572 lib573 lib574 lib575 lib576 lib578 lib579 lib582 \
lib583 lib585 lib586 lib587 lib589 lib590 lib591 lib597 lib598 lib599 \
- lib643 lib644 lib645 lib650 lib651 lib652 lib653 lib654 lib655 \
+ lib643 lib644 lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658 \
lib1156 \
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 lib1517 \
@@ -339,6 +339,10 @@ lib654_CPPFLAGS = $(AM_CPPFLAGS)
lib655_SOURCES = lib655.c $(SUPPORTFILES)
lib655_CPPFLAGS = $(AM_CPPFLAGS)
+lib658_SOURCES = lib658.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+lib658_LDADD = $(TESTUTIL_LIBS)
+lib658_CPPFLAGS = $(AM_CPPFLAGS)
+
lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
lib1500_LDADD = $(TESTUTIL_LIBS)
lib1500_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/tests/libtest/lib658.c b/tests/libtest/lib658.c
new file mode 100644
index 000000000..98e0db4b4
--- /dev/null
+++ b/tests/libtest/lib658.c
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 2018, 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 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
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "test.h"
+
+#include "testutil.h"
+#include "warnless.h"
+#include "memdebug.h"
+
+/*
+ * Get a single URL without select().
+ */
+
+int test(char *URL)
+{
+ CURL *handle = NULL;
+ CURLcode res = 0;
+ CURLU *urlp = NULL;
+ CURLUcode uc = 0;
+
+ global_init(CURL_GLOBAL_ALL);
+ easy_init(handle);
+
+ urlp = curl_url();
+
+ if(!urlp) {
+ fprintf(stderr, "problem init URL api.");
+ goto test_cleanup;
+ }
+
+ uc = curl_url_set(urlp, CURLUPART_URL, URL, 0);
+ if(uc) {
+ fprintf(stderr, "problem setting CURLUPART_URL.");
+ goto test_cleanup;
+ }
+
+ /* demonstrate override behavior */
+ easy_setopt(handle, CURLOPT_URL, "http://www.example.com");
+
+ easy_setopt(handle, CURLOPT_CURLU, urlp);
+ easy_setopt(handle, CURLOPT_VERBOSE, 1L);
+
+ res = curl_easy_perform(handle);
+
+ if(res) {
+ fprintf(stderr, "%s:%d curl_easy_perform() failed with code %d (%s)\n",
+ __FILE__, __LINE__, res, curl_easy_strerror(res));
+ goto test_cleanup;
+ }
+
+test_cleanup:
+
+ curl_url_cleanup(urlp);
+ curl_easy_cleanup(handle);
+ curl_global_cleanup();
+
+ return res;
+}