setopt: add CURLOPT_CURLU

Allows an application to pass in a pre-parsed URL via a URL handle.

Closes #3227
This commit is contained in:
Jim Fuller 2018-11-01 19:16:15 +01:00 committed by Daniel Stenberg
parent 073332b525
commit 5c4fe0d826
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
16 changed files with 310 additions and 9 deletions

View File

@ -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.

72
docs/examples/urlapi.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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), "

View File

@ -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 \

View File

@ -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

View File

@ -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;

View File

@ -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*) */

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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 {

View File

@ -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 \

50
tests/data/test658 Normal file
View File

@ -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>

View File

@ -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)

76
tests/libtest/lib658.c Normal file
View File

@ -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;
}