return result;
}
+
+char *
+pstrndup(char const *s, size_t size)
+{
+ char *result;
+
+ result = strndup(s, size);
+ if (result == NULL)
+ enomem_panic();
+
+ return result;
+}
/* strdup(), but panic on allocation failure. */
char *pstrdup(char const *s);
+char *pstrndup(char const *s, size_t size);
#endif /* SRC_ALLOC_H_ */
get_url(struct rpki_uri *uri, const char *tal, struct rpki_uri **url)
{
char const *guri, *c;
- char *guri2;
+ char *gcopy;
unsigned int slashes;
int error;
- if (uri_get_type(uri) != UT_RPP) {
- uri_refget(uri);
- *url = uri;
- return 0;
- }
+ if (uri_get_type(uri) != UT_RPP)
+ goto reuse_uri;
/*
* Careful with this code. rsync(1):
* But note: This only works if we're synchronizing a directory.
* But this is fine, because this hack stacks with the minimum common
* path performance hack.
+ *
+ * Minimum common path performance hack: rsync the rsync module root,
+ * not every RPP separately. The former is much faster.
*/
guri = uri_get_global(uri);
for (c = guri; *c != '\0'; c++) {
if (*c == '/') {
slashes++;
- if (slashes == 4)
- return __uri_create(url, tal, UT_RPP,
- NULL, guri, c - guri + 1);
+ if (slashes == 4) {
+ if (c[1] == '\0')
+ goto reuse_uri;
+ gcopy = pstrndup(guri, c - guri + 1);
+ goto gcopy2url;
+ }
}
}
- if (slashes == 3 && *(c - 1) != '/') {
- guri2 = pstrdup(guri); /* Remove const */
- guri2[c - guri] = '/';
- error = __uri_create(url, tal, UT_RPP, NULL, guri2,
- c - guri + 1);
- free(guri2);
- return error;
+ if (slashes == 3 && c[-1] != '/') {
+ gcopy = pmalloc(c - guri + 2);
+ memcpy(gcopy, guri, c - guri);
+ gcopy[c - guri] = '/';
+ gcopy[c - guri + 1] = '\0';
+ goto gcopy2url;
}
- /*
- * Minimum common path performance hack: rsync the rsync module root,
- * not every RPP separately. The former is much faster.
- */
return pr_val_err("Can't rsync URL '%s': The URL seems to be missing a domain or rsync module.",
guri);
+
+reuse_uri:
+ uri_refget(uri);
+ *url = uri;
+ return 0;
+
+gcopy2url:
+ error = uri_create(url, tal, UT_RPP, NULL, gcopy);
+ free(gcopy);
+ return error;
}
static bool
#endif
#define MAX_CAPACITY 4096u
+/* @reserve needs to be < INITIAL_CAPACITY. */
void
-pb_init(struct path_builder *pb)
+__pb_init(struct path_builder *pb, size_t reserve)
{
pb->string = pmalloc(INITIAL_CAPACITY);
- pb->string[0] = 0;
- pb->len = 0;
+ pb->string[reserve] = 0;
+ pb->len = reserve;
pb->capacity = INITIAL_CAPACITY;
}
size_t capacity;
};
-void pb_init(struct path_builder *);
+void __pb_init(struct path_builder *, size_t);
+#define pb_init(pb) __pb_init(pb, 0)
int pb_init_cache(struct path_builder *, char const *, char const *);
/*
* Create @uri from the @ad
*/
static int
-uri_create_ad(struct rpki_uri **uri, ACCESS_DESCRIPTION *ad, enum uri_type type,
- bool is_notif)
+uri_create_ad(struct rpki_uri **uri, ACCESS_DESCRIPTION *ad, enum uri_type type)
{
ASN1_STRING *asn1str;
+ char *str;
int ptype;
+ int error;
asn1str = GENERAL_NAME_get0_value(ad->location, &ptype);
/*
* GEN_URI signals an IA5String.
* IA5String is a subset of ASCII, so this cast is safe.
- * No guarantees of a NULL chara, though.
+ * No guarantees of a NULL chara though, which is why we need a dup.
*
* TODO (testers) According to RFC 5280, accessLocation can be an IRI
* somehow converted into URI form. I don't think that's an issue
* directory our g2l version of @asn1_string should contain.
* But ask the testers to keep an eye on it anyway.
*/
- return __uri_create(uri,
- tal_get_file_name(validation_tal(state_retrieve())), type, NULL,
- ASN1_STRING_get0_data(asn1str), ASN1_STRING_length(asn1str));
+ str = pstrndup((char const *)ASN1_STRING_get0_data(asn1str),
+ ASN1_STRING_length(asn1str));
+
+ error = uri_create(uri,
+ tal_get_file_name(validation_tal(state_retrieve())),
+ type, NULL, str);
+
+ free(str);
+ return error;
}
/**
for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ia); i++) {
ad = sk_ACCESS_DESCRIPTION_value(ia, i);
if (OBJ_obj2nid(ad->method) == nid) {
- error = uri_create_ad(&uri, ad, meta->type,
- meta == &RPKI_NOTIFY);
+ error = uri_create_ad(&uri, ad, meta->type);
switch (error) {
case 0:
break;
return uri_create_caged(uri,
tal_get_file_name(validation_tal(state_retrieve())), notif,
- uri_get_global(*uri), uri_get_global_len(*uri));
+ uri_get_global(*uri));
}
static int
* non-ASCII characters.
*/
char *global;
- /** Length of @global. */
- size_t global_len;
/**
* "Local URI".
: pr_val_err("URL has non-printable character code '%d'.", character);
}
+static int append_guri(struct path_builder *, char const *, char const *,
+ int, bool);
+
/**
- * Initializes @uri->global* by cloning @str.
- * This function does not assume that @str is null-terminated.
+ * Initializes @uri->global by building a normalized version of @str.
*/
static int
-str2global(char const *str, size_t str_len, struct rpki_uri *uri)
+str2global(char const *str, struct rpki_uri *uri)
{
+#define SCHEMA_LEN 8 /* strlen("rsync://"), strlen("https://") */
+
+ char const *s;
+ char const *pfx;
int error;
- size_t i;
+ struct path_builder pb;
- for (i = 0; i < str_len; i++) {
- error = validate_url_character(str[i]);
+ if (str == NULL){
+ uri->global = NULL;
+ return 0;
+ }
+
+ for (s = str; s[0] != '\0'; s++) {
+ error = validate_url_character(s[0]);
if (error)
return error;
}
- uri->global = pmalloc(str_len + 1);
- strncpy(uri->global, str, str_len);
- uri->global[str_len] = '\0';
- uri->global_len = str_len;
+ pfx = NULL;
+ error = 0;
+
+ switch (uri->type) {
+ case UT_TA_RSYNC:
+ case UT_RPP:
+ case UT_CAGED:
+ case UT_AIA:
+ case UT_SO:
+ case UT_MFT:
+ pfx = "rsync://";
+ error = ENOTRSYNC;
+ break;
+ case UT_TA_HTTP:
+ case UT_NOTIF:
+ case UT_TMP:
+ pfx = "https://";
+ error = ENOTHTTPS;
+ break;
+ }
+
+ if (pfx == NULL)
+ pr_crit("Unknown URI type: %u", uri->type);
+
+ __pb_init(&pb, SCHEMA_LEN - 1);
+ error = append_guri(&pb, str, pfx, error, true);
+ if (error) {
+ pb_cleanup(&pb);
+ return error;
+ }
+ uri->global = strncpy(pb.string, str, SCHEMA_LEN);
return 0;
}
joined[dir_len + ia5->size] = '\0';
uri->global = joined;
- uri->global_len = dir_len + ia5->size;
return 0;
}
if (error)
return error;
- error = append_guri(pb, notif->global, "https://", ENOTHTTPS, true);
+ error = pb_append(pb, ¬if->global[SCHEMA_LEN]);
if (error)
pb_cleanup(pb);
+
return error;
}
* Maps "rsync://a.b.c/d/e.cer" into "<local-repository>/rsync/a.b.c/d/e.cer".
*/
static int
-map_simple(struct rpki_uri *uri, char const *tal, char const *gprefix, int err)
+map_simple(struct rpki_uri *uri, char const *tal, char const *subdir)
{
struct path_builder pb;
int error;
- error = pb_init_cache(&pb, tal, NULL);
+ error = pb_init_cache(&pb, tal, subdir);
if (error)
return error;
- error = append_guri(&pb, uri->global, gprefix, err, false);
+ error = pb_append(&pb, &uri->global[SCHEMA_LEN]);
if (error) {
pb_cleanup(&pb);
return error;
if (error)
return error;
- if (uri->global[0] == '\0')
- goto end; /* Caller is only interested in the cage. */
+ if (uri->global == NULL)
+ goto success; /* Caller is only interested in the cage. */
- error = append_guri(&pb, uri->global, "rsync://", ENOTRSYNC, true);
+ error = pb_append(&pb, &uri->global[SCHEMA_LEN]);
if (error) {
pb_cleanup(&pb);
return error;
}
-end: uri->local = pb.string;
+success:
+ uri->local = pb.string;
return 0;
}
switch (uri->type) {
case UT_TA_RSYNC:
case UT_RPP:
- return map_simple(uri, tal, "rsync://", ENOTRSYNC);
+ return map_simple(uri, tal, "rsync");
case UT_TA_HTTP:
case UT_NOTIF:
- return map_simple(uri, tal, "https://", ENOTHTTPS);
+ return map_simple(uri, tal, "https");
case UT_TMP:
return cache_tmpfile(&uri->local);
/*
* I think the reason why @guri is not a char * is to convey that it doesn't
* need to be NULL terminated, but I'm not sure.
+ *
+ * FIXME callers now need to ensure @guri is NULL-terminated.
*/
int
-__uri_create(struct rpki_uri **result, char const *tal, enum uri_type type,
- struct rpki_uri *notif, void const *guri, size_t guri_len)
+uri_create(struct rpki_uri **result, char const *tal, enum uri_type type,
+ struct rpki_uri *notif, char const *guri)
{
struct rpki_uri *uri;
int error;
uri = pmalloc(sizeof(struct rpki_uri));
+ uri->type = type;
+ uri->references = 1;
- error = str2global(guri, guri_len, uri);
+ error = str2global(guri, uri);
if (error) {
free(uri);
return error;
}
- uri->type = type;
-
error = autocomplete_local(uri, tal, notif);
if (error) {
free(uri->global);
return error;
}
- uri->references = 1;
-
*result = uri;
return 0;
}
int error;
uri = pmalloc(sizeof(struct rpki_uri));
+ uri->type = (notif == NULL) ? UT_RPP : UT_CAGED;
+ uri->references = 1;
error = ia5str2global(uri, mft->global, ia5);
if (error) {
return error;
}
- uri->type = (notif == NULL) ? UT_RPP : UT_CAGED;
-
error = autocomplete_local(uri, tal, notif);
if (error) {
free(uri->global);
return error;
}
- uri->references = 1;
-
*result = uri;
return 0;
}
return uri->local;
}
-size_t
-uri_get_global_len(struct rpki_uri *uri)
-{
- return uri->global_len;
-}
-
bool
uri_equals(struct rpki_uri *u1, struct rpki_uri *u2)
{
bool
uri_has_extension(struct rpki_uri *uri, char const *ext)
{
+ size_t uri_len;
size_t ext_len;
int cmp;
+ uri_len = strlen(uri->global);
ext_len = strlen(ext);
- if (uri->global_len < ext_len)
+
+ if (uri_len < ext_len)
return false;
- cmp = strncmp(uri->global + uri->global_len - ext_len, ext, ext_len);
+ cmp = strncmp(uri->global + uri_len - ext_len, ext, ext_len);
return cmp == 0;
}
struct rpki_uri;
-int __uri_create(struct rpki_uri **, char const *, enum uri_type,
- struct rpki_uri *, void const *, size_t);
+int uri_create(struct rpki_uri **, char const *, enum uri_type,
+ struct rpki_uri *, char const *);
int uri_create_mft(struct rpki_uri **, char const *, struct rpki_uri *,
struct rpki_uri *, IA5String_t *);
struct rpki_uri *uri_create_cache(char const *);
-#define uri_create(uri, tal, type, notif, guri) \
- __uri_create(uri, tal, type, notif, guri, strlen(guri))
-#define uri_create_caged(uri, tal, notif, guri, guri_len) \
- __uri_create(uri, tal, UT_CAGED, notif, guri, guri_len)
+#define uri_create_caged(uri, tal, notif, guri) \
+ uri_create(uri, tal, UT_CAGED, notif, guri)
#define uri_create_cage(uri, tal, notif) \
- uri_create_caged(uri, tal, notif, "", 0)
+ uri_create_caged(uri, tal, notif, NULL)
struct rpki_uri *uri_refget(struct rpki_uri *);
void uri_refput(struct rpki_uri *);
*/
char const *uri_get_global(struct rpki_uri *);
char const *uri_get_local(struct rpki_uri *);
-size_t uri_get_global_len(struct rpki_uri *);
bool uri_equals(struct rpki_uri *, struct rpki_uri *);
bool uri_has_extension(struct rpki_uri *, char const *);
hash_setup();
uri.global = "https://example.com/resources/lorem-ipsum.txt";
- uri.global_len = strlen(uri.global);
uri.local = "resources/lorem-ipsum.txt";
uri.type = UT_TA_HTTP;
uri.references = 1;
ck_assert_int_eq(0, relax_ng_init());
notif_uri.global = "https://example.com/notification.xml";
- notif_uri.global_len = strlen(notif_uri.global);
notif_uri.local = "cache/example.com/notification.xml";
notif_uri.type = UT_NOTIF;
notif_uri.references = 1;
uri_refput(uri);
ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/"));
- ck_assert_str_eq("https://a.b.c/", uri_get_global(uri));
+ ck_assert_str_eq("https://a.b.c", uri_get_global(uri));
ck_assert_str_eq("tmp/test.tal/https/a.b.c", uri_get_local(uri));
uri_refput(uri);
uri_refput(uri);
ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/d/.."));
- ck_assert_str_eq("https://a.b.c/d/..", uri_get_global(uri));
+ ck_assert_str_eq("https://a.b.c", uri_get_global(uri));
ck_assert_str_eq("tmp/test.tal/https/a.b.c", uri_get_local(uri));
uri_refput(uri);
ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/."));
- ck_assert_str_eq("https://a.b.c/.", uri_get_global(uri));
+ ck_assert_str_eq("https://a.b.c", uri_get_global(uri));
ck_assert_str_eq("tmp/test.tal/https/a.b.c", uri_get_local(uri));
uri_refput(uri);
ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/././d/././e/./."));
- ck_assert_str_eq("https://a.b.c/././d/././e/./.", uri_get_global(uri));
+ ck_assert_str_eq("https://a.b.c/d/e", uri_get_global(uri));
ck_assert_str_eq("tmp/test.tal/https/a.b.c/d/e", uri_get_local(uri));
uri_refput(uri);
ck_assert_int_eq(0, URI_CREATE_HTTP(uri, "https://a.b.c/a/b/.././.."));
- ck_assert_str_eq("https://a.b.c/a/b/.././..", uri_get_global(uri));
+ ck_assert_str_eq("https://a.b.c", uri_get_global(uri));
ck_assert_str_eq("tmp/test.tal/https/a.b.c", uri_get_local(uri));
uri_refput(uri);