url construction helpers
This commit is contained in:
parent
6f9354cac6
commit
3859a40f24
@ -22,6 +22,7 @@
|
||||
#define TALER_UTIL_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
#include "taler_amount_lib.h"
|
||||
#include "taler_crypto_lib.h"
|
||||
|
||||
@ -134,4 +135,62 @@ const struct GNUNET_OS_ProjectData *
|
||||
TALER_project_data_default (void);
|
||||
|
||||
|
||||
/**
|
||||
* URL-encode a string according to rfc3986.
|
||||
*
|
||||
* @param s string to encode
|
||||
* @returns the urlencoded string, the caller must free it with GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_urlencode (const char *s);
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL with query parameters.
|
||||
*
|
||||
* @param base_url absolute base URL to use
|
||||
* @param path path of the url
|
||||
* @param ... NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* only the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_url_join (const char *base_url,
|
||||
const char *path,
|
||||
...);
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL for the given parameters.
|
||||
*
|
||||
* @param proto protocol for the URL (typically https)
|
||||
* @param host hostname for the URL
|
||||
* @param prefix prefix for the URL
|
||||
* @param path path for the URL
|
||||
* @param ... NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_url_absolute_raw (const char *proto,
|
||||
const char *host,
|
||||
const char *prefix,
|
||||
const char *path,
|
||||
...);
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL for a given MHD connection.
|
||||
*
|
||||
* @param path path of the url
|
||||
* @param ... NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_url_absolute_mhd (struct MHD_Connection *connection,
|
||||
const char *path,
|
||||
...);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -57,11 +57,13 @@ libtalerutil_la_LDFLAGS = \
|
||||
|
||||
TESTS = \
|
||||
test_amount \
|
||||
test_crypto
|
||||
test_crypto \
|
||||
test_url
|
||||
|
||||
check_PROGRAMS = \
|
||||
test_amount \
|
||||
test_crypto
|
||||
test_crypto \
|
||||
test_url
|
||||
|
||||
|
||||
test_amount_SOURCES = \
|
||||
@ -75,3 +77,9 @@ test_crypto_SOURCES = \
|
||||
test_crypto_LDADD = \
|
||||
-lgnunetutil \
|
||||
libtalerutil.la
|
||||
|
||||
test_url_SOURCES = \
|
||||
test_url.c
|
||||
test_url_LDADD = \
|
||||
-lgnunetutil \
|
||||
libtalerutil.la
|
||||
|
300
src/util/util.c
300
src/util/util.c
@ -159,4 +159,304 @@ TALER_getopt_get_amount (char shortName,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a character is reserved and should
|
||||
* be urlencoded.
|
||||
*
|
||||
* @param c character to look at
|
||||
* @return #GNUNET_YES if @a c needs to be urlencoded,
|
||||
* #GNUNET_NO otherwise
|
||||
*/
|
||||
static bool
|
||||
is_reserved(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e':
|
||||
case 'f': case 'g': case 'h': case 'i': case 'j':
|
||||
case 'k': case 'l': case 'm': case 'n': case 'o':
|
||||
case 'p': case 'q': case 'r': case 's': case 't':
|
||||
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E':
|
||||
case 'F': case 'G': case 'H': case 'I': case 'J':
|
||||
case 'K': case 'L': case 'M': case 'N': case 'O':
|
||||
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
||||
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
|
||||
case '-': case '.': case '_': case '~':
|
||||
return GNUNET_NO;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL-encode a string according to rfc3986.
|
||||
*
|
||||
* @param s string to encode
|
||||
* @returns the urlencoded string, the caller must free it with GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_urlencode (const char *s)
|
||||
{
|
||||
unsigned int new_size;
|
||||
unsigned int i;
|
||||
unsigned int t;
|
||||
char *out;
|
||||
|
||||
new_size = strlen (s);
|
||||
for (i = 0; i < strlen (s); i++)
|
||||
if (GNUNET_YES == is_reserved (s[i]))
|
||||
new_size += 2;
|
||||
out = GNUNET_malloc (new_size + 1);
|
||||
for (i = 0, t = 0; i < strlen (s); i++, t++)
|
||||
{
|
||||
if (GNUNET_YES == is_reserved (s[i]))
|
||||
{
|
||||
snprintf(&out[t], 4, "%%%02X", s[i]);
|
||||
t += 2;
|
||||
continue;
|
||||
}
|
||||
out[t] = s[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grow a string in a buffer with the given size.
|
||||
* The buffer is re-allocated if necessary.
|
||||
*
|
||||
* @param s string buffer
|
||||
* @param p the string to append
|
||||
* @param n pointer to the allocated size of n
|
||||
* @returns pointer to the resulting buffer,
|
||||
* might differ from @a s (!!)
|
||||
*/
|
||||
static char *
|
||||
grow_string (char *s, const char *p, size_t *n)
|
||||
{
|
||||
for (; strlen (s) + strlen (p) >= *n; *n *= 2);
|
||||
s = GNUNET_realloc (s, *n);
|
||||
GNUNET_assert (NULL != s);
|
||||
strncat (s, p, *n);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Grow a string in a buffer with the given size.
|
||||
* The buffer is re-allocated if necessary.
|
||||
*
|
||||
* Ensures that slashes are removed or added when joining paths.
|
||||
*
|
||||
* @param s string buffer
|
||||
* @param p the string to append
|
||||
* @param n pointer to the allocated size of n
|
||||
* @returns pointer to the resulting buffer,
|
||||
* might differ from @a s (!!)
|
||||
*/
|
||||
static char *
|
||||
grow_string_path (char *s, const char *p, size_t *n)
|
||||
{
|
||||
char a = (0 == strlen (s)) ? '\0' : s[strlen (s) - 1];
|
||||
char b = (0 == strlen (p)) ? '\0' : p[0];
|
||||
|
||||
if ( (a == '/') && (b == '/'))
|
||||
{
|
||||
p++;
|
||||
}
|
||||
else if ( (a != '/') && (b != '/'))
|
||||
{
|
||||
if (NULL == (s = grow_string (s, "/", n)))
|
||||
return NULL;
|
||||
}
|
||||
return grow_string (s, p, n);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL with query parameters.
|
||||
*
|
||||
* @param base_url absolute base URL to use
|
||||
* @param path path of the url
|
||||
* @param ... NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_url_join (const char *base_url,
|
||||
const char *path,
|
||||
...)
|
||||
{
|
||||
size_t n = 256;
|
||||
char *res = GNUNET_malloc (n);
|
||||
unsigned int iparam = 0;
|
||||
char *enc;
|
||||
va_list args;
|
||||
|
||||
GNUNET_assert (NULL != res);
|
||||
|
||||
grow_string (res, base_url, &n);
|
||||
|
||||
grow_string_path (res, path, &n);
|
||||
|
||||
va_start (args, path);
|
||||
|
||||
while (1) {
|
||||
char *key;
|
||||
char *value;
|
||||
key = va_arg (args, char *);
|
||||
if (NULL == key)
|
||||
break;
|
||||
value = va_arg (args, char *);
|
||||
if (NULL == value)
|
||||
continue;
|
||||
grow_string (res, (0 == iparam) ? "?" : "&", &n);
|
||||
iparam++;
|
||||
grow_string (res, key, &n);
|
||||
grow_string (res, "=", &n);
|
||||
enc = TALER_urlencode (value);
|
||||
grow_string (res, enc, &n);
|
||||
GNUNET_free (enc);
|
||||
}
|
||||
|
||||
va_end (args);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL for the given parameters.
|
||||
*
|
||||
* @param proto protocol for the URL (typically https)
|
||||
* @param host hostname for the URL
|
||||
* @param prefix prefix for the URL
|
||||
* @param path path for the URL
|
||||
* @param args NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
url_absolute_raw_va (const char *proto,
|
||||
const char *host,
|
||||
const char *prefix,
|
||||
const char *path,
|
||||
va_list args)
|
||||
{
|
||||
size_t n = 256;
|
||||
char *res = GNUNET_malloc (n);
|
||||
char *enc;
|
||||
unsigned int iparam = 0;
|
||||
|
||||
grow_string (res, proto, &n);
|
||||
grow_string (res, "://", &n);
|
||||
grow_string (res, host, &n);
|
||||
|
||||
grow_string_path (res, prefix, &n);
|
||||
|
||||
grow_string_path (res, path, &n);
|
||||
|
||||
while (1) {
|
||||
char *key;
|
||||
char *value;
|
||||
key = va_arg (args, char *);
|
||||
if (NULL == key)
|
||||
break;
|
||||
value = va_arg (args, char *);
|
||||
if (NULL == value)
|
||||
continue;
|
||||
grow_string (res, (0 == iparam) ? "?" : "&", &n);
|
||||
iparam++;
|
||||
grow_string (res, key, &n);
|
||||
grow_string (res, "=", &n);
|
||||
enc = TALER_urlencode (value);
|
||||
grow_string (res, enc, &n);
|
||||
GNUNET_free (enc);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL for the given parameters.
|
||||
*
|
||||
* @param proto protocol for the URL (typically https)
|
||||
* @param host hostname for the URL
|
||||
* @param prefix prefix for the URL
|
||||
* @param path path for the URL
|
||||
* @param args NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_url_absolute_raw (const char *proto,
|
||||
const char *host,
|
||||
const char *prefix,
|
||||
const char *path,
|
||||
...)
|
||||
{
|
||||
char *result;
|
||||
va_list args;
|
||||
|
||||
va_start (args, path);
|
||||
result = url_absolute_raw_va (proto, host, prefix, path, args);
|
||||
va_end (args);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make an absolute URL for a given MHD connection.
|
||||
*
|
||||
* @param path path of the url
|
||||
* @param ... NULL-terminated key-value pairs (char *) for query parameters,
|
||||
* the value will be url-encoded
|
||||
* @returns the URL, must be freed with #GNUNET_free
|
||||
*/
|
||||
char *
|
||||
TALER_url_absolute_mhd (struct MHD_Connection *connection,
|
||||
const char *path,
|
||||
...)
|
||||
{
|
||||
/* By default we assume we're running under HTTPS */
|
||||
const char *proto = "https";
|
||||
const char *forwarded_proto = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "X-Forwarded-Proto");
|
||||
const char *host;
|
||||
const char *forwarded_host;
|
||||
const char *prefix;
|
||||
va_list args;
|
||||
char *result;
|
||||
|
||||
if (NULL != forwarded_proto)
|
||||
proto = forwarded_proto;
|
||||
|
||||
host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Host");
|
||||
forwarded_host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "X-Forwarded-Host");
|
||||
|
||||
prefix = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "X-Forwarded-Prefix");
|
||||
if (NULL == prefix)
|
||||
prefix = "";
|
||||
|
||||
if (NULL != forwarded_host)
|
||||
host = forwarded_host;
|
||||
|
||||
if (NULL == host)
|
||||
{
|
||||
/* Should never happen, at last the host header should be defined */
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start (args, path);
|
||||
result = TALER_url_absolute_raw (proto, host, prefix, path, args);
|
||||
va_end (args);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* end of util.c */
|
||||
|
Loading…
Reference in New Issue
Block a user