url construction helpers
This commit is contained in:
parent
6f9354cac6
commit
3859a40f24
@ -22,6 +22,7 @@
|
|||||||
#define TALER_UTIL_H
|
#define TALER_UTIL_H
|
||||||
|
|
||||||
#include <gnunet/gnunet_util_lib.h>
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
|
#include <microhttpd.h>
|
||||||
#include "taler_amount_lib.h"
|
#include "taler_amount_lib.h"
|
||||||
#include "taler_crypto_lib.h"
|
#include "taler_crypto_lib.h"
|
||||||
|
|
||||||
@ -134,4 +135,62 @@ const struct GNUNET_OS_ProjectData *
|
|||||||
TALER_project_data_default (void);
|
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
|
#endif
|
||||||
|
@ -57,11 +57,13 @@ libtalerutil_la_LDFLAGS = \
|
|||||||
|
|
||||||
TESTS = \
|
TESTS = \
|
||||||
test_amount \
|
test_amount \
|
||||||
test_crypto
|
test_crypto \
|
||||||
|
test_url
|
||||||
|
|
||||||
check_PROGRAMS = \
|
check_PROGRAMS = \
|
||||||
test_amount \
|
test_amount \
|
||||||
test_crypto
|
test_crypto \
|
||||||
|
test_url
|
||||||
|
|
||||||
|
|
||||||
test_amount_SOURCES = \
|
test_amount_SOURCES = \
|
||||||
@ -75,3 +77,9 @@ test_crypto_SOURCES = \
|
|||||||
test_crypto_LDADD = \
|
test_crypto_LDADD = \
|
||||||
-lgnunetutil \
|
-lgnunetutil \
|
||||||
libtalerutil.la
|
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 */
|
/* end of util.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user