diff --git a/config.sh b/config.sh
index fc1134c0c98d9f57cb2cfdbb3b9d6faf35001dfd..70c4489bf5fd48fc0eb636bf739a5d82dcff8663 100644
--- a/config.sh
+++ b/config.sh
@@ -5,6 +5,7 @@ AS=${AS:-as}
CC=${CC:-cc}
CFLAGS=${CFLAGS:-}
LD=${LD:-ld}
+LIBSSL=
for arg
do
@@ -12,6 +13,9 @@ # TODO: Add args for install directories
case "$arg" in
--prefix=*)
PREFIX=${arg#*=}
;;
--with-libssl=*)
LIBSSL=${arg#*=}
;;
esac
done
@@ -72,12 +76,27 @@ return 1
fi
}
+find_library() {
printf "NOT FOUND\n"
printf "Tried pkg-config %s\n" "$pc"
return 1
+}
run_configure() {
mkdir -p $outdir
for flag in -g -std=c11 -D_XOPEN_SOURCE=700 -Wall -Wextra -Werror -pedantic
do
printf "Checking for $flag... "
printf "Checking for %s... " "$flag"
if test_cflags "$flag"
then
echo yes
@@ -86,9 +105,13 @@ echo no
fi
done
printf "Creating $outdir/config.mk... "
cat <<-EOF > "$outdir"/config.mk
CC=$CC
PREFIX=${PREFIX:-/usr/local}
OUTDIR=${outdir}
_INSTDIR=\$(DESTDIR)\$(PREFIX)
diff --git a/configure b/configure
index 7b1a48b785b7ab1a8811cb36ea9ee00a68fc9ff8..680b57fc9e319c2707e0cc2ded0bc22597544d78 100755
--- a/configure
+++ b/configure
@@ -4,7 +4,10 @@ eval ". $srcdir/config.sh"
gmni() {
genrules gmnic \
src/gmnic.c
src/client.c \
src/escape.c \
src/gmnic.c \
src/url.c
}
all="gmnic"
diff --git a/include/client.h b/include/client.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbd73234311331ea52650d59dbd9cf535b73298b
--- /dev/null
+++ b/include/client.h
@@ -0,0 +1,67 @@
+#ifndef GEMINI_CLIENT_H
+#define GEMINI_CLIENT_H
+#include <netdb.h>
+#include <openssl/ssl.h>
+#include <sys/socket.h>
+struct gemini_response {
+};
+struct gemini_options {
+};
+enum gemini_result {
+};
+// Requests the specified URL via the gemini protocol. If options is non-NULL,
+// it may specify some additional configuration to adjust client behavior.
+//
+// Returns a value indicating the success of the request. If GEMINI_OK is
+// returned, the response details shall be written to the gemini_response
+// argument.
+enum gemini_result gemini_request(const char *url,
struct gemini_options *options,
struct gemini_response *resp);
+// Must be called after gemini_request in order to free up the resources
+// allocated during the request. If you intend to re-use the SSL_CTX provided by
+// gemini_options, set the ctx pointer to NULL before calling
+// gemini_response_finish.
+void gemini_response_finish(struct gemini_response *resp);
+#endif
diff --git a/include/escape.h b/include/escape.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1184ba3141b2992b0b18e44105bdc4474a7d8c9
--- /dev/null
+++ b/include/escape.h
@@ -0,0 +1,175 @@
+#ifndef ESCAPE_H
+#define ESCAPE_H
+/***************************************************************************
_ _ ____ _
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
+/* from curl.h */
+typedef enum {
7.17.0, reused in April 2011 for 7.21.5] */
due to lack of access - when login fails
this is not returned. */
7.15.4, reused in Dec 2011 for 7.24.0]*/
[was obsoleted in August 2007 for 7.17.0,
reused in Dec 2011 for 7.24.0]*/
[was obsoleted in August 2007 for 7.17.0,
reused in July 2014 for 7.38.0] */
instead of a memory allocation error if CURL_DOES_CONVERSIONS
is defined
default */
wasn't verified fine */
that failed */
accepted and we failed to login */
callbacks using curl_easy_setopt options
CURLOPT_CONV_FROM_NETWORK_FUNCTION,
CURLOPT_CONV_TO_NETWORK_FUNCTION, and
CURLOPT_CONV_FROM_UTF8_FUNCTION */
or wrong format */
generic so the error message will be of
interest when this has happened */
connection */
wait till it's ready and try again (Added
in 7.18.2) */
wrong format (Added in 7.19.0) */
7.19.0) */
session will be queued */
match */
*/
inside a callback */
+} CURLcode;
+/* Escape and unescape URL encoding in strings. The functions return a new
+bool Curl_isunreserved(unsigned char in);
+CURLcode Curl_urldecode(const char *string, size_t length,
char **ostring, size_t *olen,
bool reject_crlf);
+char *curl_easy_escape(const char *string, int length);
+char *curl_escape(const char *string, int length);
+char *curl_easy_unescape(const char *string,
int length, int *outlength);
+char *curl_unescape(const char *string, int length);
+#endif /* HEADER_CURL_ESCAPE_H */
diff --git a/include/url.h b/include/url.h
new file mode 100644
index 0000000000000000000000000000000000000000..155fd55740dbe47a498062713aca217ab259734f
--- /dev/null
+++ b/include/url.h
@@ -0,0 +1,103 @@
+#ifndef URLAPI_H
+#define URLAPI_H
+/***************************************************************************
_ _ ____ _
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
+/* the error codes for the URL API */
+typedef enum {
+} CURLUcode;
+typedef enum {
+} CURLUPart;
+#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;
+/*
+struct Curl_URL *curl_url(void);
+/*
+void curl_url_cleanup(struct Curl_URL *handle);
+/*
+struct Curl_URL *curl_url_dup(struct Curl_URL *in);
+/*
+CURLUcode curl_url_get(struct Curl_URL *handle, CURLUPart what,
+/*
+CURLUcode curl_url_set(struct Curl_URL *handle, CURLUPart what,
+#endif
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f2debb52c310f88e82ad83ca2251ba233d6a704
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,190 @@
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "client.h"
+#include "url.h"
+static enum gemini_result
+gemini_get_addrinfo(struct Curl_URL *uri, struct gemini_options *options,
+{
port = (int)strtol(uport, NULL, 10);
free(uport);
*addr = options->addr;
struct addrinfo hints = {0};
if (options && options->hints) {
hints = *options->hints;
} else {
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
}
char pbuf[7];
snprintf(pbuf, sizeof(pbuf), "%d", port);
char *domain;
CURLUcode uc = curl_url_get(uri, CURLUPART_HOST, &domain, 0);
assert(uc == CURLUE_OK);
int r = getaddrinfo(domain, pbuf, &hints, addr);
free(domain);
if (r != 0) {
resp->status = r;
return GEMINI_ERR_RESOLVE;
}
+}
+static enum gemini_result
+gemini_connect(struct Curl_URL *uri, struct gemini_options *options,
struct gemini_response *resp, int *sfd)
+{
goto cleanup;
*sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (*sfd == -1) {
continue;
}
if (connect(*sfd, rp->ai_addr, rp->ai_addrlen) != -1) {
break;
}
close(*sfd);
resp->status = errno;
res = GEMINI_ERR_CONNECT;
return res;
+cleanup:
freeaddrinfo(addr);
+}
+#define GEMINI_META_MAXLEN 1024
+#define GEMINI_STATUS_MAXLEN 2
+enum gemini_result
+gemini_request(const char *url, struct gemini_options *options,
struct gemini_response *resp)
+{
return GEMINI_ERR_INVALID_URL;
return GEMINI_ERR_OOM;
return GEMINI_ERR_INVALID_URL;
resp->ssl_ctx = options->ssl_ctx;
SSL_CTX_up_ref(options->ssl_ctx);
resp->ssl_ctx = SSL_CTX_new(TLS_method());
assert(resp->ssl_ctx);
resp->ssl = options->ssl;
SSL_up_ref(resp->ssl);
BIO_set_ssl(sbio, resp->ssl, 0);
resp->fd = -1;
res = gemini_connect(uri, options, resp, &resp->fd);
if (res != GEMINI_OK) {
goto cleanup;
}
resp->ssl = SSL_new(resp->ssl_ctx);
assert(resp->ssl);
int r = SSL_set_fd(resp->ssl, resp->fd);
if (r != 1) {
resp->status = r;
res = GEMINI_ERR_SSL;
goto cleanup;
}
r = SSL_connect(resp->ssl);
if (r != 1) {
resp->status = r;
res = GEMINI_ERR_SSL;
goto cleanup;
}
BIO_set_ssl(sbio, resp->ssl, 0);
res = GEMINI_ERR_IO;
goto cleanup;
+ GEMINI_STATUS_MAXLEN
+ 2 /* CRLF */ + 1 /* NUL */];
res = GEMINI_ERR_IO;
goto cleanup;
+cleanup:
+}
+void
+gemini_response_finish(struct gemini_response *resp)
+{
return;
close(resp->fd);
+}
diff --git a/src/escape.c b/src/escape.c
new file mode 100644
index 0000000000000000000000000000000000000000..d083da699d96f01a94a6ce8a86e41f0a47c54ffe
--- /dev/null
+++ b/src/escape.c
@@ -0,0 +1,213 @@
+/***************************************************************************
_ _ ____ _
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
+/* Escape and unescape URL encoding in strings. The functions return a new
+#include <ctype.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "escape.h"
+/* Portable character check (remember EBCDIC). Do not use isalnum() because
+*/
+bool Curl_isunreserved(unsigned char in)
+{
return true;
break;
+}
+/* for ABI-compatibility with previous versions */
+char *curl_escape(const char *string, int inlength)
+{
+}
+/* for ABI-compatibility with previous versions */
+char *curl_unescape(const char *string, int length)
+{
+}
+char *curl_easy_escape(const char *string, int inlength)
+{
/* just copy this */
ns[strindex++] = in;
/* encode it */
newlen += 2; /* the size grows with two, since this'll become a %XX */
if(newlen > alloc) {
alloc *= 2;
testing_ptr = realloc(ns, alloc);
if(!testing_ptr)
return NULL;
ns = testing_ptr;
}
snprintf(&ns[strindex], 4, "%%%02X", in);
strindex += 3;
+}
+/*
+CURLcode Curl_urldecode(const char *string, size_t length,
char **ostring, size_t *olen,
bool reject_ctrl)
+{
isxdigit(string[1]) && isxdigit(string[2])) {
/* this is two hexadecimal digits following a '%' */
char hexstr[3];
char *ptr;
hexstr[0] = string[1];
hexstr[1] = string[2];
hexstr[2] = 0;
hex = strtoul(hexstr, &ptr, 16);
in = (unsigned char)hex; /* this long is never bigger than 255 anyway */
string += 2;
alloc -= 2;
free(ns);
return CURLE_URL_MALFORMAT;
+}
+/*
+char *curl_easy_unescape(const char *string, int length, int *olen)
+{
return NULL;
if(outputlen <= (size_t) INT_MAX)
*olen = (int)outputlen;
else
/* too large to return in an int, fail! */
free(str);
+}
+/* For operating systems/environments that use different malloc/free
+void curl_free(void *p)
+{
+}
diff --git a/src/gmnic.c b/src/gmnic.c
index 35a49493cc6af2486d055c9bde5a576942c2e40a..7b2eb183ebfe67dce0aaf8c6010bf6785b503df6 100644
--- a/src/gmnic.c
+++ b/src/gmnic.c
@@ -1,8 +1,91 @@
+#include <assert.h>
+#include <getopt.h>
+#include <openssl/err.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
+#include "client.h"
+static void
+usage(char *argv_0)
+{
"usage: %s [-LI] [-C cert] [-d input] gemini://...\n",
argv_0);
+}
int
-main(int argc, char *argv[]) {
+main(int argc, char *argv[])
+{
switch (c) {
case '4':
assert(0); // TODO
break;
case '6':
assert(0); // TODO
break;
case 'C':
certificate = optarg;
break;
case 'd':
input = optarg;
break;
case 'h':
usage(argv[0]);
return 0;
case 'L':
follow_redirect = true;
break;
case 'I':
headers = true;
break;
default:
fprintf(stderr, "fatal: unknown flag %c", c);
return 1;
}
usage(argv[0]);
return 1;
printf("OK\n");
break;
printf("OOM\n");
break;
printf("INVALID_URL\n");
break;
printf("RESOLVE\n");
break;
printf("CONNECT\n");
break;
fprintf(stderr, "SSL error: %s\n", ERR_error_string(
SSL_get_error(resp.ssl, resp.status), NULL));
break;
return 0;
}
diff --git a/src/url.c b/src/url.c
new file mode 100644
index 0000000000000000000000000000000000000000..47e31b5fcbeeecb5bc3962585311b20e3518bb73
--- /dev/null
+++ b/src/url.c
@@ -0,0 +1,1448 @@
+/***************************************************************************
_ _ ____ _
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
+#define MAX_SCHEME_LEN 8
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "escape.h"
+#include "url.h"
+/* Provided by gmni */
+static char *
+aprintf(const char *fmt, ...)
+{
+}
+/* via lib/dotdot.c */
+char *Curl_dedotdotify(const char *input)
+{
remove that prefix from the input buffer; otherwise, */
clone += 2;
clen -= 2;
clone += 3;
clen -= 3;
"." is a complete path segment, then replace that prefix with "/" in
the input buffer; otherwise, */
clone += 2;
clen -= 2;
clone[1]='/';
clone++;
clen -= 1;
".." is a complete path segment, then replace that prefix with "/" in
the input buffer and remove the last segment and its preceding "/" (if
any) from the output buffer; otherwise, */
clone += 3;
clen -= 3;
/* remove the last segment from the output buffer */
while(outptr > out) {
outptr--;
if(*outptr == '/')
break;
}
*outptr = 0; /* zero-terminate where it stops */
clone[2]='/';
clone += 2;
clen -= 2;
/* remove the last segment from the output buffer */
while(outptr > out) {
outptr--;
if(*outptr == '/')
break;
}
*outptr = 0; /* zero-terminate where it stops */
that from the input buffer; otherwise, */
*clone = 0;
*out = 0;
/* E. move the first path segment in the input buffer to the end of
the output buffer, including the initial "/" character (if any) and
any subsequent characters up to, but not including, the next "/"
character or the end of the input buffer. */
do {
*outptr++ = *clone++;
clen--;
} while(*clone && (*clone != '/'));
*outptr = 0;
may now have been altered so we copy from the original input string
from the correct index. */
+}
+/* via lib/url.c */
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userp, char **passwdp,
char **optionsp)
+{
psep = NULL;
osep = NULL;
(size_t)(osep && psep > osep ? osep - login : psep - login) :
(osep ? (size_t)(osep - login) : len));
(osep && osep > psep ? (size_t)(osep - psep) :
(size_t)(login + len - psep)) - 1 : 0);
(psep && psep > osep ? (size_t)(psep - osep) :
(size_t)(login + len - osep)) - 1 : 0);
result = CURLE_OUT_OF_MEMORY;
free(ubuf);
result = CURLE_OUT_OF_MEMORY;
free(pbuf);
free(ubuf);
result = CURLE_OUT_OF_MEMORY;
memcpy(ubuf, login, ulen);
ubuf[ulen] = '\0';
free(*userp);
*userp = ubuf;
memcpy(pbuf, psep + 1, plen);
pbuf[plen] = '\0';
free(*passwdp);
*passwdp = pbuf;
memcpy(obuf, osep + 1, olen);
obuf[olen] = '\0';
free(*optionsp);
*optionsp = obuf;
+}
+/* Internal representation of CURLU. Point to URL-encoded strings. */
+struct Curl_URL {
+};
+#define DEFAULT_SCHEME "https"
+static void free_urlhandle(struct Curl_URL *u)
+{
+}
+/* move the full contents of one handle onto another and
+static void mv_urlhandle(struct Curl_URL *from,
struct Curl_URL *to)
+{
+}
+/*
+static const char *find_host_sep(const char *url)
+{
+}
+/*
+static bool urlchar_needs_escaping(int c)
+{
+}
+/*
+size_t Curl_strlen_url(const char *url, bool relative)
+{
++newlen;
continue;
left = false;
/* FALLTHROUGH */
if(urlchar_needs_escaping(*ptr))
newlen += 2;
newlen++;
break;
if(left)
newlen += 3;
else
newlen++;
break;
+}
+/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
+void Curl_strcpy_url(char *output, const char *url, bool relative)
+{
*iptr; /* until zero byte */
iptr++) {
*optr++ = *iptr;
continue;
left = false;
/* FALLTHROUGH */
if(urlchar_needs_escaping(*iptr)) {
snprintf(optr, 4, "%%%02x", *iptr);
optr += 3;
}
else
*optr++=*iptr;
break;
if(left) {
*optr++='%'; /* add a '%' */
*optr++='2'; /* add a '2' */
*optr++='0'; /* add a '0' */
}
else
*optr++='+'; /* add a '+' here */
break;
+}
+/*
+bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
+{
if(buf)
buf[i] = 0;
return true;
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
if(buf)
buf[i] = (char)tolower(s);
break;
+}
+/*
+char *Curl_concat_url(const char *base, const char *relurl)
+{
point to read-only data */
and cut it and the right-side of that off */
*pathsep = 0;
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 */
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
that position instead */
protsep = pathsep + 1;
protsep = NULL;
and act accordingly */
useurl += 2; /* just skip the "./" */
(useurl[1] == '.') &&
(useurl[2] == '/')) {
level++;
useurl += 3; /* pass the "../" */
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;
}
}
/* 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;
/* 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;
}
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 + 1 /* zero byte */);
+}
+/*
+static CURLUcode parse_hostname_login(struct Curl_URL *u,
char **hostname,
unsigned int flags)
+{
options if the handler says we should. Note that 'h' might be NULL! */
&userp, &passwdp, NULL);
/* Option DISALLOW_USER is set and url contains username. */
result = CURLUE_USER_NOT_ALLOWED;
goto out;
+}
+static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
+{
&endbracket, &len)) &&
(']' == endbracket)) {
if(*portptr != ':')
return CURLUE_MALFORMED_INPUT;
portptr = NULL;
return CURLUE_BAD_PORT_NUMBER;
/* Single unix standard says port numbers are 16 bits long, but we don't
treat port zero as OK. */
return CURLUE_BAD_PORT_NUMBER;
return CURLUE_BAD_PORT_NUMBER;
*portptr++ = '\0'; /* cut off the name there */
*rest = 0;
/* generate a new to get rid of leading zeroes etc */
snprintf(portbuf, sizeof(portbuf), "%ld", port);
u->portnum = port;
u->port = strdup(portbuf);
if(!u->port)
return CURLUE_OUT_OF_MEMORY;
/* Browser behavior adaptation. If there's a colon with no digits after,
just cut off the name there which makes us ignore the colon and just
use the default port. Firefox and Chrome both do that. */
*portptr = '\0';
+}
+/* scan for byte values < 31 or 127 */
+static CURLUcode junkscan(char *part)
+{
/* since we don't know which part is scanned, return a generic error
code */
return CURLUE_MALFORMED_INPUT;
+}
+static CURLUcode hostname_check(char *hostname, unsigned int flags)
+{
/* hostname with bad content */
return CURLUE_MALFORMED_INPUT;
/* hostname with bad content */
return CURLUE_MALFORMED_INPUT;
+}
+#define HOSTNAME_END(x) (((x) == '/') || ((x) == '?') || ((x) == '#'))
+static CURLUcode seturl(const char *url, struct Curl_URL *u, unsigned int flags)
+{
return CURLUE_OUT_OF_MEMORY;
* "file://")
*
* We allow omitted hostname (e.g. file:/<path>) -- valid according to
* RFC 8089, but not the (current) WHAT-WG URL spec.
*/
/* swallow the two slashes */
char *ptr = &path[2];
path = ptr;
int i = 0;
p = &url[schemelen + 1];
while(p && (*p == '/') && (i < 4)) {
p++;
i++;
}
if((i < 1) || (i>3))
/* less than one or more than three slashes */
return CURLUE_MALFORMED_INPUT;
schemep = schemebuf;
if(junkscan(schemep))
return CURLUE_MALFORMED_INPUT;
/* no scheme! */
return CURLUE_MALFORMED_INPUT;
p++;
return CURLUE_MALFORMED_INPUT;
return CURLUE_OUT_OF_MEMORY;
return CURLUE_OUT_OF_MEMORY;
/* if we got a new version */
path = newp;
path_alloced = true;
free(newp);
return CURLUE_OUT_OF_MEMORY;
* Parse the login details and strip them out of the host name.
*/
return CURLUE_MALFORMED_INPUT;
return result;
return result;
return result;
return CURLUE_OUT_OF_MEMORY;
return CURLUE_OUT_OF_MEMORY;
return CURLUE_OUT_OF_MEMORY;
+}
+/*
+static CURLUcode parseurl(const char *url, struct Curl_URL *u, unsigned int flags)
+{
+}
+/*
+struct Curl_URL *curl_url(void)
+{
+}
+void curl_url_cleanup(struct Curl_URL *u)
+{
+}
+#define DUP(dest, src, name) \
goto fail; \
+struct Curl_URL *curl_url_dup(struct Curl_URL *in)
+{
+}
+CURLUcode curl_url_get(struct Curl_URL *u, CURLUPart what,
char **part, unsigned int flags)
+{
ptr = u->path = strdup("/");
if(!u->path)
return CURLUE_OUT_OF_MEMORY;
url = aprintf("file://%s%s%s",
u->path,
u->fragment? "#": "",
u->fragment? u->fragment : "");
return CURLUE_NO_HOST;
if(u->scheme)
scheme = u->scheme;
else
return CURLUE_NO_SCHEME;
options = NULL;
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
scheme,
u->user ? u->user : "",
u->password ? ":": "",
u->password ? u->password : "",
options ? ";" : "",
options ? options : "",
(u->user || u->password || options) ? "@": "",
u->host,
port ? ":": "",
port ? port : "",
(u->path && (u->path[0] != '/')) ? "/": "",
u->path ? u->path : "/",
u->query? "?": "",
u->query? u->query : "",
u->fragment? "#": "",
u->fragment? u->fragment : "");
return CURLUE_OUT_OF_MEMORY;
return CURLUE_OUT_OF_MEMORY;
/* convert + to space */
char *plus;
for(plus = *part; *plus; ++plus) {
if(*plus == '+')
*plus = ' ';
}
char *decoded;
size_t dlen;
CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, true);
free(*part);
if(res) {
*part = NULL;
return CURLUE_URLDECODE;
}
*part = decoded;
+}
+CURLUcode curl_url_set(struct Curl_URL *u, CURLUPart what,
const char *part, unsigned int flags)
+{
break;
storep = &u->scheme;
break;
storep = &u->user;
break;
storep = &u->password;
break;
storep = &u->options;
break;
storep = &u->host;
break;
storep = &u->port;
break;
storep = &u->path;
break;
storep = &u->query;
break;
storep = &u->fragment;
break;
return CURLUE_UNKNOWN_PART;
free(*storep);
*storep = NULL;
return CURLUE_BAD_PORT_NUMBER;
* Allow a new URL to replace the existing (if any) contents.
*
* If the existing contents is enough for a URL, allow a relative URL to
* replace it.
*/
handle2 = curl_url();
if(!handle2)
return CURLUE_OUT_OF_MEMORY;
result = parseurl(part, handle2, flags);
if(!result)
mv_urlhandle(handle2, u);
else
curl_url_cleanup(handle2);
return result;
/* couldn't get the old URL, just use the new! */
handle2 = curl_url();
if(!handle2)
return CURLUE_OUT_OF_MEMORY;
result = parseurl(part, handle2, flags);
if(!result)
mv_urlhandle(handle2, u);
else
curl_url_cleanup(handle2);
return result;
return CURLUE_OUT_OF_MEMORY;
free(redired_url);
return CURLUE_OUT_OF_MEMORY;
mv_urlhandle(handle2, u);
curl_url_cleanup(handle2);
const char *i;
char *o;
bool free_part = false;
char *enc = malloc(nalloc * 3 + 1); /* for worst case! */
if(!enc)
return CURLUE_OUT_OF_MEMORY;
if(plusencode) {
/* space to plus */
i = part;
for(o = enc; *i; ++o, ++i)
*o = (*i == ' ') ? '+' : *i;
*o = 0; /* zero terminate */
part = strdup(enc);
if(!part) {
free(enc);
return CURLUE_OUT_OF_MEMORY;
}
free_part = true;
}
for(i = part, o = enc; *i; i++) {
if(Curl_isunreserved(*i) ||
((*i == '/') && urlskipslash) ||
((*i == '=') && equalsencode) ||
((*i == '+') && plusencode)) {
if((*i == '=') && equalsencode)
/* only skip the first equals sign */
equalsencode = false;
*o = *i;
o++;
}
else {
snprintf(o, 4, "%%%02x", *i);
o += 3;
}
}
*o = 0; /* zero terminate */
newp = enc;
if(free_part)
free((char *)part);
char *p;
newp = strdup(part);
if(!newp)
return CURLUE_OUT_OF_MEMORY;
p = (char *)newp;
while(*p) {
/* make sure percent encoded are lower case */
if((*p == '%') && isxdigit(p[1]) && isxdigit(p[2]) &&
(isupper(p[1]) || isupper(p[2]))) {
p[1] = (char)tolower(p[1]);
p[2] = (char)tolower(p[2]);
p += 3;
}
else
p++;
}
/* Append the string onto the old query. Add a '&' separator if none is
present at the end of the exsting query already */
size_t querylen = u->query ? strlen(u->query) : 0;
bool addamperand = querylen && (u->query[querylen -1] != '&');
if(querylen) {
size_t newplen = strlen(newp);
char *p = malloc(querylen + addamperand + newplen + 1);
if(!p) {
free((char *)newp);
return CURLUE_OUT_OF_MEMORY;
}
strcpy(p, u->query); /* original query */
if(addamperand)
p[querylen] = '&'; /* ampersand */
strcpy(&p[querylen + addamperand], newp); /* new suffix */
free((char *)newp);
free(*storep);
*storep = p;
return CURLUE_OK;
}
fails */
+}
text/gemini
This content has been proxied by September (ba2dc).