mirror of
https://github.com/moparisthebest/curl
synced 2024-12-23 08:38:49 -05:00
URL-API
See header file and man pages for API. All documented API details work and are tested in the 1560 test case. Closes #2842
This commit is contained in:
parent
17ca0ccff4
commit
fb30ac5a2d
@ -1,25 +1,82 @@
|
||||
# Shared between Makefile.am and CMakeLists.txt
|
||||
|
||||
man_MANS = curl_easy_cleanup.3 curl_easy_getinfo.3 curl_easy_init.3 \
|
||||
curl_easy_perform.3 curl_easy_setopt.3 curl_easy_duphandle.3 \
|
||||
curl_formadd.3 curl_formfree.3 curl_getdate.3 curl_getenv.3 \
|
||||
curl_slist_append.3 curl_slist_free_all.3 curl_version.3 \
|
||||
curl_version_info.3 curl_escape.3 curl_unescape.3 curl_free.3 \
|
||||
curl_strequal.3 curl_strnequal.3 curl_mprintf.3 curl_global_init.3 \
|
||||
curl_global_cleanup.3 curl_multi_add_handle.3 curl_multi_cleanup.3 \
|
||||
curl_multi_fdset.3 curl_multi_info_read.3 curl_multi_init.3 \
|
||||
curl_multi_perform.3 curl_multi_remove_handle.3 curl_share_cleanup.3 \
|
||||
curl_share_init.3 curl_share_setopt.3 libcurl.3 libcurl-easy.3 \
|
||||
libcurl-multi.3 libcurl-share.3 libcurl-errors.3 curl_easy_strerror.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_easy_pause.3 curl_easy_recv.3 curl_easy_send.3 \
|
||||
curl_multi_socket_action.3 curl_multi_wait.3 libcurl-symbols.3 \
|
||||
libcurl-thread.3 curl_multi_socket_all.3 curl_global_sslset.3 \
|
||||
curl_mime_init.3 curl_mime_free.3 curl_mime_addpart.3 curl_mime_name.3 \
|
||||
curl_mime_data.3 curl_mime_data_cb.3 curl_mime_filedata.3 \
|
||||
curl_mime_filename.3 curl_mime_subparts.3 \
|
||||
curl_mime_type.3 curl_mime_headers.3 curl_mime_encoder.3 libcurl-env.3 \
|
||||
libcurl-security.3 curl_easy_upkeep.3
|
||||
man_MANS = \
|
||||
curl_easy_cleanup.3 \
|
||||
curl_easy_duphandle.3 \
|
||||
curl_easy_escape.3 \
|
||||
curl_easy_getinfo.3 \
|
||||
curl_easy_init.3 \
|
||||
curl_easy_pause.3 \
|
||||
curl_easy_perform.3 \
|
||||
curl_easy_recv.3 \
|
||||
curl_easy_reset.3 \
|
||||
curl_easy_send.3 \
|
||||
curl_easy_setopt.3 \
|
||||
curl_easy_strerror.3 \
|
||||
curl_easy_unescape.3 \
|
||||
curl_easy_upkeep.3 \
|
||||
curl_escape.3 \
|
||||
curl_formadd.3 \
|
||||
curl_formfree.3 \
|
||||
curl_formget.3 \
|
||||
curl_free.3 \
|
||||
curl_getdate.3 \
|
||||
curl_getenv.3 \
|
||||
curl_global_cleanup.3 \
|
||||
curl_global_init.3 \
|
||||
curl_global_init_mem.3 \
|
||||
curl_global_sslset.3 \
|
||||
curl_mime_addpart.3 \
|
||||
curl_mime_data.3 \
|
||||
curl_mime_data_cb.3 \
|
||||
curl_mime_encoder.3 \
|
||||
curl_mime_filedata.3 \
|
||||
curl_mime_filename.3 \
|
||||
curl_mime_free.3 \
|
||||
curl_mime_headers.3 \
|
||||
curl_mime_init.3 \
|
||||
curl_mime_name.3 \
|
||||
curl_mime_subparts.3 \
|
||||
curl_mime_type.3 \
|
||||
curl_mprintf.3 \
|
||||
curl_multi_add_handle.3 \
|
||||
curl_multi_assign.3 \
|
||||
curl_multi_cleanup.3 \
|
||||
curl_multi_fdset.3 \
|
||||
curl_multi_info_read.3 \
|
||||
curl_multi_init.3 \
|
||||
curl_multi_perform.3 \
|
||||
curl_multi_remove_handle.3 \
|
||||
curl_multi_setopt.3 \
|
||||
curl_multi_socket.3 \
|
||||
curl_multi_socket_action.3 \
|
||||
curl_multi_socket_all.3 \
|
||||
curl_multi_strerror.3 \
|
||||
curl_multi_timeout.3 \
|
||||
curl_multi_wait.3 \
|
||||
curl_share_cleanup.3 \
|
||||
curl_share_init.3 \
|
||||
curl_share_setopt.3 \
|
||||
curl_share_strerror.3 \
|
||||
curl_slist_append.3 \
|
||||
curl_slist_free_all.3 \
|
||||
curl_strequal.3 \
|
||||
curl_strnequal.3 \
|
||||
curl_unescape.3 \
|
||||
curl_url.3 \
|
||||
curl_url_cleanup.3 \
|
||||
curl_url_dup.3 \
|
||||
curl_url_get.3 \
|
||||
curl_url_set.3 \
|
||||
curl_version.3 \
|
||||
curl_version_info.3 \
|
||||
libcurl-easy.3 \
|
||||
libcurl-env.3 \
|
||||
libcurl-errors.3 \
|
||||
libcurl-multi.3 \
|
||||
libcurl-security.3 \
|
||||
libcurl-share.3 \
|
||||
libcurl-symbols.3 \
|
||||
libcurl-thread.3 \
|
||||
libcurl-tutorial.3 \
|
||||
libcurl.3
|
||||
|
61
docs/libcurl/curl_url.3
Normal file
61
docs/libcurl/curl_url.3
Normal 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 curl_url 3 "6 Aug 2018" "libcurl" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_url - returns a new CURLU handle
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
|
||||
CURLU *curl_url();
|
||||
.SH EXPERIMENTAL
|
||||
The URL API is considered \fBEXPERIMENTAL\fP until further notice. Please test
|
||||
it, report bugs and help us perfect it. Once proven to be reliable, the
|
||||
experimental label will be removed.
|
||||
|
||||
While this API is marked experimental, we reserve the right to modify the API
|
||||
slightly if we deem it necessary and it makes it notably better or easier to
|
||||
use.
|
||||
.SH DESCRIPTION
|
||||
This function will allocates and returns a pointer to a fresh CURLU handle, to
|
||||
be used for further use of the URL API.
|
||||
.SH RETURN VALUE
|
||||
Returns a \fBCURLU *\fP if successful, or NULL if out of memory.
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
CURLUcode rc;
|
||||
CURLU *url = curl_url();
|
||||
rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
|
||||
if(!rc) {
|
||||
char *scheme;
|
||||
rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0);
|
||||
if(!rc) {
|
||||
printf("the scheme is %s\n", scheme);
|
||||
curl_free(scheme);
|
||||
}
|
||||
curl_url_cleanup(url);
|
||||
}
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Added in curl 7.63.0
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_url_cleanup "(3), " curl_url_get "(3), " curl_url_set "(3), "
|
||||
.BR curl_url_dup "(3), "
|
44
docs/libcurl/curl_url_cleanup.3
Normal file
44
docs/libcurl/curl_url_cleanup.3
Normal file
@ -0,0 +1,44 @@
|
||||
.\" **************************************************************************
|
||||
.\" * _ _ ____ _
|
||||
.\" * 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 curl_url_cleanup 3 "6 Aug 2018" "libcurl" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_url_cleanup - free a CURLU handle
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
|
||||
void curl_url_cleanup(CURLU *handle);
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Frees all the resources associated with the given CURLU handle!
|
||||
.SH RETURN VALUE
|
||||
none
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
CURLU *url = curl_url();
|
||||
curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
|
||||
curl_url_cleanup(url);
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Added in curl 7.63.0
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_url_dup "(3), " curl_url "(3), " curl_url_set "(3), "
|
||||
.BR curl_url_get "(3), "
|
52
docs/libcurl/curl_url_dup.3
Normal file
52
docs/libcurl/curl_url_dup.3
Normal file
@ -0,0 +1,52 @@
|
||||
.\" **************************************************************************
|
||||
.\" * _ _ ____ _
|
||||
.\" * 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 curl_url_dup 3 "6 Aug 2018" "libcurl" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_url_dup - duplicate a CURLU handle
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
|
||||
CURLU *curl_url_dup(CURLU *inhandle);
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Duplicates a given CURLU \fIinhandle\fP and all its contents and returns a
|
||||
pointer to a new CURLU handle. The new handle also needs to be freed with
|
||||
\fIcurl_url_cleanup(3)\fP.
|
||||
.SH RETURN VALUE
|
||||
Returns a new handle or NULL if out of memory.
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
CURLUcode rc;
|
||||
CURLU *url = curl_url();
|
||||
CURLU *url2;
|
||||
rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
|
||||
if(!rc) {
|
||||
url2 = curl_url_dup(url); /* clone it! */
|
||||
curl_url_cleanup(url2);
|
||||
}
|
||||
curl_url_cleanup(url);
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Added in curl 7.63.0
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_url_cleanup "(3), " curl_url "(3), " curl_url_set "(3), "
|
||||
.BR curl_url_get "(3), "
|
110
docs/libcurl/curl_url_get.3
Normal file
110
docs/libcurl/curl_url_get.3
Normal file
@ -0,0 +1,110 @@
|
||||
.\" **************************************************************************
|
||||
.\" * _ _ ____ _
|
||||
.\" * 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 curl_url_get 3 "6 Aug 2018" "libcurl" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_url_get - extract a part from a URL
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
|
||||
.nf
|
||||
CURLUcode curl_url_get(CURLU *url,
|
||||
CURLUPart what,
|
||||
char **part,
|
||||
unsigned int flags)
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Given the \fIurl\fP handle of an already parsed URL, this function lets the
|
||||
user extract individual pieces from it.
|
||||
|
||||
The \fIwhat\fP argument should be the particular part to extract (see list
|
||||
below) and \fIpart\fP points to a 'char *' to get updated to point to a newly
|
||||
allocated string with the contents.
|
||||
|
||||
The \fIflags\fP argument is a bitmask with individual features.
|
||||
|
||||
The returned part pointer must be freed with \fIcurl_free(3)\fP after use.
|
||||
.SH FLAGS
|
||||
The flags argument is zero, one or more bits set in a bitmask.
|
||||
.IP CURLU_DEFAULT_PORT
|
||||
If the handle has no port stored, this option will make \fIcurl_url_get(3)\fP
|
||||
return the default port for the used scheme.
|
||||
.IP CURLU_DEFAULT_SCHEME
|
||||
If the handle has no scheme stored, this option will make
|
||||
\fIcurl_url_get(3)\fP return the default scheme instead of error.
|
||||
.IP CURLU_NO_DEFAULT_PORT
|
||||
Instructs \fIcurl_url_get(3)\fP to not return a port number if it matches the
|
||||
default port for the scheme.
|
||||
.IP CURLU_URLDECODE
|
||||
Asks \fIcurl_url_get(3)\fP to URL decode the contents before returning it. It
|
||||
will not attempt to decode the scheme, the port number or the full URL.
|
||||
|
||||
The query component will also get plus-to-space convertion as a bonus when
|
||||
this bit is set.
|
||||
|
||||
Note that this URL decoding is charset unaware and you will get a zero
|
||||
terminated string back with data that could be intended for a particular
|
||||
encoding.
|
||||
|
||||
If there's any byte values lower than 32 in the decoded string, the get
|
||||
operation will return an error instead.
|
||||
.SH PARTS
|
||||
.IP CURLUPART_URL
|
||||
When asked to return the full URL, \fIcurl_url_get(3)\fP will return a
|
||||
normalized and possibly cleaned up version of what was previously parsed.
|
||||
.IP CURLUPART_SCHEME
|
||||
Scheme cannot be URL decoded on get.
|
||||
.IP CURLUPART_USER
|
||||
.IP CURLUPART_PASSWORD
|
||||
.IP CURLUPART_OPTIONS
|
||||
.IP CURLUPART_HOST
|
||||
.IP CURLUPART_PORT
|
||||
Port cannot be URL decoded on get.
|
||||
.IP CURLUPART_PATH
|
||||
.IP CURLUPART_QUERY
|
||||
The query part will also get pluses converted to space when asked to URL
|
||||
decode on get with the CURLU_URLDECODE bit.
|
||||
.IP CURLUPART_FRAGMENT
|
||||
.SH RETURN VALUE
|
||||
Returns a CURLUcode error value, which is CURLUE_OK (0) if everything went
|
||||
fine.
|
||||
|
||||
If this function returns an error, no URL part is returned.
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
CURLUcode rc;
|
||||
CURLU *url = curl_url();
|
||||
rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
|
||||
if(!rc) {
|
||||
char *scheme;
|
||||
rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0);
|
||||
if(!rc) {
|
||||
printf("the scheme is %s\n", scheme);
|
||||
curl_free(scheme);
|
||||
}
|
||||
curl_url_cleanup(url);
|
||||
}
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Added in curl 7.63.0
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_url_cleanup "(3), " curl_url "(3), " curl_url_set "(3), "
|
||||
.BR curl_url_dup "(3), "
|
120
docs/libcurl/curl_url_set.3
Normal file
120
docs/libcurl/curl_url_set.3
Normal file
@ -0,0 +1,120 @@
|
||||
.\" **************************************************************************
|
||||
.\" * _ _ ____ _
|
||||
.\" * 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 curl_url_set 3 "6 Aug 2018" "libcurl" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_url_set - set a part from a URL
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
|
||||
CURLUcode curl_url_set(CURLU *url,
|
||||
CURLUPart part,
|
||||
const char *content,
|
||||
unsigned int flags)
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
Given the \fIurl\fP handle of an already parsed URL, this function lets the
|
||||
user set/update individual pieces of it.
|
||||
|
||||
The \fIpart\fP argument should identify the particular URL part (see list
|
||||
below) to set or change, with \fIcontent\fP pointing to a zero terminated
|
||||
string with the new contents for that URL part. The contents should be in the
|
||||
form and encoding they'd use in a URL: URL encoded.
|
||||
|
||||
Setting a part to a NULL pointer will effectively remove that part's contents
|
||||
from the CURLU handle.
|
||||
|
||||
The \fIflags\fP argument is a bitmask with independent features.
|
||||
.SH PARTS
|
||||
.IP CURLUPART_URL
|
||||
Allows the full URL of the handle to be replaced. If the handle already is
|
||||
populated with a URL, the new URL can be relative to the previous.
|
||||
|
||||
When successfully setting a new URL, relative or absolute, the handle contents
|
||||
will be replaced with the information of the newly set URL.
|
||||
|
||||
Pass a pointer to a zero terminated string to the \fIurl\fP parameter. The
|
||||
string must point to a correctly formatted "RFC 3986+" URL or be a NULL
|
||||
pointer.
|
||||
.IP CURLUPART_SCHEME
|
||||
Scheme cannot be URL decoded on set.
|
||||
.IP CURLUPART_USER
|
||||
.IP CURLUPART_PASSWORD
|
||||
.IP CURLUPART_OPTIONS
|
||||
.IP CURLUPART_HOST
|
||||
The host name can use IDNA. The string must then be encoded as your locale
|
||||
says or UTF-8 (when winidn is used).
|
||||
.IP CURLUPART_PORT
|
||||
Port cannot be URL encoded on set.
|
||||
.IP CURLUPART_PATH
|
||||
If a path is set in the URL without a leading slash, a slash will be inserted
|
||||
automatically when this URL is read from the handle.
|
||||
.IP CURLUPART_QUERY
|
||||
The query part will also get spaces converted to pluses when asked to URL
|
||||
encode on set with the CURLU_URLENCODE bit.
|
||||
|
||||
If used in with \fICURLU_APPENDQUERY\fP, the provided part will be appended on
|
||||
the end of the existing query - and if the previous part didn't end with an
|
||||
ampersand (&), an ampersand will be inserted before the new appended part.
|
||||
|
||||
When \fCURLU_APPENDQUERY\fP is used together with \fICURLU_URLENCODE\fP,
|
||||
the '=' symbols will not be URL encoded.
|
||||
|
||||
The question mark in the URL is not part of the actual query contents.
|
||||
.IP CURLUPART_FRAGMENT
|
||||
The hash sign in the URL is not part of the actual fragment contents.
|
||||
.SH FLAGS
|
||||
The flags argument is zero, one or more bits set in a bitmask.
|
||||
.IP CURLU_NON_SUPPORT_SCHEME
|
||||
If set, allows \fIcurl_url_set(3)\fP to set a non-supported scheme.
|
||||
.IP CURLU_URLENCODE
|
||||
When set, \fIcurl_url_set(3)\fP URL encodes the part on entry, except for
|
||||
scheme, port and URL.
|
||||
|
||||
When setting the path component with URL encoding enabled, the slash character
|
||||
will be skipped.
|
||||
|
||||
The query part gets space-to-plus conversion before the URL conversion.
|
||||
|
||||
This URL encoding is charset unaware and will convert the input on a
|
||||
byte-by-byte manner.
|
||||
.SH RETURN VALUE
|
||||
Returns a CURLUcode error value, which is CURLUE_OK (0) if everything went
|
||||
fine.
|
||||
|
||||
If this function returns an error, no URL part is returned.
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
CURLUcode rc;
|
||||
CURLU *url = curl_url();
|
||||
rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
|
||||
if(!rc) {
|
||||
char *scheme;
|
||||
/* change it to an FTP URL */
|
||||
rc = curl_url_set(url, CURLUPART_SCHEME, "ftp", 0);
|
||||
}
|
||||
curl_url_cleanup(url);
|
||||
.fi
|
||||
.SH AVAILABILITY
|
||||
Added in curl 7.63.0
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_url_cleanup "(3), " curl_url "(3), " curl_url_get "(3), "
|
||||
.BR curl_url_dup "(3), "
|
@ -721,6 +721,36 @@ CURLSSLSET_NO_BACKENDS 7.56.0
|
||||
CURLSSLSET_OK 7.56.0
|
||||
CURLSSLSET_TOO_LATE 7.56.0
|
||||
CURLSSLSET_UNKNOWN_BACKEND 7.56.0
|
||||
CURLUPART_FRAGMENT 7.62.0
|
||||
CURLUPART_HOST 7.62.0
|
||||
CURLUPART_OPTIONS 7.62.0
|
||||
CURLUPART_PASSWORD 7.62.0
|
||||
CURLUPART_PATH 7.62.0
|
||||
CURLUPART_PORT 7.62.0
|
||||
CURLUPART_QUERY 7.62.0
|
||||
CURLUPART_SCHEME 7.62.0
|
||||
CURLUPART_URL 7.62.0
|
||||
CURLUPART_USER 7.62.0
|
||||
CURLUE_BAD_HANDLE 7.62.0
|
||||
CURLUE_BAD_PARTPOINTER 7.62.0
|
||||
CURLUE_BAD_PORT_NUMBER 7.62.0
|
||||
CURLUE_MALFORMED_INPUT 7.62.0
|
||||
CURLUE_NO_FRAGMENT 7.62.0
|
||||
CURLUE_NO_HOST 7.62.0
|
||||
CURLUE_NO_OPTIONS 7.62.0
|
||||
CURLUE_NO_PASSWORD 7.62.0
|
||||
CURLUE_NO_PATH 7.62.0
|
||||
CURLUE_NO_PORT 7.62.0
|
||||
CURLUE_NO_QUERY 7.62.0
|
||||
CURLUE_NO_SCHEME 7.62.0
|
||||
CURLUE_NO_USER 7.62.0
|
||||
CURLUE_OK 7.62.0
|
||||
CURLUE_OUT_OF_MEMORY 7.62.0
|
||||
CURLUE_RELATIVE 7.62.0
|
||||
CURLUE_UNKNOWN_PART 7.62.0
|
||||
CURLUE_UNSUPPORTED_SCHEME 7.62.0
|
||||
CURLUE_URLDECODE 7.62.0
|
||||
CURLUE_USER_NOT_ALLOWED 7.62.0
|
||||
CURLUSESSL_ALL 7.17.0
|
||||
CURLUSESSL_CONTROL 7.17.0
|
||||
CURLUSESSL_NONE 7.17.0
|
||||
|
@ -5,7 +5,7 @@
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
# 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
|
||||
@ -21,7 +21,7 @@
|
||||
###########################################################################
|
||||
pkginclude_HEADERS = \
|
||||
curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \
|
||||
typecheck-gcc.h system.h
|
||||
typecheck-gcc.h system.h urlapi.h
|
||||
|
||||
pkgincludedir= $(includedir)/curl
|
||||
|
||||
|
@ -2794,6 +2794,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
|
||||
stuff before they can be included! */
|
||||
#include "easy.h" /* nothing in curl is fun without the easy stuff */
|
||||
#include "multi.h"
|
||||
#include "urlapi.h"
|
||||
|
||||
/* the typechecker doesn't work in C++ (yet) */
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
|
||||
|
121
include/curl/urlapi.h
Normal file
121
include/curl/urlapi.h
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef __CURL_URLAPI_H
|
||||
#define __CURL_URLAPI_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* the error codes for the URL API */
|
||||
typedef enum {
|
||||
CURLUE_OK,
|
||||
CURLUE_BAD_HANDLE, /* 1 */
|
||||
CURLUE_BAD_PARTPOINTER, /* 2 */
|
||||
CURLUE_MALFORMED_INPUT, /* 3 */
|
||||
CURLUE_BAD_PORT_NUMBER, /* 4 */
|
||||
CURLUE_UNSUPPORTED_SCHEME, /* 5 */
|
||||
CURLUE_URLDECODE, /* 6 */
|
||||
CURLUE_RELATIVE, /* 7 */
|
||||
CURLUE_USER_NOT_ALLOWED, /* 8 */
|
||||
CURLUE_UNKNOWN_PART, /* 9 */
|
||||
CURLUE_NO_SCHEME, /* 10 */
|
||||
CURLUE_NO_USER, /* 11 */
|
||||
CURLUE_NO_PASSWORD, /* 12 */
|
||||
CURLUE_NO_OPTIONS, /* 13 */
|
||||
CURLUE_NO_HOST, /* 14 */
|
||||
CURLUE_NO_PORT, /* 15 */
|
||||
CURLUE_NO_PATH, /* 16 */
|
||||
CURLUE_NO_QUERY, /* 17 */
|
||||
CURLUE_NO_FRAGMENT, /* 18 */
|
||||
CURLUE_OUT_OF_MEMORY /* 19 */
|
||||
} CURLUcode;
|
||||
|
||||
typedef enum {
|
||||
CURLUPART_URL,
|
||||
CURLUPART_SCHEME,
|
||||
CURLUPART_USER,
|
||||
CURLUPART_PASSWORD,
|
||||
CURLUPART_OPTIONS,
|
||||
CURLUPART_HOST,
|
||||
CURLUPART_PORT,
|
||||
CURLUPART_PATH,
|
||||
CURLUPART_QUERY,
|
||||
CURLUPART_FRAGMENT
|
||||
} CURLUPart;
|
||||
|
||||
#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */
|
||||
#define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set,
|
||||
if the port number matches the
|
||||
default for the scheme */
|
||||
#define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if
|
||||
missing */
|
||||
#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */
|
||||
#define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */
|
||||
#define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */
|
||||
#define CURLU_URLDECODE (1<<6) /* URL decode on get */
|
||||
#define CURLU_URLENCODE (1<<7) /* URL encode on set */
|
||||
#define CURLU_APPENDQUERY (1<<8) /* append a form style part */
|
||||
|
||||
typedef struct Curl_URL CURLU;
|
||||
|
||||
/*
|
||||
* curl_url() creates a new CURLU handle and returns a pointer to it.
|
||||
* Must be freed with curl_url_cleanup().
|
||||
*/
|
||||
CURL_EXTERN CURLU *curl_url(void);
|
||||
|
||||
/*
|
||||
* curl_url_cleanup() frees the CURLU handle and related resources used for
|
||||
* the URL parsing. It will not free strings previously returned with the URL
|
||||
* API.
|
||||
*/
|
||||
CURL_EXTERN void curl_url_cleanup(CURLU *handle);
|
||||
|
||||
/*
|
||||
* curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
|
||||
* handle must also be freed with curl_url_cleanup().
|
||||
*/
|
||||
CURL_EXTERN CURLU *curl_url_dup(CURLU *in);
|
||||
|
||||
/*
|
||||
* curl_url_get() extracts a specific part of the URL from a CURLU
|
||||
* handle. Returns error code. The returned pointer MUST be freed with
|
||||
* curl_free() afterwards.
|
||||
*/
|
||||
CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
|
||||
char **part, unsigned int flags);
|
||||
|
||||
/*
|
||||
* curl_url_set() sets a specific part of the URL in a CURLU handle. Returns
|
||||
* error code. The passed in string will be copied. Passing a NULL instead of
|
||||
* a part string, clears that part.
|
||||
*/
|
||||
CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
|
||||
const char *part, unsigned int flags);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
@ -55,7 +55,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
||||
curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
|
||||
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
|
||||
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
|
||||
doh.c
|
||||
doh.c urlapi.c
|
||||
|
||||
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
|
||||
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
|
||||
@ -75,7 +75,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
|
||||
curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
|
||||
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
|
||||
curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \
|
||||
curl_path.h curl_ctype.h curl_range.h psl.h doh.h
|
||||
curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h
|
||||
|
||||
LIB_RCFILES = libcurl.rc
|
||||
|
||||
|
10
lib/escape.c
10
lib/escape.c
@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* 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
|
||||
@ -41,7 +41,7 @@
|
||||
its behavior is altered by the current locale.
|
||||
See https://tools.ietf.org/html/rfc3986#section-2.3
|
||||
*/
|
||||
static bool Curl_isunreserved(unsigned char in)
|
||||
bool Curl_isunreserved(unsigned char in)
|
||||
{
|
||||
switch(in) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
@ -141,6 +141,8 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
|
||||
* Returns a pointer to a malloced string in *ostring with length given in
|
||||
* *olen. If length == 0, the length is assumed to be strlen(string).
|
||||
*
|
||||
* 'data' can be set to NULL but then this function can't convert network
|
||||
* data to host for non-ascii.
|
||||
*/
|
||||
CURLcode Curl_urldecode(struct Curl_easy *data,
|
||||
const char *string, size_t length,
|
||||
@ -151,7 +153,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
|
||||
char *ns = malloc(alloc);
|
||||
size_t strindex = 0;
|
||||
unsigned long hex;
|
||||
CURLcode result;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(!ns)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
@ -171,12 +173,14 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
|
||||
|
||||
in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
|
||||
|
||||
if(data) {
|
||||
result = Curl_convert_from_network(data, (char *)&in, 1);
|
||||
if(result) {
|
||||
/* Curl_convert_from_network calls failf if unsuccessful */
|
||||
free(ns);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
string += 2;
|
||||
alloc -= 2;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* 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
|
||||
@ -24,6 +24,7 @@
|
||||
/* Escape and unescape URL encoding in strings. The functions return a new
|
||||
* allocated string or NULL if an error occurred. */
|
||||
|
||||
bool Curl_isunreserved(unsigned char in);
|
||||
CURLcode Curl_urldecode(struct Curl_easy *data,
|
||||
const char *string, size_t length,
|
||||
char **ostring, size_t *olen,
|
||||
|
@ -159,7 +159,8 @@ const struct Curl_handler Curl_handler_imaps = {
|
||||
ZERO_NULL, /* connection_check */
|
||||
PORT_IMAPS, /* defport */
|
||||
CURLPROTO_IMAPS, /* protocol */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
|
||||
PROTOPT_URLOPTIONS
|
||||
};
|
||||
#endif
|
||||
|
||||
|
314
lib/transfer.c
314
lib/transfer.c
@ -75,6 +75,7 @@
|
||||
#include "http2.h"
|
||||
#include "mime.h"
|
||||
#include "strcase.h"
|
||||
#include "urlapi-int.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@ -1454,311 +1455,6 @@ CURLcode Curl_posttransfer(struct Curl_easy *data)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
/*
|
||||
* Find the separator at the end of the host name, or the '?' in cases like
|
||||
* http://www.url.com?id=2380
|
||||
*/
|
||||
static const char *find_host_sep(const char *url)
|
||||
{
|
||||
const char *sep;
|
||||
const char *query;
|
||||
|
||||
/* Find the start of the hostname */
|
||||
sep = strstr(url, "//");
|
||||
if(!sep)
|
||||
sep = url;
|
||||
else
|
||||
sep += 2;
|
||||
|
||||
query = strchr(sep, '?');
|
||||
sep = strchr(sep, '/');
|
||||
|
||||
if(!sep)
|
||||
sep = url + strlen(url);
|
||||
|
||||
if(!query)
|
||||
query = url + strlen(url);
|
||||
|
||||
return sep < query ? sep : query;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decide in an encoding-independent manner whether a character in an
|
||||
* URL must be escaped. The same criterion must be used in strlen_url()
|
||||
* and strcpy_url().
|
||||
*/
|
||||
static bool urlchar_needs_escaping(int c)
|
||||
{
|
||||
return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
|
||||
}
|
||||
|
||||
/*
|
||||
* strlen_url() returns the length of the given URL if the spaces within the
|
||||
* URL were properly URL encoded.
|
||||
* URL encoding should be skipped for host names, otherwise IDN resolution
|
||||
* will fail.
|
||||
*/
|
||||
static size_t strlen_url(const char *url, bool relative)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
size_t newlen = 0;
|
||||
bool left = TRUE; /* left side of the ? */
|
||||
const unsigned char *host_sep = (const unsigned char *) url;
|
||||
|
||||
if(!relative)
|
||||
host_sep = (const unsigned char *) find_host_sep(url);
|
||||
|
||||
for(ptr = (unsigned char *)url; *ptr; ptr++) {
|
||||
|
||||
if(ptr < host_sep) {
|
||||
++newlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(*ptr) {
|
||||
case '?':
|
||||
left = FALSE;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if(urlchar_needs_escaping(*ptr))
|
||||
newlen += 2;
|
||||
newlen++;
|
||||
break;
|
||||
case ' ':
|
||||
if(left)
|
||||
newlen += 3;
|
||||
else
|
||||
newlen++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newlen;
|
||||
}
|
||||
|
||||
/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
|
||||
* the source URL accordingly.
|
||||
* URL encoding should be skipped for host names, otherwise IDN resolution
|
||||
* will fail.
|
||||
*/
|
||||
static void strcpy_url(char *output, const char *url, bool relative)
|
||||
{
|
||||
/* we must add this with whitespace-replacing */
|
||||
bool left = TRUE;
|
||||
const unsigned char *iptr;
|
||||
char *optr = output;
|
||||
const unsigned char *host_sep = (const unsigned char *) url;
|
||||
|
||||
if(!relative)
|
||||
host_sep = (const unsigned char *) find_host_sep(url);
|
||||
|
||||
for(iptr = (unsigned char *)url; /* read from here */
|
||||
*iptr; /* until zero byte */
|
||||
iptr++) {
|
||||
|
||||
if(iptr < host_sep) {
|
||||
*optr++ = *iptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(*iptr) {
|
||||
case '?':
|
||||
left = FALSE;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if(urlchar_needs_escaping(*iptr)) {
|
||||
snprintf(optr, 4, "%%%02x", *iptr);
|
||||
optr += 3;
|
||||
}
|
||||
else
|
||||
*optr++=*iptr;
|
||||
break;
|
||||
case ' ':
|
||||
if(left) {
|
||||
*optr++='%'; /* add a '%' */
|
||||
*optr++='2'; /* add a '2' */
|
||||
*optr++='0'; /* add a '0' */
|
||||
}
|
||||
else
|
||||
*optr++='+'; /* add a '+' here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
*optr = 0; /* zero terminate output buffer */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the given URL is absolute (as opposed to relative)
|
||||
*/
|
||||
static bool is_absolute_url(const char *url)
|
||||
{
|
||||
char prot[16]; /* URL protocol string storage */
|
||||
char letter; /* used for a silly sscanf */
|
||||
|
||||
return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate a relative URL to a base URL making it absolute.
|
||||
* URL-encodes any spaces.
|
||||
* The returned pointer must be freed by the caller unless NULL
|
||||
* (returns NULL on out of memory).
|
||||
*/
|
||||
static char *concat_url(const char *base, const char *relurl)
|
||||
{
|
||||
/***
|
||||
TRY to append this new path to the old URL
|
||||
to the right of the host part. Oh crap, this is doomed to cause
|
||||
problems in the future...
|
||||
*/
|
||||
char *newest;
|
||||
char *protsep;
|
||||
char *pathsep;
|
||||
size_t newlen;
|
||||
bool host_changed = FALSE;
|
||||
|
||||
const char *useurl = relurl;
|
||||
size_t urllen;
|
||||
|
||||
/* we must make our own copy of the URL to play with, as it may
|
||||
point to read-only data */
|
||||
char *url_clone = strdup(base);
|
||||
|
||||
if(!url_clone)
|
||||
return NULL; /* skip out of this NOW */
|
||||
|
||||
/* protsep points to the start of the host name */
|
||||
protsep = strstr(url_clone, "//");
|
||||
if(!protsep)
|
||||
protsep = url_clone;
|
||||
else
|
||||
protsep += 2; /* pass the slashes */
|
||||
|
||||
if('/' != relurl[0]) {
|
||||
int level = 0;
|
||||
|
||||
/* First we need to find out if there's a ?-letter in the URL,
|
||||
and cut it and the right-side of that off */
|
||||
pathsep = strchr(protsep, '?');
|
||||
if(pathsep)
|
||||
*pathsep = 0;
|
||||
|
||||
/* we have a relative path to append to the last slash if there's one
|
||||
available, or if the new URL is just a query string (starts with a
|
||||
'?') we append the new one at the end of the entire currently worked
|
||||
out URL */
|
||||
if(useurl[0] != '?') {
|
||||
pathsep = strrchr(protsep, '/');
|
||||
if(pathsep)
|
||||
*pathsep = 0;
|
||||
}
|
||||
|
||||
/* Check if there's any slash after the host name, and if so, remember
|
||||
that position instead */
|
||||
pathsep = strchr(protsep, '/');
|
||||
if(pathsep)
|
||||
protsep = pathsep + 1;
|
||||
else
|
||||
protsep = NULL;
|
||||
|
||||
/* now deal with one "./" or any amount of "../" in the newurl
|
||||
and act accordingly */
|
||||
|
||||
if((useurl[0] == '.') && (useurl[1] == '/'))
|
||||
useurl += 2; /* just skip the "./" */
|
||||
|
||||
while((useurl[0] == '.') &&
|
||||
(useurl[1] == '.') &&
|
||||
(useurl[2] == '/')) {
|
||||
level++;
|
||||
useurl += 3; /* pass the "../" */
|
||||
}
|
||||
|
||||
if(protsep) {
|
||||
while(level--) {
|
||||
/* cut off one more level from the right of the original URL */
|
||||
pathsep = strrchr(protsep, '/');
|
||||
if(pathsep)
|
||||
*pathsep = 0;
|
||||
else {
|
||||
*protsep = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* We got a new absolute path for this server */
|
||||
|
||||
if((relurl[0] == '/') && (relurl[1] == '/')) {
|
||||
/* the new URL starts with //, just keep the protocol part from the
|
||||
original one */
|
||||
*protsep = 0;
|
||||
useurl = &relurl[2]; /* we keep the slashes from the original, so we
|
||||
skip the new ones */
|
||||
host_changed = TRUE;
|
||||
}
|
||||
else {
|
||||
/* cut off the original URL from the first slash, or deal with URLs
|
||||
without slash */
|
||||
pathsep = strchr(protsep, '/');
|
||||
if(pathsep) {
|
||||
/* When people use badly formatted URLs, such as
|
||||
"http://www.url.com?dir=/home/daniel" we must not use the first
|
||||
slash, if there's a ?-letter before it! */
|
||||
char *sep = strchr(protsep, '?');
|
||||
if(sep && (sep < pathsep))
|
||||
pathsep = sep;
|
||||
*pathsep = 0;
|
||||
}
|
||||
else {
|
||||
/* There was no slash. Now, since we might be operating on a badly
|
||||
formatted URL, such as "http://www.url.com?id=2380" which doesn't
|
||||
use a slash separator as it is supposed to, we need to check for a
|
||||
?-letter as well! */
|
||||
pathsep = strchr(protsep, '?');
|
||||
if(pathsep)
|
||||
*pathsep = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the new part contains a space, this is a mighty stupid redirect
|
||||
but we still make an effort to do "right". To the left of a '?'
|
||||
letter we replace each space with %20 while it is replaced with '+'
|
||||
on the right side of the '?' letter.
|
||||
*/
|
||||
newlen = strlen_url(useurl, !host_changed);
|
||||
|
||||
urllen = strlen(url_clone);
|
||||
|
||||
newest = malloc(urllen + 1 + /* possible slash */
|
||||
newlen + 1 /* zero byte */);
|
||||
|
||||
if(!newest) {
|
||||
free(url_clone); /* don't leak this */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy over the root url part */
|
||||
memcpy(newest, url_clone, urllen);
|
||||
|
||||
/* check if we need to append a slash */
|
||||
if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
|
||||
;
|
||||
else
|
||||
newest[urllen++]='/';
|
||||
|
||||
/* then append the new piece on the right side */
|
||||
strcpy_url(&newest[urllen], useurl, !host_changed);
|
||||
|
||||
free(url_clone);
|
||||
|
||||
return newest;
|
||||
}
|
||||
#endif /* CURL_DISABLE_HTTP */
|
||||
|
||||
/*
|
||||
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
|
||||
* as given by the remote server and set up the new URL to request.
|
||||
@ -1810,12 +1506,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_absolute_url(newurl)) {
|
||||
if(!Curl_is_absolute_url(newurl, NULL, 8)) {
|
||||
/***
|
||||
*DANG* this is an RFC 2068 violation. The URL is supposed
|
||||
to be absolute and this doesn't seem to be that!
|
||||
*/
|
||||
char *absolute = concat_url(data->change.url, newurl);
|
||||
char *absolute = Curl_concat_url(data->change.url, newurl);
|
||||
if(!absolute)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
newurl = absolute;
|
||||
@ -1824,7 +1520,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
|
||||
/* 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, FALSE);
|
||||
size_t newlen = Curl_strlen_url(newurl, FALSE);
|
||||
|
||||
/* This is an absolute URL, don't allow the custom port number */
|
||||
disallowport = TRUE;
|
||||
@ -1833,7 +1529,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
|
||||
if(!newest)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
strcpy_url(newest, newurl, FALSE); /* create a space-free URL */
|
||||
Curl_strcpy_url(newest, newurl, FALSE); /* create a space-free URL */
|
||||
newurl = newest; /* use this instead now */
|
||||
|
||||
}
|
||||
|
34
lib/url.c
34
lib/url.c
@ -1944,30 +1944,37 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* returns the handdler if the given scheme is built-in */
|
||||
const struct Curl_handler *Curl_builtin_scheme(const char *scheme)
|
||||
{
|
||||
const struct Curl_handler * const *pp;
|
||||
const struct Curl_handler *p;
|
||||
/* Scan protocol handler table and match against 'scheme'. The handler may
|
||||
be changed later when the protocol specific setup function is called. */
|
||||
for(pp = protocols; (p = *pp) != NULL; pp++)
|
||||
if(strcasecompare(p->scheme, scheme))
|
||||
/* Protocol found in table. Check if allowed */
|
||||
return p;
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
||||
|
||||
static CURLcode findprotocol(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const char *protostr)
|
||||
{
|
||||
const struct Curl_handler * const *pp;
|
||||
const struct Curl_handler *p;
|
||||
const struct Curl_handler *p = Curl_builtin_scheme(protostr);
|
||||
|
||||
/* Scan protocol handler table and match against 'protostr' to set a few
|
||||
variables based on the URL. Now that the handler may be changed later
|
||||
when the protocol specific setup function is called. */
|
||||
for(pp = protocols; (p = *pp) != NULL; pp++) {
|
||||
if(strcasecompare(p->scheme, protostr)) {
|
||||
/* Protocol found in table. Check if allowed */
|
||||
if(!(data->set.allowed_protocols & p->protocol))
|
||||
/* nope, get out */
|
||||
break;
|
||||
if(p && /* Protocol found in table. Check if allowed */
|
||||
(data->set.allowed_protocols & p->protocol)) {
|
||||
|
||||
/* it is allowed for "normal" request, now do an extra check if this is
|
||||
the result of a redirect */
|
||||
if(data->state.this_is_a_follow &&
|
||||
!(data->set.redir_protocols & p->protocol))
|
||||
/* nope, get out */
|
||||
break;
|
||||
|
||||
;
|
||||
else {
|
||||
/* Perform setup complement if some. */
|
||||
conn->handler = conn->given = p;
|
||||
|
||||
@ -1976,7 +1983,6 @@ static CURLcode findprotocol(struct Curl_easy *data,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The protocol was not found in the table, but we don't have to assign it
|
||||
to anything since it is already assigned to a dummy-struct in the
|
||||
create_conn() function when the connectdata struct is allocated. */
|
||||
|
@ -79,6 +79,8 @@ void Curl_getoff_all_pipelines(struct Curl_easy *data,
|
||||
|
||||
CURLcode Curl_upkeep(struct conncache *conn_cache, void *data);
|
||||
|
||||
const struct Curl_handler *Curl_builtin_scheme(const char *scheme);
|
||||
|
||||
#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
|
||||
#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
|
||||
specified */
|
||||
|
29
lib/urlapi-int.h
Normal file
29
lib/urlapi-int.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef HEADER_CURL_URLAPI_INT_H
|
||||
#define HEADER_CURL_URLAPI_INT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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.
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
|
||||
char *Curl_concat_url(const char *base, const char *relurl);
|
||||
size_t Curl_strlen_url(const char *url, bool relative);
|
||||
void Curl_strcpy_url(char *output, const char *url, bool relative);
|
||||
#endif
|
1315
lib/urlapi.c
Normal file
1315
lib/urlapi.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -178,6 +178,8 @@ test1533 test1534 test1535 test1536 test1537 test1538 \
|
||||
test1540 \
|
||||
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
|
||||
\
|
||||
test1560 \
|
||||
\
|
||||
test1590 \
|
||||
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
|
||||
test1608 test1609 test1620 \
|
||||
|
28
tests/data/test1560
Normal file
28
tests/data/test1560
Normal file
@ -0,0 +1,28 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
unittest
|
||||
URL API
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
none
|
||||
</server>
|
||||
<features>
|
||||
file
|
||||
https
|
||||
http
|
||||
</features>
|
||||
<name>
|
||||
URL API
|
||||
</name>
|
||||
<tool>
|
||||
lib1560
|
||||
</tool>
|
||||
</client>
|
||||
|
||||
</testcase>
|
@ -133,3 +133,8 @@ lib1521.c: $(top_srcdir)/tests/libtest/mk-lib1521.pl $(top_srcdir)/include/curl/
|
||||
|
||||
checksrc:
|
||||
@PERL@ $(top_srcdir)/lib/checksrc.pl $(srcdir)/*.c
|
||||
|
||||
if CURLDEBUG
|
||||
# for debug builds, we scan the sources on all regular make invokes
|
||||
all-local: checksrc
|
||||
endif
|
||||
|
@ -30,6 +30,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
|
||||
lib1534 lib1535 lib1536 lib1537 lib1538 \
|
||||
lib1540 \
|
||||
lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \
|
||||
lib1560 \
|
||||
lib1900 \
|
||||
lib2033
|
||||
|
||||
@ -507,6 +508,9 @@ lib1557_SOURCES = lib1557.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||
lib1557_LDADD = $(TESTUTIL_LIBS)
|
||||
lib1557_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1557
|
||||
|
||||
lib1560_SOURCES = lib1560.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||
lib1560_LDADD = $(TESTUTIL_LIBS)
|
||||
|
||||
lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||
lib1900_LDADD = $(TESTUTIL_LIBS)
|
||||
lib1900_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
760
tests/libtest/lib1560.c
Normal file
760
tests/libtest/lib1560.c
Normal file
@ -0,0 +1,760 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* 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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Note:
|
||||
*
|
||||
* Since the URL parser by default only accepts schemes that *this instance*
|
||||
* of libcurl supports, make sure that the test1560 file lists all the schemes
|
||||
* that this test will assume to be present!
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "testutil.h"
|
||||
#include "warnless.h"
|
||||
#include "memdebug.h" /* LAST include file */
|
||||
|
||||
struct part {
|
||||
CURLUPart part;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
|
||||
static int checkparts(CURLU *u, const char *in, const char *wanted,
|
||||
unsigned int getflags)
|
||||
{
|
||||
int i;
|
||||
CURLUcode rc;
|
||||
char buf[256];
|
||||
char *bufp = &buf[0];
|
||||
size_t len = sizeof(buf);
|
||||
struct part parts[] = {
|
||||
{CURLUPART_SCHEME, "scheme"},
|
||||
{CURLUPART_USER, "user"},
|
||||
{CURLUPART_PASSWORD, "password"},
|
||||
{CURLUPART_OPTIONS, "options"},
|
||||
{CURLUPART_HOST, "host"},
|
||||
{CURLUPART_PORT, "port"},
|
||||
{CURLUPART_PATH, "path"},
|
||||
{CURLUPART_QUERY, "query"},
|
||||
{CURLUPART_FRAGMENT, "fragment"},
|
||||
{0, NULL}
|
||||
};
|
||||
buf[0] = 0;
|
||||
|
||||
for(i = 0; parts[i].name; i++) {
|
||||
char *p = NULL;
|
||||
size_t n;
|
||||
rc = curl_url_get(u, parts[i].part, &p, getflags);
|
||||
if(!rc && p) {
|
||||
snprintf(bufp, len, "%s%s", buf[0]?" | ":"", p);
|
||||
}
|
||||
else
|
||||
snprintf(bufp, len, "%s[%d]", buf[0]?" | ":"", (int)rc);
|
||||
|
||||
n = strlen(bufp);
|
||||
bufp += n;
|
||||
len -= n;
|
||||
curl_free(p);
|
||||
}
|
||||
if(strcmp(buf, wanted)) {
|
||||
fprintf(stderr, "in: %s\nwanted: %s\ngot: %s\n", in, wanted, buf);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct redircase {
|
||||
const char *in;
|
||||
const char *set;
|
||||
const char *out;
|
||||
unsigned int urlflags;
|
||||
unsigned int setflags;
|
||||
CURLUcode ucode;
|
||||
};
|
||||
|
||||
struct setcase {
|
||||
const char *in;
|
||||
const char *set;
|
||||
const char *out;
|
||||
unsigned int urlflags;
|
||||
unsigned int setflags;
|
||||
CURLUcode ucode;
|
||||
};
|
||||
|
||||
struct testcase {
|
||||
const char *in;
|
||||
const char *out;
|
||||
unsigned int urlflags;
|
||||
unsigned int getflags;
|
||||
CURLUcode ucode;
|
||||
};
|
||||
|
||||
struct urltestcase {
|
||||
const char *in;
|
||||
const char *out;
|
||||
unsigned int urlflags; /* pass to curl_url() */
|
||||
unsigned int getflags; /* pass to curl_url_get() */
|
||||
CURLUcode ucode;
|
||||
};
|
||||
|
||||
struct querycase {
|
||||
const char *in;
|
||||
const char *q;
|
||||
const char *out;
|
||||
unsigned int urlflags; /* pass to curl_url() */
|
||||
unsigned int qflags; /* pass to curl_url_get() */
|
||||
CURLUcode ucode;
|
||||
};
|
||||
|
||||
static struct testcase get_parts_list[] ={
|
||||
{"https://127.0.0.1:443",
|
||||
"https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [17] | [18]",
|
||||
0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
|
||||
{"http://%3a:%3a@ex%0ample/%3f+?+%3f+%23#+%23%3f%g7",
|
||||
"http | : | : | [13] | [6] | [15] | /?+ | ? # | +#?%g7",
|
||||
0, CURLU_URLDECODE, CURLUE_OK},
|
||||
{"http://%3a:%3a@ex%0ample/%3f?%3f%35#%35%3f%g7",
|
||||
"http | %3a | %3a | [13] | ex%0ample | [15] | /%3f | %3f%35 | %35%3f%g7",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://HO0_-st%41/",
|
||||
"http | [11] | [12] | [13] | HO0_-st%41 | [15] | / | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file://hello.html",
|
||||
"",
|
||||
0, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"http://HO0_-st/",
|
||||
"http | [11] | [12] | [13] | HO0_-st | [15] | / | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"imap://user:pass;option@server/path",
|
||||
"imap | user | pass | option | server | [15] | /path | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://user:pass;option@server/path",
|
||||
"http | user | pass;option | [13] | server | [15] | /path | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file:/hello.html",
|
||||
"file | [11] | [12] | [13] | [14] | [15] | /hello.html | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file://127.0.0.1/hello.html",
|
||||
"file | [11] | [12] | [13] | [14] | [15] | /hello.html | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file:////hello.html",
|
||||
"file | [11] | [12] | [13] | [14] | [15] | //hello.html | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file:///hello.html",
|
||||
"file | [11] | [12] | [13] | [14] | [15] | /hello.html | [17] | [18]",
|
||||
0, 0, CURLUE_OK},
|
||||
{"https://127.0.0.1",
|
||||
"https | [11] | [12] | [13] | 127.0.0.1 | 443 | / | [17] | [18]",
|
||||
0, CURLU_DEFAULT_PORT, CURLUE_OK},
|
||||
{"https://127.0.0.1",
|
||||
"https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [17] | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://[::1]:1234",
|
||||
"https | [11] | [12] | [13] | [::1] | 1234 | / | [17] | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://127abc.com",
|
||||
"https | [11] | [12] | [13] | 127abc.com | [15] | / | [17] | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https:// example.com?check",
|
||||
"",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"https://e x a m p l e.com?check",
|
||||
"",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"https://example.com?check",
|
||||
"https | [11] | [12] | [13] | example.com | [15] | / | check | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://example.com:65536",
|
||||
"",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PORT_NUMBER},
|
||||
{"https://example.com:0#moo",
|
||||
"",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PORT_NUMBER},
|
||||
{"https://example.com:01#moo",
|
||||
"https | [11] | [12] | [13] | example.com | 1 | / | "
|
||||
"[17] | moo",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://example.com:1#moo",
|
||||
"https | [11] | [12] | [13] | example.com | 1 | / | "
|
||||
"[17] | moo",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://example.com#moo",
|
||||
"http | [11] | [12] | [13] | example.com | [15] | / | "
|
||||
"[17] | moo",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://example.com",
|
||||
"http | [11] | [12] | [13] | example.com | [15] | / | "
|
||||
"[17] | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://example.com/path/html",
|
||||
"http | [11] | [12] | [13] | example.com | [15] | /path/html | "
|
||||
"[17] | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://example.com/path/html?query=name",
|
||||
"http | [11] | [12] | [13] | example.com | [15] | /path/html | "
|
||||
"query=name | [18]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://example.com/path/html?query=name#anchor",
|
||||
"http | [11] | [12] | [13] | example.com | [15] | /path/html | "
|
||||
"query=name | anchor",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://example.com:1234/path/html?query=name#anchor",
|
||||
"http | [11] | [12] | [13] | example.com | 1234 | /path/html | "
|
||||
"query=name | anchor",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http:///user:password@example.com:1234/path/html?query=name#anchor",
|
||||
"http | user | password | [13] | example.com | 1234 | /path/html | "
|
||||
"query=name | anchor",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://user:password@example.com:1234/path/html?query=name#anchor",
|
||||
"https | user | password | [13] | example.com | 1234 | /path/html | "
|
||||
"query=name | anchor",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http://user:password@example.com:1234/path/html?query=name#anchor",
|
||||
"http | user | password | [13] | example.com | 1234 | /path/html | "
|
||||
"query=name | anchor",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http:/user:password@example.com:1234/path/html?query=name#anchor",
|
||||
"http | user | password | [13] | example.com | 1234 | /path/html | "
|
||||
"query=name | anchor",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"http:////user:password@example.com:1234/path/html?query=name#anchor",
|
||||
"",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
|
||||
{NULL, NULL, 0, 0, CURLUE_OK},
|
||||
};
|
||||
|
||||
static struct urltestcase get_url_list[] = {
|
||||
{"HTTP://test/", "http://test/", 0, 0, CURLUE_OK},
|
||||
{"http://HO0_-st..~./", "", 0, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"http:/@example.com: 123/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
|
||||
{"http:/@example.com:123 /", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
|
||||
{"http:/@example.com:123a/", "", 0, 0, CURLUE_BAD_PORT_NUMBER},
|
||||
{"http://host/file\r", "", 0, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"http://host/file\n\x03", "", 0, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"htt\x02://host/file", "",
|
||||
CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT},
|
||||
{" http://host/file", "", 0, 0, CURLUE_MALFORMED_INPUT},
|
||||
/* here the password ends at the semicolon and options is 'word' */
|
||||
{"imap://user:pass;word@host/file",
|
||||
"imap://user:pass;word@host/file",
|
||||
0, 0, CURLUE_OK},
|
||||
/* here the password has the semicolon */
|
||||
{"http://user:pass;word@host/file",
|
||||
"http://user:pass;word@host/file",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file:///file.txt#moo",
|
||||
"file:///file.txt#moo",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file:////file.txt",
|
||||
"file:////file.txt",
|
||||
0, 0, CURLUE_OK},
|
||||
{"file:///file.txt",
|
||||
"file:///file.txt",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com/hello/../here",
|
||||
"http://example.com/hello/../here",
|
||||
CURLU_PATH_AS_IS, 0, CURLUE_OK},
|
||||
{"http://example.com/hello/../here",
|
||||
"http://example.com/here",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com:80",
|
||||
"http://example.com/",
|
||||
0, CURLU_NO_DEFAULT_PORT, CURLUE_OK},
|
||||
{"tp://example.com/path/html",
|
||||
"",
|
||||
0, 0, CURLUE_UNSUPPORTED_SCHEME},
|
||||
{"http://hello:fool@example.com",
|
||||
"",
|
||||
CURLU_DISALLOW_USER, 0, CURLUE_USER_NOT_ALLOWED},
|
||||
{"http:/@example.com:123",
|
||||
"http://example.com:123/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http:/:password@example.com",
|
||||
"http://:password@example.com/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://user@example.com?#",
|
||||
"http://user@example.com/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://user@example.com?",
|
||||
"http://user@example.com/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://user@example.com#anchor",
|
||||
"http://user@example.com/#anchor",
|
||||
0, 0, CURLUE_OK},
|
||||
{"example.com/path/html",
|
||||
"https://example.com/path/html",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"example.com/path/html",
|
||||
"",
|
||||
0, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"http://user:password@example.com:1234/path/html?query=name#anchor",
|
||||
"http://user:password@example.com:1234/path/html?query=name#anchor",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com:1234/path/html?query=name#anchor",
|
||||
"http://example.com:1234/path/html?query=name#anchor",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com/path/html?query=name#anchor",
|
||||
"http://example.com/path/html?query=name#anchor",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com/path/html?query=name",
|
||||
"http://example.com/path/html?query=name",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com/path/html",
|
||||
"http://example.com/path/html",
|
||||
0, 0, CURLUE_OK},
|
||||
{"tp://example.com/path/html",
|
||||
"tp://example.com/path/html",
|
||||
CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK},
|
||||
{NULL, NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
static int checkurl(const char *url, const char *out)
|
||||
{
|
||||
if(strcmp(out, url)) {
|
||||
fprintf(stderr, "Wanted: %s\nGot : %s\n",
|
||||
out, url);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* !checksrc! disable SPACEBEFORECOMMA 1 */
|
||||
static struct setcase set_parts_list[] = {
|
||||
{"https://host/",
|
||||
"path=%4A%4B%4C,",
|
||||
"https://host/%4a%4b%4c",
|
||||
0, 0, CURLUE_NO_HOST},
|
||||
{"https://host/mooo?q#f",
|
||||
"path=NULL,query=NULL,fragment=NULL,",
|
||||
"https://host/",
|
||||
0, 0, CURLUE_NO_HOST},
|
||||
{"https://user:secret@host/",
|
||||
"user=NULL,password=NULL,",
|
||||
"https://host/",
|
||||
0, 0, CURLUE_NO_HOST},
|
||||
{NULL,
|
||||
"scheme=https,user= @:,host=foobar,",
|
||||
"https://%20%20%20%40%3a@foobar/",
|
||||
0, CURLU_URLENCODE, CURLUE_OK},
|
||||
{NULL,
|
||||
"scheme=https,host= ,path= ,user= ,password= ,query= ,fragment= ,",
|
||||
"https://%20:%20@%20%20/%20?+#%20",
|
||||
0, CURLU_URLENCODE, CURLUE_OK},
|
||||
{NULL,
|
||||
"scheme=https,host=foobar,path=/this /path /is /here,",
|
||||
"https://foobar/this%20/path%20/is%20/here",
|
||||
0, CURLU_URLENCODE, CURLUE_OK},
|
||||
{"imap://user:secret;opt@host/",
|
||||
"options=updated,scheme=imaps,password=p4ssw0rd,",
|
||||
"imaps://user:p4ssw0rd;updated@host/",
|
||||
0, 0, CURLUE_NO_HOST},
|
||||
{"imap://user:secret;optit@host/",
|
||||
"scheme=https,",
|
||||
"https://user:secret@host/",
|
||||
0, 0, CURLUE_NO_HOST},
|
||||
{"file:///file#anchor",
|
||||
"scheme=https,host=example,",
|
||||
"https://example/file#anchor",
|
||||
0, 0, CURLUE_NO_HOST},
|
||||
{NULL, /* start fresh! */
|
||||
"scheme=file,host=127.0.0.1,path=/no,user=anonymous,",
|
||||
"file:///no",
|
||||
0, 0, CURLUE_OK},
|
||||
{NULL, /* start fresh! */
|
||||
"scheme=ftp,host=127.0.0.1,path=/no,user=anonymous,",
|
||||
"ftp://anonymous@127.0.0.1/no",
|
||||
0, 0, CURLUE_OK},
|
||||
{NULL, /* start fresh! */
|
||||
"scheme=https,host=example.com,",
|
||||
"https://example.com/",
|
||||
0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK},
|
||||
{"http://user:foo@example.com/path?query#frag",
|
||||
"fragment=changed,",
|
||||
"http://user:foo@example.com/path?query#changed",
|
||||
0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK},
|
||||
{"http://example.com/",
|
||||
"scheme=foo,", /* not accepted */
|
||||
"http://example.com/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com/",
|
||||
"scheme=https,path=/hello,fragment=snippet,",
|
||||
"https://example.com/hello#snippet",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com:80",
|
||||
"user=foo,port=1922,",
|
||||
"http://foo@example.com:1922/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com:80",
|
||||
"user=foo,password=bar,",
|
||||
"http://foo:bar@example.com:80/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com:80",
|
||||
"user=foo,",
|
||||
"http://foo@example.com:80/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com",
|
||||
"host=www.example.com,",
|
||||
"http://www.example.com/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"http://example.com:80",
|
||||
"scheme=ftp,",
|
||||
"ftp://example.com:80/",
|
||||
0, 0, CURLUE_OK},
|
||||
{NULL, NULL, NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
static CURLUPart part2id(char *part)
|
||||
{
|
||||
if(!strcmp("url", part))
|
||||
return CURLUPART_URL;
|
||||
if(!strcmp("scheme", part))
|
||||
return CURLUPART_SCHEME;
|
||||
if(!strcmp("user", part))
|
||||
return CURLUPART_USER;
|
||||
if(!strcmp("password", part))
|
||||
return CURLUPART_PASSWORD;
|
||||
if(!strcmp("options", part))
|
||||
return CURLUPART_OPTIONS;
|
||||
if(!strcmp("host", part))
|
||||
return CURLUPART_HOST;
|
||||
if(!strcmp("port", part))
|
||||
return CURLUPART_PORT;
|
||||
if(!strcmp("path", part))
|
||||
return CURLUPART_PATH;
|
||||
if(!strcmp("query", part))
|
||||
return CURLUPART_QUERY;
|
||||
if(!strcmp("fragment", part))
|
||||
return CURLUPART_FRAGMENT;
|
||||
return 9999; /* bad input => bad output */
|
||||
}
|
||||
|
||||
static void updateurl(CURLU *u, const char *cmd, unsigned int setflags)
|
||||
{
|
||||
const char *p = cmd;
|
||||
|
||||
/* make sure the last command ends with a comma too! */
|
||||
while(p) {
|
||||
char *e = strchr(p, ',');
|
||||
if(e) {
|
||||
size_t n = e-p;
|
||||
char buf[80];
|
||||
char part[80];
|
||||
char value[80];
|
||||
memcpy(buf, p, n);
|
||||
buf[n] = 0;
|
||||
if(2 == sscanf(buf, "%79[^=]=%79[^,]", part, value)) {
|
||||
CURLUPart what = part2id(part);
|
||||
#if 0
|
||||
/* for debugging this */
|
||||
fprintf(stderr, "%s = %s [%d]\n", part, value, (int)what);
|
||||
#endif
|
||||
if(!strcmp("NULL", value))
|
||||
curl_url_set(u, what, NULL, setflags);
|
||||
else
|
||||
curl_url_set(u, what, value, setflags);
|
||||
}
|
||||
p = e + 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static struct redircase set_url_list[] = {
|
||||
{"file://localhost/path?query#frag",
|
||||
"foo#another",
|
||||
"file:///foo#another",
|
||||
0, 0, 0},
|
||||
{"http://example.com/path?query#frag",
|
||||
"https://two.example.com/bradnew",
|
||||
"https://two.example.com/bradnew",
|
||||
0, 0, 0},
|
||||
{"http://example.com/path?query#frag",
|
||||
"../../newpage#foo",
|
||||
"http://example.com/newpage#foo",
|
||||
0, 0, 0},
|
||||
{"http://user:foo@example.com/path?query#frag",
|
||||
"../../newpage",
|
||||
"http://user:foo@example.com/newpage",
|
||||
0, 0, 0},
|
||||
{"http://user:foo@example.com/path?query#frag",
|
||||
"../newpage",
|
||||
"http://user:foo@example.com/newpage",
|
||||
0, 0, 0},
|
||||
{NULL, NULL, NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
static int set_url(void)
|
||||
{
|
||||
int i;
|
||||
CURLUcode rc;
|
||||
CURLU *urlp;
|
||||
int error = 0;
|
||||
|
||||
for(i = 0; set_url_list[i].in && !error; i++) {
|
||||
char *url = NULL;
|
||||
urlp = curl_url();
|
||||
if(!urlp)
|
||||
break;
|
||||
rc = curl_url_set(urlp, CURLUPART_URL, set_url_list[i].in,
|
||||
set_url_list[i].urlflags);
|
||||
if(!rc) {
|
||||
rc = curl_url_set(urlp, CURLUPART_URL, set_url_list[i].set,
|
||||
set_url_list[i].setflags);
|
||||
if(rc) {
|
||||
fprintf(stderr, "%s:%d Set URL %s returned %d\n",
|
||||
__FILE__, __LINE__, set_url_list[i].set,
|
||||
(int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
|
||||
if(rc) {
|
||||
fprintf(stderr, "%s:%d Get URL returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
if(checkurl(url, set_url_list[i].out)) {
|
||||
error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
curl_free(url);
|
||||
}
|
||||
else if(rc != set_url_list[i].ucode) {
|
||||
fprintf(stderr, "Set URL\nin: %s\nreturned %d (expected %d)\n",
|
||||
set_url_list[i].in, (int)rc, set_url_list[i].ucode);
|
||||
error++;
|
||||
}
|
||||
curl_url_cleanup(urlp);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int set_parts(void)
|
||||
{
|
||||
int i;
|
||||
CURLUcode rc;
|
||||
int error = 0;
|
||||
|
||||
for(i = 0; set_parts_list[i].set && !error; i++) {
|
||||
char *url = NULL;
|
||||
CURLU *urlp = curl_url();
|
||||
if(!urlp) {
|
||||
error++;
|
||||
break;
|
||||
}
|
||||
if(set_parts_list[i].in)
|
||||
rc = curl_url_set(urlp, CURLUPART_URL, set_parts_list[i].in,
|
||||
set_parts_list[i].urlflags);
|
||||
else
|
||||
rc = CURLUE_OK;
|
||||
if(!rc) {
|
||||
updateurl(urlp, set_parts_list[i].set, set_parts_list[i].setflags);
|
||||
rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
|
||||
|
||||
if(rc) {
|
||||
fprintf(stderr, "%s:%d Get URL returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else if(checkurl(url, set_parts_list[i].out)) {
|
||||
error++;
|
||||
}
|
||||
}
|
||||
else if(rc != set_parts_list[i].ucode) {
|
||||
fprintf(stderr, "Set parts\nin: %s\nreturned %d (expected %d)\n",
|
||||
set_parts_list[i].in, (int)rc, set_parts_list[i].ucode);
|
||||
error++;
|
||||
}
|
||||
curl_free(url);
|
||||
curl_url_cleanup(urlp);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int get_url(void)
|
||||
{
|
||||
int i;
|
||||
CURLUcode rc;
|
||||
int error = 0;
|
||||
for(i = 0; get_url_list[i].in && !error; i++) {
|
||||
char *url = NULL;
|
||||
CURLU *urlp = curl_url();
|
||||
if(!urlp) {
|
||||
error++;
|
||||
break;
|
||||
}
|
||||
rc = curl_url_set(urlp, CURLUPART_URL, get_url_list[i].in,
|
||||
get_url_list[i].urlflags);
|
||||
if(!rc) {
|
||||
rc = curl_url_get(urlp, CURLUPART_URL, &url, get_url_list[i].getflags);
|
||||
|
||||
if(rc) {
|
||||
fprintf(stderr, "%s:%d returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
if(checkurl(url, get_url_list[i].out)) {
|
||||
error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(rc != get_url_list[i].ucode) {
|
||||
fprintf(stderr, "Get URL\nin: %s\nreturned %d (expected %d)\n",
|
||||
get_url_list[i].in, (int)rc, get_url_list[i].ucode);
|
||||
error++;
|
||||
}
|
||||
curl_free(url);
|
||||
curl_url_cleanup(urlp);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int get_parts(void)
|
||||
{
|
||||
int i;
|
||||
CURLUcode rc;
|
||||
CURLU *urlp;
|
||||
int error = 0;
|
||||
for(i = 0; get_parts_list[i].in && !error; i++) {
|
||||
urlp = curl_url();
|
||||
if(!urlp) {
|
||||
error++;
|
||||
break;
|
||||
}
|
||||
rc = curl_url_set(urlp, CURLUPART_URL,
|
||||
get_parts_list[i].in,
|
||||
get_parts_list[i].urlflags);
|
||||
if(rc != get_parts_list[i].ucode) {
|
||||
fprintf(stderr, "Get parts\nin: %s\nreturned %d (expected %d)\n",
|
||||
get_parts_list[i].in, (int)rc, get_parts_list[i].ucode);
|
||||
error++;
|
||||
}
|
||||
else if(get_parts_list[i].ucode) {
|
||||
/* the expected error happened */
|
||||
}
|
||||
else if(checkparts(urlp, get_parts_list[i].in, get_parts_list[i].out,
|
||||
get_parts_list[i].getflags))
|
||||
error++;
|
||||
curl_url_cleanup(urlp);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct querycase append_list[] = {
|
||||
{"HTTP://test/?s", "name=joe\x02", "http://test/?s&name=joe%02",
|
||||
0, CURLU_URLENCODE, CURLUE_OK},
|
||||
{"HTTP://test/?size=2#f", "name=joe=", "http://test/?size=2&name=joe=#f",
|
||||
0, CURLU_URLENCODE, CURLUE_OK},
|
||||
{"HTTP://test/?size=2#f", "name=joe doe",
|
||||
"http://test/?size=2&name=joe+doe#f",
|
||||
0, CURLU_URLENCODE, CURLUE_OK},
|
||||
{"HTTP://test/", "name=joe", "http://test/?name=joe", 0, 0, CURLUE_OK},
|
||||
{"HTTP://test/?size=2", "name=joe", "http://test/?size=2&name=joe",
|
||||
0, 0, CURLUE_OK},
|
||||
{"HTTP://test/?size=2&", "name=joe", "http://test/?size=2&name=joe",
|
||||
0, 0, CURLUE_OK},
|
||||
{"HTTP://test/?size=2#f", "name=joe", "http://test/?size=2&name=joe#f",
|
||||
0, 0, CURLUE_OK},
|
||||
{NULL, NULL, NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
static int append(void)
|
||||
{
|
||||
int i;
|
||||
CURLUcode rc;
|
||||
CURLU *urlp;
|
||||
int error = 0;
|
||||
for(i = 0; append_list[i].in && !error; i++) {
|
||||
urlp = curl_url();
|
||||
if(!urlp) {
|
||||
error++;
|
||||
break;
|
||||
}
|
||||
rc = curl_url_set(urlp, CURLUPART_URL,
|
||||
append_list[i].in,
|
||||
append_list[i].urlflags);
|
||||
if(rc)
|
||||
error++;
|
||||
else
|
||||
rc = curl_url_set(urlp, CURLUPART_QUERY,
|
||||
append_list[i].q,
|
||||
append_list[i].qflags | CURLU_APPENDQUERY);
|
||||
if(error)
|
||||
;
|
||||
else if(rc != append_list[i].ucode) {
|
||||
fprintf(stderr, "Append\nin: %s\nreturned %d (expected %d)\n",
|
||||
append_list[i].in, (int)rc, append_list[i].ucode);
|
||||
error++;
|
||||
}
|
||||
else if(append_list[i].ucode) {
|
||||
/* the expected error happened */
|
||||
}
|
||||
else {
|
||||
char *url;
|
||||
rc = curl_url_get(urlp, CURLUPART_URL, &url, 0);
|
||||
if(rc) {
|
||||
fprintf(stderr, "%s:%d Get URL returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
if(checkurl(url, append_list[i].out)) {
|
||||
error++;
|
||||
}
|
||||
curl_free(url);
|
||||
}
|
||||
}
|
||||
curl_url_cleanup(urlp);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int test(char *URL)
|
||||
{
|
||||
(void)URL; /* not used */
|
||||
|
||||
if(append())
|
||||
return 5;
|
||||
|
||||
if(set_url())
|
||||
return 1;
|
||||
|
||||
if(set_parts())
|
||||
return 2;
|
||||
|
||||
if(get_url())
|
||||
return 3;
|
||||
|
||||
if(get_parts())
|
||||
return 4;
|
||||
|
||||
printf("success\n");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user