Fixes all the normalization TODOs.
...Well, except the curl URI normalization PR is on hold.
I might have to implement something myself later.
};
int
-RsyncRequest_init(struct RsyncRequest *req, char const *url, char const *path)
+RsyncRequest_init(struct RsyncRequest *req, struct uri const *url,
+ char const *path)
{
memset(req, 0, sizeof(*req));
- if (OCTET_STRING_fromString(&req->url, url) < 0)
+ if (OCTET_STRING_fromBuf(&req->url, uri_str(url), uri_len(url)) < 0)
return -1;
if (OCTET_STRING_fromString(&req->path, path) < 0)
return -1;
#define _RsyncRequest_H_
/* Including external dependencies */
+#include "types/url.h"
#include "asn1/asn1c/OCTET_STRING.h"
#include "asn1/asn1c/constr_SEQUENCE.h"
/* Implementation */
extern asn_TYPE_descriptor_t asn_DEF_RsyncRequest;
-int RsyncRequest_init(struct RsyncRequest *, char const *, char const *);
+int RsyncRequest_init(struct RsyncRequest *, struct uri const *, char const *);
#ifdef __cplusplus
}
* If node is rsync, @http is NULL.
* If node is HTTP, @http is the simple URL.
* If node is RRDP, @http is the rpkiNotify.
+ *
+ * Points to @id; do not clean.
*/
- char const *http;
+ struct uri http;
/*
* If node is rsync, @rsync is the simple URL.
* If node is HTTP, @rsync is NULL.
* If node is RRDP, @rsync is the caRepository.
+ *
+ * Points to @id; do not clean.
*/
- char const *rsync;
+ struct uri rsync;
};
/*
struct cache_cage {
struct cache_node const *refresh;
struct cache_node const *fallback;
- char const *rpkiNotify;
+ struct uri rpkiNotify;
struct mft_meta *mft; /* Fallback */
};
struct cache_commit {
- char *rpkiNotify;
- char *caRepository;
+ struct uri rpkiNotify;
+ struct uri caRepository;
struct cache_mapping *files;
size_t nfiles;
struct mft_meta mft; /* RPPs commits only */
foreach_node(delete_node, NULL);
}
-char *
-get_rsync_module(char const *url)
+/*
+ * - Result must not be cleant.
+ * - strlen(uri_str(module)) should not be trusted.
+ */
+static bool
+get_rsync_module(struct uri const *url, struct uri *module)
{
+ char const *str;
array_index u;
unsigned int slashes;
+ str = uri_str(url);
slashes = 0;
- for (u = 0; url[u] != 0; u++)
- if (url[u] == '/') {
+ for (u = 0; str[u] != 0; u++)
+ if (str[u] == '/') {
slashes++;
- if (slashes == 4)
- return pstrndup(url, u);
+ if (slashes == 4) {
+ __uri_init(module, str, u);
+ return true;
+ }
}
- if (slashes == 3 && url[u - 1] != '/')
- return pstrdup(url);
+ if (slashes == 3 && str[u - 1] != '/') {
+ *module = *url;
+ return true;
+ }
- pr_val_err("Url '%s' does not appear to have an rsync module.", url);
- return NULL;
+ pr_val_err("Url '%s' does not appear to have an rsync module.", str);
+ return false;
}
char const *
static json_t *
node2json(struct cache_node *node)
{
+ char const *str;
json_t *json;
json = json_obj_new();
if (json == NULL)
return NULL;
- if (node->key.http && json_add_str(json, "http", node->key.http))
+ str = uri_str(&node->key.http);
+ if (str && json_add_str(json, "http", str))
goto fail;
- if (node->key.rsync && json_add_str(json, "rsync", node->key.rsync))
+ str = uri_str(&node->key.rsync);
+ if (str && json_add_str(json, "rsync", str))
goto fail;
if (json_add_str(json, "path", node->path))
goto fail;
}
static void
-init_rrdp_fallback_key(struct node_key *key, char const *http, char const *rsync)
+init_rrdp_fallback_key(struct node_key *key, struct uri const *http,
+ struct uri const *rsync)
{
size_t hlen, rlen;
- hlen = strlen(http);
- rlen = strlen(rsync);
+ hlen = uri_len(http);
+ rlen = uri_len(rsync);
key->idlen = hlen + rlen + 1;
key->id = pmalloc(key->idlen + 1);
- key->http = key->id;
- key->rsync = key->id + hlen + 1;
+ __uri_init(&key->http, key->id, hlen);
+ __uri_init(&key->rsync, key->id + hlen + 1, rlen);
- memcpy(key->id, http, hlen + 1);
- memcpy(key->id + hlen + 1, rsync, rlen + 1);
+ memcpy(key->id, uri_str(http), hlen + 1);
+ memcpy(key->id + hlen + 1, uri_str(rsync), rlen + 1);
}
-static bool
-init_node_key(struct node_key *key, char const *http, char const *rsync)
+static int
+init_node_key(struct node_key *key, struct uri const *http,
+ struct uri const *rsync)
{
+ if (http && (uri_str(http) == NULL))
+ http = NULL;
+ if (rsync && (uri_str(rsync) == NULL))
+ rsync = NULL;
+
if (http != NULL && rsync != NULL) {
init_rrdp_fallback_key(key, http, rsync);
} else if (rsync != NULL) {
- key->id = pstrdup(rsync);
- key->idlen = strlen(key->id);
- key->http = NULL;
- key->rsync = key->id;
+ key->idlen = uri_len(rsync);
+ key->id = pstrndup(uri_str(rsync), key->idlen);
+ memset(&key->http, 0, sizeof(key->http));
+ __uri_init(&key->rsync, key->id, key->idlen);
} else if (http != NULL) {
- key->id = pstrdup(http);
- key->idlen = strlen(key->id);
- key->http = key->id;
- key->rsync = NULL;
+ key->idlen = uri_len(http);
+ key->id = pstrndup(uri_str(http), key->idlen);
+ __uri_init(&key->http, key->id, key->idlen);
+ memset(&key->rsync, 0, sizeof(key->rsync));
} else {
return false;
json2node(json_t *json)
{
struct cache_node *node;
- char const *http;
- char const *rsync;
+ struct uri http;
+ struct uri rsync;
char const *path;
json_t *rrdp;
int error;
- error = json_get_str(json, "http", &http);
+ error = json_get_uri(json, "http", &http);
if (error && (error != ENOENT)) {
pr_op_debug("http: %s", strerror(error));
return NULL;
}
- error = json_get_str(json, "rsync", &rsync);
+ error = json_get_uri(json, "rsync", &rsync);
if (error && (error != ENOENT)) {
pr_op_debug("rsync: %s", strerror(error));
+ uri_cleanup(&http);
return NULL;
}
node = pzalloc(sizeof(struct cache_node));
- if (!init_node_key(&node->key, http, rsync)) {
+ if (!init_node_key(&node->key, &http, &rsync)) {
pr_op_debug("JSON node is missing both http and rsync tags.");
+ uri_cleanup(&rsync);
+ uri_cleanup(&http);
goto nde;
}
+ uri_cleanup(&http);
+ uri_cleanup(&rsync);
+
error = json_get_str(json, "path", &path);
if (error) {
pr_op_debug("path: %s", strerror(error));
dl_rsync(struct cache_node *module)
{
int error;
- error = rsync_queue(module->key.rsync, module->path);
+ error = rsync_queue(&module->key.rsync, module->path);
return error ? error : EBUSY;
}
bool changed;
int error;
- error = rrdp_update(notif->key.http, notif->path, notif->success_ts,
+ error = rrdp_update(¬if->key.http, notif->path, notif->success_ts,
&changed, ¬if->rrdp);
if (error)
return error;
bool changed;
int error;
- error = http_download(file->key.http, file->path,
+ error = http_download(&file->key.http, file->path,
file->success_ts, &changed);
if (error)
return error;
}
static struct cache_node *
-provide_node(struct cache_table *tbl, char const *http, char const *rsync)
+provide_node(struct cache_table *tbl, struct uri const *http,
+ struct uri const *rsync)
{
struct node_key key;
struct cache_node *node;
* By contract, @result->state will be DLS_FRESH on return 0.
*/
static int
-do_refresh(struct cache_table *tbl, char const *uri, struct cache_node **result)
+do_refresh(struct cache_table *tbl, struct uri const *uri,
+ struct cache_node **result)
{
+ struct uri module;
struct cache_node *node;
bool downloaded = false;
- pr_val_debug("Trying %s (online)...", uri);
+ pr_val_debug("Trying %s (online)...", uri_str(uri));
if (!tbl->enabled) {
pr_val_debug("Protocol disabled.");
}
if (tbl == &cache.rsync) {
- char *module = get_rsync_module(uri);
- if (module == NULL)
+ if (!get_rsync_module(uri, &module))
return EINVAL;
mutex_lock(&tbl->lock);
- node = provide_node(tbl, NULL, module);
- free(module);
+ node = provide_node(tbl, NULL, &module);
} else {
mutex_lock(&tbl->lock);
node = provide_node(tbl, uri, NULL);
struct node_key key;
struct cache_node *result;
- if (!sias->rpkiNotify || !sias->caRepository)
+ if (!uri_str(&sias->rpkiNotify) || !uri_str(&sias->caRepository))
return NULL;
- init_rrdp_fallback_key(&key, sias->rpkiNotify, sias->caRepository);
+ init_rrdp_fallback_key(&key, &sias->rpkiNotify, &sias->caRepository);
result = find_node(&cache.fallback, key.id, key.idlen);
free(key.id);
struct cache_node *rsync;
rrdp = find_rrdp_fallback_node(sias);
- rsync = find_node(&cache.fallback, sias->caRepository,
- strlen(sias->caRepository));
+ rsync = find_node(&cache.fallback, uri_str(&sias->caRepository),
+ uri_len(&sias->caRepository));
if (rrdp == NULL)
return rsync;
/* Do not free nor modify the result. */
char *
-cache_refresh_by_url(char const *url)
+cache_refresh_by_url(struct uri const *url)
{
struct cache_node *node = NULL;
// XXX review result signs
- // XXX Normalize @url
- if (url_is_https(url))
+ if (uri_is_https(url))
do_refresh(&cache.https, url, &node);
- else if (url_is_rsync(url))
+ else if (uri_is_rsync(url))
do_refresh(&cache.rsync, url, &node);
return node ? node->path : NULL;
* Do not free nor modify the result.
*/
char *
-cache_get_fallback(char const *url)
+cache_get_fallback(struct uri const *url)
{
struct cache_node *node;
* Mutex not needed here.
*/
- pr_val_debug("Trying %s (offline)...", url);
+ pr_val_debug("Trying %s (offline)...", uri_str(url));
- node = find_node(&cache.fallback, url, strlen(url));
+ node = find_node(&cache.fallback, uri_str(url), uri_len(url));
if (!node) {
pr_val_debug("Cache data unavailable.");
return NULL;
{
struct cache_node *node;
struct cache_cage *cage;
- char const *rpkiNotify;
+ struct uri rpkiNotify;
// XXX Make sure somewhere validates rpkiManifest matches caRepository.
// XXX review result signs
- // XXX normalize rpkiNotify & caRepository?
/* Try RRDP + optional fallback */
- if (sias->rpkiNotify) {
- switch (do_refresh(&cache.rrdp, sias->rpkiNotify, &node)) {
+ if (uri_str(&sias->rpkiNotify) != NULL) {
+ switch (do_refresh(&cache.rrdp, &sias->rpkiNotify, &node)) {
case 0:
rpkiNotify = sias->rpkiNotify;
goto refresh_success;
}
/* Try rsync + optional fallback */
- switch (do_refresh(&cache.rsync, sias->caRepository, &node)) {
+ switch (do_refresh(&cache.rsync, &sias->caRepository, &node)) {
case 0:
- rpkiNotify = NULL;
+ memset(&rpkiNotify, 0, sizeof(rpkiNotify));
goto refresh_success;
case EBUSY:
return EBUSY;
}
static char const *
-node2file(struct cache_node const *node, char const *url)
+node2file(struct cache_node const *node, struct uri const *url)
{
if (node == NULL)
return NULL;
// XXX RRDP is const, rsync needs to be freed
return (node->rrdp)
? /* RRDP */ rrdp_file(node->rrdp, url)
- : /* rsync */ path_join(node->path, strip_rsync_module(url));
+ : /* rsync */ path_join(node->path, strip_rsync_module(uri_str(url)));
}
char const *
-cage_map_file(struct cache_cage *cage, char const *url)
+cage_map_file(struct cache_cage *cage, struct uri const *url)
{
/*
* Remember: In addition to honoring the consts of cache->refresh and
* not going to be modified nor deleted until the cache cleanup.
*/
void
-cache_commit_rpp(char const *rpkiNotify, char const *caRepository,
+cache_commit_rpp(struct uri const *rpkiNotify, struct uri const *caRepository,
struct rpp *rpp)
{
struct cache_commit *commit;
commit = pmalloc(sizeof(struct cache_commit));
- commit->rpkiNotify = rpkiNotify ? pstrdup(rpkiNotify) : NULL;
- commit->caRepository = pstrdup(caRepository);
+ uri_copy(&commit->rpkiNotify, rpkiNotify);
+ uri_copy(&commit->caRepository, caRepository);
commit->files = rpp->files;
commit->nfiles = rpp->nfiles;
INTEGER_move(&commit->mft.num, &rpp->mft.num);
{
struct cache_commit *commit;
- commit = pmalloc(sizeof(struct cache_commit));
- commit->rpkiNotify = NULL;
- commit->caRepository = NULL;
+ commit = pzalloc(sizeof(struct cache_commit));
+ memset(&commit->rpkiNotify, 0, sizeof(commit->rpkiNotify));
+ memset(&commit->caRepository, 0, sizeof(commit->caRepository));
commit->files = pmalloc(sizeof(*map));
- commit->files[0].url = pstrdup(map->url);
+ uri_copy(&commit->files[0].url, &map->url);
commit->files[0].path = pstrdup(map->path);
commit->nfiles = 1;
memset(&commit->mft, 0, sizeof(commit->mft));
}
void
-rsync_finished(char const *url, char const *path)
+rsync_finished(struct uri const *url, char const *path)
{
struct cache_node *node;
mutex_lock(&cache.rsync.lock);
- node = find_node(&cache.rsync, url, strlen(url));
+ node = find_node(&cache.rsync, uri_str(url), uri_len(url));
if (node == NULL) {
mutex_unlock(&cache.rsync.lock);
pr_op_err("rsync '%s -> %s' finished, but cache node does not exist.",
- url, path);
+ uri_str(url), path);
return;
}
if (node->state != DLS_ONGOING)
pr_op_warn("rsync '%s -> %s' finished, but existing node was not in ONGOING state.",
- url, path);
+ uri_str(url), path);
node->state = DLS_FRESH;
node->dlerr = 0;
task_wakeup_dormants();
}
-char const *
+struct uri const *
cage_rpkiNotify(struct cache_cage *cage)
{
- return cage->rpkiNotify;
+ return &cage->rpkiNotify;
}
static void
if (!node)
return;
- printf("\thttp:%s rsync:%s (%s): ", node->key.http, node->key.rsync,
- node->path);
+ printf("\thttp:%s rsync:%s (%s): ", uri_str(&node->key.http),
+ uri_str(&node->key.rsync), node->path);
switch (node->state) {
case DLS_OUTDATED:
printf("stale ");
* Note, this is accidentally working perfectly for rsync too.
* Might want to rename some of this.
*/
- dst = rrdp_create_fallback(fb->path, &fb->rrdp, src->url);
+ dst = rrdp_create_fallback(fb->path, &fb->rrdp, &src->url);
if (!dst)
goto skip;
commit = STAILQ_FIRST(&commits);
STAILQ_REMOVE_HEAD(&commits, lh);
- if (commit->caRepository) {
+ if (uri_str(&commit->caRepository) != NULL) {
pr_op_debug("Creating fallback for %s (%s)",
- commit->caRepository, commit->rpkiNotify);
+ uri_str(&commit->caRepository),
+ uri_str(&commit->rpkiNotify));
- fb = provide_node(&cache.fallback, commit->rpkiNotify,
- commit->caRepository);
+ fb = provide_node(&cache.fallback,
+ &commit->rpkiNotify,
+ &commit->caRepository);
fb->success_ts = now;
pr_op_debug("mkdir -f %s", fb->path);
} else { /* TA */
struct cache_mapping *map = &commit->files[0];
- pr_op_debug("Creating fallback for %s", map->url);
+ pr_op_debug("Creating fallback for %s",
+ uri_str(&map->url));
- fb = provide_node(&cache.fallback, map->url, NULL);
+ fb = provide_node(&cache.fallback, &map->url, NULL);
fb->success_ts = now;
if (is_fallback(map->path))
goto freshen;
write_metadata(fb);
freshen: fb->state = DLS_FRESH;
-skip: free(commit->rpkiNotify);
- free(commit->caRepository);
+skip: uri_cleanup(&commit->rpkiNotify);
+ uri_cleanup(&commit->caRepository);
for (i = 0; i < commit->nfiles; i++) {
- free(commit->files[i].url);
+ uri_cleanup(&commit->files[i].url);
free(commit->files[i].path);
}
free(commit->files);
void
sias_cleanup(struct sia_uris *sias)
{
- free(sias->caRepository);
- free(sias->rpkiNotify);
- free(sias->rpkiManifest);
- free(sias->crldp);
- free(sias->caIssuers);
- free(sias->signedObject);
+ uri_cleanup(&sias->caRepository);
+ uri_cleanup(&sias->rpkiNotify);
+ uri_cleanup(&sias->rpkiManifest);
+ uri_cleanup(&sias->crldp);
+ uri_cleanup(&sias->caIssuers);
+ uri_cleanup(&sias->signedObject);
}
#include <stdbool.h>
#include "types/map.h"
#include "types/rpp.h"
+#include "types/url.h"
int cache_setup(void); /* Init this module */
void cache_atexit(void);
/* XXX might wanna rename */
struct sia_uris {
- char *caRepository; /* RPP cage */
- char *rpkiNotify; /* RRDP Notification */
- char *rpkiManifest;
+ struct uri caRepository; /* RPP cage */
+ struct uri rpkiNotify; /* RRDP Notification */
+ struct uri rpkiManifest;
/**
* CRL Distribution Points's fullName. Non-TA certificates only.
* RFC 6487, section 4.8.6.
*/
- char *crldp;
+ struct uri crldp;
/**
* AIA's caIssuers. Non-TA certificates only.
* RFC 6487, section 4.8.7.
*/
- char *caIssuers;
+ struct uri caIssuers;
/**
* SIA's signedObject. EE certificates only.
* RFC 6487, section 4.8.8.2.
*/
- char *signedObject;
+ struct uri signedObject;
};
void sias_init(struct sia_uris *);
void sias_cleanup(struct sia_uris *);
-char *cache_refresh_by_url(char const *);
-char *cache_get_fallback(char const *);
+char *cache_refresh_by_url(struct uri const *);
+char *cache_get_fallback(struct uri const *);
struct cache_cage;
int cache_refresh_by_sias(struct sia_uris *, struct cache_cage **);
-char const *cage_map_file(struct cache_cage *, char const *);
+char const *cage_map_file(struct cache_cage *, struct uri const *);
bool cage_disable_refresh(struct cache_cage *);
struct mft_meta const *cage_mft_fallback(struct cache_cage *);
-void cache_commit_rpp(char const *, char const *, struct rpp *);
+void cache_commit_rpp(struct uri const *, struct uri const *, struct rpp *);
void cache_commit_file(struct cache_mapping *);
-char const *cage_rpkiNotify(struct cache_cage *);
+struct uri const *cage_rpkiNotify(struct cache_cage *);
void cache_print(void); /* Dump cache in stdout */
#include "log.h"
int
-validate_cdp(struct sia_uris *sias, char const *crl_url)
+validate_cdp(struct sia_uris const *sias, struct uri const *crl_url)
{
- if (sias->crldp == NULL)
+ if (uri_str(&sias->crldp) == NULL)
pr_crit("Certificate's CRL Distribution Point was not recorded.");
-
- if (crl_url == NULL)
+ if (uri_str(crl_url) == NULL)
pr_crit("Manifest's CRL was not recorded.");
- if (strcmp(sias->crldp, crl_url) != 0) {
+ if (uri_equals(&sias->crldp, crl_url) != 0) {
return pr_val_err("Certificate's CRL Distribution Point ('%s') does not match manifest's CRL ('%s').",
- sias->crldp, crl_url);
+ uri_str(&sias->crldp), uri_str(crl_url));
}
return 0;
}
static int
-validate_signedObject(struct sia_uris *sias, char const *url)
+validate_signedObject(struct sia_uris const *sias, struct uri const *url)
{
- if (sias->signedObject == NULL)
+ if (uri_str(&sias->signedObject) == NULL)
pr_crit("Certificate's signedObject was not recorded.");
- /* XXX the left one is no longer normalized */
- if (strcmp(sias->signedObject, url) != 0) {
+ if (!uri_equals(&sias->signedObject, url))
return pr_val_err("Certificate's signedObject ('%s') does not match the URI of its own signed object (%s).",
- sias->signedObject, url);
- }
+ uri_str(&sias->signedObject), uri_str(url));
return 0;
}
* @url: URL of the signed object that contains the EE certificate.
*/
int
-refs_validate_ee(struct sia_uris *sias, char const *crl_url, char const *url)
+refs_validate_ee(struct sia_uris const *sias, struct uri const *crl_url,
+ struct uri const *url)
{
int error;
#include "cache.h"
-int validate_cdp(struct sia_uris *, char const *);
-int refs_validate_ee(struct sia_uris *, char const *, char const *);
+int validate_cdp(struct sia_uris const *, struct uri const *);
+int refs_validate_ee(struct sia_uris const *, struct uri const *,
+ struct uri const *);
#endif /* SRC_CERTIFICATE_REFS_H_ */
#include <sys/stat.h>
#include <sys/types.h>
-/* "I think this is not supposed to be implemented." */
-#define ENOTSUPPORTED 3172
/* "I haven't implemented this yet." */
#define ENOTIMPLEMENTED 3173
#include <getopt.h>
+#include "alloc.h"
#include "config/str.h"
#include "log.h"
#include "types/path.h"
static int
get_http_response_code(struct http_handler *handler, long *http_code,
- char const *uri)
+ struct uri const *uri)
{
CURLcode res;
if (res != CURLE_OK) {
return pr_op_err_st("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned %d (%s). "
"I think this is supposed to be illegal, so I'll have to drop URI '%s'.",
- res, curl_err_string(handler, res), uri);
+ res, curl_err_string(handler, res), uri_str(uri));
}
return 0;
return -EINVAL; /* Do not retry */
}
+static int
+check_same_origin(struct uri const *src, char const *redirect)
+{
+ struct uri redirect_url;
+ int error;
+
+ error = uri_init(&redirect_url, redirect);
+ if (error)
+ return error;
+
+ if (!uri_same_origin(src, &redirect_url))
+ error = pr_val_err("%s is redirecting to %s; disallowing because of different origin.",
+ uri_str(src), uri_str(&redirect_url));
+
+ uri_cleanup(&redirect_url);
+ return error;
+}
+
/*
* Download @src into @dst; HTTP assumed.
*
* If @changed is not NULL, initialize it to false.
*/
int
-http_download(char const *src, char const *dst, curl_off_t ims, bool *changed)
+http_download(struct uri const *src, char const *dst,
+ curl_off_t ims, bool *changed)
{
struct http_handler handler;
struct write_callback_arg args;
unsigned int r;
int error;
- pr_val_info("HTTP GET: %s -> %s", src, dst);
+ pr_val_info("HTTP GET: %s -> %s", uri_str(src), dst);
error = http_easy_init(&handler, ims);
if (error)
do {
handler.errbuf[0] = 0;
- setopt_str(handler.curl, CURLOPT_URL, (redirect != NULL) ? redirect : src);
+ setopt_str(handler.curl, CURLOPT_URL,
+ (redirect != NULL) ? redirect : uri_str(src));
args.total_bytes = 0;
args.error = 0;
res = curl_easy_perform(handler.curl); /* write_callback() */
if (args.file != NULL)
file_close(args.file);
- pr_val_debug("Done. Total bytes transferred: %zu", args.total_bytes);
+ pr_val_debug("Done. Total bytes transferred: %zu",
+ args.total_bytes);
args.error = validate_file_size(&args);
if (args.error) {
redirect = NULL;
}
- res = curl_easy_getinfo(handler.curl, CURLINFO_REDIRECT_URL, &redirect);
+ res = curl_easy_getinfo(handler.curl, CURLINFO_REDIRECT_URL,
+ &redirect);
if (res != CURLE_OK) {
error = pr_op_err("curl_easy_getinfo(CURLINFO_REDIRECT_URL) returned %u.", res);
redirect = NULL;
if (redirect == NULL)
break;
- if (!url_same_origin(src, redirect)) {
- error = pr_val_err("%s is redirecting to %s; disallowing because of different origin.",
- src, redirect);
- redirect = NULL;
- goto end;
- }
-
r++;
if (r > config_get_max_redirs()) {
error = pr_val_err("Too many redirects.");
redirect = NULL;
goto end;
}
+ error = check_same_origin(src, redirect);
+ if (error)
+ goto end;
/* The original redirect is destroyed during the next curl_easy_perform(). */
redirect = pstrdup(redirect);
#include <curl/curl.h>
#include <stdbool.h>
+#include "types/url.h"
+
int http_init(void);
void http_cleanup(void);
-int http_download(char const *, char const *, curl_off_t, bool *);
+int http_download(struct uri const *, char const *, curl_off_t, bool *);
#endif /* SRC_HTTP_H_ */
static int
fetch_url(char const *url, char const *filename)
{
+ struct uri uri;
char *path;
int error;
+ error = uri_init(&uri, url);
+ if (error)
+ return error;
+
path = path_join(config_get_tal(), filename);
- error = http_download(url, path, 0, NULL);
+ error = http_download(&uri, path, 0, NULL);
if (error) {
fprintf(stderr, "Couldn't fetch '%s': %s\n",
path, strerror(abs(error)));
fprintf(stdout, "Successfully fetched '%s'!\n\n", path);
end: free(path);
+ uri_cleanup(&uri);
return error;
}
return 0;
}
+/* Result needs to be cleant up. */
+int
+json_get_uri(json_t *parent, char const *name, struct uri *result)
+{
+ char const *str;
+ int error;
+
+ memset(result, 0, sizeof(*result));
+
+ error = json_get_str(parent, name, &str);
+ if (error)
+ return error;
+ error = uri_init(result, str);
+ if (error) {
+ pr_op_err("Malformed URL: %s", str);
+ return -error;
+ }
+
+ return 0;
+}
+
static int
json_get_int_t(json_t *parent, char const *name, json_int_t *result)
{
#include "asn1/asn1c/INTEGER.h"
#include "file.h"
+#include "types/url.h"
/*
* Contract of get functions:
int json_get_bigint(json_t *, char const *, INTEGER_t *);
int json_get_ts(json_t *, char const *, time_t *);
int json_get_str(json_t *, char const *, char const **);
+int json_get_uri(json_t *, char const *, struct uri *);
int json_get_array(json_t *, char const *, json_t **);
int json_get_object(json_t *, char const *, json_t **);
pr_crit("Unknown policy: %u", cert->policy);
}
-static bool
-is_rsync(ASN1_IA5STRING *uri)
-{
- static char const *const PREFIX = "rsync://";
- size_t prefix_len = strlen(PREFIX);
-
- return (uri->length >= prefix_len)
- ? (strncmp((char *) uri->data, PREFIX, strlen(PREFIX)) == 0)
- : false;
-}
-
-static void
-handle_rpkiManifest(char *uri, void *arg)
+static int
+handle_rpkiManifest(struct uri const *uri, void *arg)
{
struct sia_uris *uris = arg;
+ char const *rm;
- pr_clutter("rpkiManifest: %s", uri);
+ rm = uri_str(uri);
+ pr_clutter("rpkiManifest: %s", rm);
- if (uris->rpkiManifest != NULL) {
- pr_val_warn("Ignoring additional rpkiManifest: %s", uri);
- free(uri);
- } else {
- uris->rpkiManifest = uri;
+ if (!uri_is_rsync(uri)) {
+ pr_val_debug("Ignoring non-rsync rpkiManifest '%s'.", rm);
+ return ENOTSUP;
+ }
+
+ if (uri_str(&uris->rpkiManifest) != NULL) {
+ pr_val_warn("Ignoring additional rpkiManifest: %s", rm);
+ return 0;
}
+
+ uri_copy(&uris->rpkiManifest, uri);
+ return 0;
}
-static void
-handle_caRepository(char *uri, void *arg)
+static int
+handle_caRepository(struct uri const *uri, void *arg)
{
struct sia_uris *uris = arg;
+ char const *cr;
- pr_clutter("caRepository: %s", uri);
+ cr = uri_str(uri);
+ pr_clutter("caRepository: %s", caRepo);
- if (uris->caRepository != NULL) {
- pr_val_warn("Ignoring additional caRepository: %s", uri);
- free(uri);
- } else {
- uris->caRepository = uri;
+ if (!uri_is_rsync(uri)) {
+ pr_val_debug("Ignoring non-rsync caRepository '%s'.", cr);
+ return ENOTSUP;
}
+
+ if (uri_str(&uris->caRepository) != NULL) {
+ pr_val_warn("Ignoring additional caRepository: %s", cr);
+ return 0;
+ }
+
+ uri_copy(&uris->caRepository, uri);
+ return 0;
}
-static void
-handle_rpkiNotify(char *uri, void *arg)
+static int
+handle_rpkiNotify(struct uri const *uri, void *arg)
{
struct sia_uris *uris = arg;
+ char const *rn;
- pr_clutter("rpkiNotify: %s", uri);
+ rn = uri_str(uri);
+ pr_clutter("rpkiNotify: %s", rn);
- if (uris->rpkiNotify != NULL) {
- pr_val_warn("Ignoring additional rpkiNotify: %s", uri);
- free(uri);
- } else {
- uris->rpkiNotify = uri;
+ if (!uri_is_https(uri)) {
+ pr_val_debug("Ignoring non-https rpkiNotify '%s'.", rn);
+ return ENOTSUP;
}
+
+ if (uri_str(&uris->rpkiNotify) != NULL) {
+ pr_val_warn("Ignoring additional rpkiNotify: %s", rn);
+ return 0;
+ }
+
+ uri_copy(&uris->rpkiNotify, uri);
+ return 0;
}
-static void
-handle_signedObject(char *uri, void *arg)
+static int
+handle_signedObject(struct uri const *uri, void *arg)
{
struct sia_uris *sias = arg;
- pr_clutter("signedObject: %s", uri);
- sias->signedObject = uri;
+ char const *so;
+
+ so = uri_str(uri);
+ pr_clutter("signedObject: %s", so);
+
+ if (!uri_is_rsync(uri)) {
+ pr_val_debug("Ignoring non-rsync signedObject '%s'.", so);
+ return ENOTSUP;
+ }
+
+ if (uri_str(&sias->signedObject) != NULL) {
+ pr_val_warn("Ignoring additional signedObject: %s", so);
+ return 0;
+ }
+
+ uri_copy(&sias->signedObject, uri);
+ return 0;
}
static int
return handle_ku(ext, 0x80);
}
+static int
+gn2uri(GENERAL_NAME *ad, struct uri *uri)
+{
+ ASN1_STRING *asn1str;
+ int ptype;
+ char *str;
+ int error;
+
+ asn1str = GENERAL_NAME_get0_value(ad, &ptype);
+ if (ptype != GEN_URI) {
+ pr_val_debug("Ignoring unknown GENERAL_NAME type: %d", ptype);
+ return ENOTSUP;
+ }
+
+ /*
+ * TODO (testers) According to RFC 5280, accessLocation can be an IRI
+ * somehow converted into URI form. I don't think that's an issue
+ * because the RSYNC clone operation should not have performed the
+ * conversion, so we should be looking at precisely the IA5String
+ * directory our g2l version of @asn1_string should contain.
+ * But ask the testers to keep an eye on it anyway.
+ */
+ error = ia5s2string(asn1str, &str);
+ if (error)
+ return error;
+ error = uri_init(uri, str);
+ free(str);
+
+ return error;
+}
+
static int
handle_cdp(void *ext, void *arg)
{
struct sia_uris *sias = arg;
DIST_POINT *dp;
GENERAL_NAMES *names;
- GENERAL_NAME *name;
- ASN1_IA5STRING *str;
int i;
- int type;
char const *error_msg;
if (sk_DIST_POINT_num(crldp) != 1) {
names = dp->distpoint->name.fullname;
for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
- name = sk_GENERAL_NAME_value(names, i);
- str = GENERAL_NAME_get0_value(name, &type);
- if (type == GEN_URI && is_rsync(str)) {
- /*
- * Since we're parsing and validating the manifest's CRL
- * at some point, I think that all we need to do now is
- * compare this CRL URI to that one's.
- *
- * But there is a problem:
- * The manifest's CRL might not have been parsed at this
- * point. In fact, it's guaranteed to not have been
- * parsed if the certificate we're validating is the EE
- * certificate of the manifest itself.
- *
- * So we will store the URI in @refs, and validate it
- * later.
- */
- return ia5s2string(str, &sias->crldp);
+ /*
+ * Since we're parsing and validating the manifest's CRL at some
+ * point, I think that all we need to do now is compare this CRL
+ * URI to that one's.
+ *
+ * But there is a problem: The manifest's CRL might not have
+ * been parsed at this point. In fact, it's guaranteed to not
+ * have been parsed if the certificate we're validating is the
+ * EE certificate of the manifest itself.
+ *
+ * So we will store the URI in @sias, and validate it later.
+ */
+ if (gn2uri(sk_GENERAL_NAME_value(names, i), &sias->crldp) != 0)
+ continue;
+ if (!uri_is_rsync(&sias->crldp)) {
+ uri_cleanup(&sias->crldp);
+ continue;
}
+ return 0;
}
error_msg = "lacks an RSYNC URI";
ext_cdp()->name, error_msg);
}
-/*
- * Create @map from the @ad
- */
-static int
-ad2uri(char **uri, ACCESS_DESCRIPTION *ad)
-{
- ASN1_STRING *asn1str;
- int ptype;
-
- asn1str = GENERAL_NAME_get0_value(ad->location, &ptype);
-
- /*
- * RFC 6487: "This extension MUST have an instance of an
- * AccessDescription with an accessMethod of id-ad-rpkiManifest, (...)
- * with an rsync URI [RFC5781] form of accessLocation."
- *
- * Ehhhhhh. It's a little annoying in that it seems to be stucking more
- * than one requirement in a single sentence, which I think is rather
- * rare for an RFC. Normally they tend to hammer things more.
- *
- * Does it imply that the GeneralName CHOICE is constrained to type
- * "uniformResourceIdentifier"? I guess so, though I don't see anything
- * stopping a few of the other types from also being capable of storing
- * URIs.
- *
- * Also, nobody seems to be using the other types, and handling them
- * would be a titanic pain. So this is what I'm committing to.
- */
- if (ptype != GEN_URI) {
- pr_val_err("Unknown GENERAL_NAME type: %d", ptype);
- return ENOTSUPPORTED;
- }
-
- /*
- * GEN_URI signals an IA5String.
- * IA5String is a subset of ASCII, so this cast is safe.
- * 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
- * because the RSYNC clone operation should not have performed the
- * conversion, so we should be looking at precisely the IA5String
- * directory our g2l version of @asn1_string should contain.
- * But ask the testers to keep an eye on it anyway.
- *
- * XXX There used to be a map_create() here. Make sure validations are
- * restored somewhere:
- * 1. ascii
- * 2. "rsync://" or "https://" prefix (ENOTRSYNC, ENOTHTTPS)
- * 3. URL normalization
- */
- *uri = pstrndup((char const *)ASN1_STRING_get0_data(asn1str),
- ASN1_STRING_length(asn1str));
- return 0;
-}
-
/*
* The RFC does not explain AD validation very well. This is personal
* interpretation, influenced by Tim Bruijnzeels's response
* (I'm being a bit more lax than he suggested.)
*
* 1. The NID (@nid) can be found more than once.
- * 2. All access descriptions that match the NID must be URLs.
* 3. Depending on meta->required, zero or one of those matches will be an URL
* of the meta->type we're expecting.
* (I would have gone with "at least zero of those matches", but I don't know
*/
static int
handle_ad(int nid, struct ad_metadata const *meta, SIGNATURE_INFO_ACCESS *ia,
- void (*cb)(char *, void *), void *arg)
+ int (*cb)(struct uri const *, void *), void *arg)
{
ACCESS_DESCRIPTION *ad;
- char *uri;
+ struct uri uri;
bool found;
unsigned int i;
int 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 = ad2uri(&uri, ad);
- switch (error) {
- case 0:
- break;
- case ENOTSUPPORTED:
+ if (gn2uri(ad->location, &uri) != 0)
continue;
- default:
- return error;
- }
if (found) {
- free(uri);
+ uri_cleanup(&uri);
return pr_val_err("Extension '%s' has multiple '%s' %s URIs.",
meta->ia_name, meta->name, meta->type);
}
- cb(uri, arg); /* Ownership of uri stolen */
+ error = cb(&uri, arg);
+ uri_cleanup(&uri);
+ if (error == ENOTSUP)
+ continue;
+ if (error)
+ return error;
+
found = true;
}
}
return 0;
}
-static void
-handle_caIssuers(char *uri, void *arg)
+static int
+handle_caIssuers(struct uri const *uri, void *arg)
{
struct sia_uris *sias = arg;
+
+ if (!uri_is_rsync(uri)) {
+ pr_val_debug("Ignoring non-rsync caIssuers '%s'.", uri_str(uri));
+ return ENOTSUP;
+ }
+
/*
* Bringing the parent certificate's URI all the way
* over here is too much trouble, so do the handle_cdp()
* hack.
- *
- * XXX Uh... it's extremely easy now.
*/
- sias->caIssuers = uri;
+ uri_copy(&sias->caIssuers, uri);
+ return 0;
}
static int
error = certificate_validate_aia(cert);
if (error)
return error;
- return validate_cdp(&cert->sias, cert->parent->rpp.crl.map->url);
+ return validate_cdp(&cert->sias, &cert->parent->rpp.crl.map->url);
}
int
int
certificate_validate_aia(struct rpki_certificate *cert)
{
- /*
- * FIXME Compare the AIA to the parent's URI.
- * We're currently not recording the URI, so this can't be solved until
- * the #78 refactor.
- */
+ if (!uri_equals(&cert->parent->map.url, &cert->sias.caIssuers))
+ return pr_val_err("Certificate's caIssuers (%s) does not match parent certificate's URL (%s).",
+ uri_str(&cert->parent->map.url),
+ uri_str(&cert->sias.caIssuers));
+
return 0;
}
certificate_traverse(struct rpki_certificate *ca)
{
struct cache_cage *cage;
- char const *mft_path;
+ struct cache_mapping mft;
array_index i;
struct cache_mapping *map;
- char const *ext;
unsigned int queued;
int error;
default:
return pr_val_err("caRepository '%s' could not be refreshed, "
"and there is no fallback in the cache. "
- "I'm going to have to skip it.", ca->sias.caRepository);
+ "I'm going to have to skip it.",
+ uri_str(&ca->sias.caRepository));
}
-retry: mft_path = cage_map_file(cage, ca->sias.rpkiManifest);
- if (!mft_path) {
+ mft.url = ca->sias.rpkiManifest;
+retry: mft.path = (char *)cage_map_file(cage, &mft.url); /* Will not edit */
+ if (!mft.path) {
if (cage_disable_refresh(cage))
goto retry;
error = pr_val_err("caRepository '%s' is missing a manifest.",
- ca->sias.caRepository);
+ uri_str(&ca->sias.caRepository));
goto end;
}
- error = manifest_traverse(ca->sias.rpkiManifest, mft_path, cage, ca);
+ error = manifest_traverse(&mft, cage, ca);
if (error) {
if (cage_disable_refresh(cage))
goto retry;
queued = 0;
for (i = 0; i < ca->rpp.nfiles; i++) {
map = ca->rpp.files + i;
- ext = map->url + strlen(map->url) - 4;
- if (strcmp(ext, ".cer") == 0)
+ if (uri_has_extension(&map->url, ".cer"))
queued += task_enqueue_rpp(map, ca);
- else if (strcmp(ext, ".roa") == 0)
+ else if (uri_has_extension(&map->url, ".roa"))
roa_traverse(map, ca);
- else if (strcmp(ext, ".gbr") == 0)
+ else if (uri_has_extension(&map->url, ".gbr"))
ghostbusters_traverse(map, ca);
}
if (queued > 0)
task_wakeup();
- cache_commit_rpp(cage_rpkiNotify(cage), ca->sias.caRepository, &ca->rpp);
+ cache_commit_rpp(cage_rpkiNotify(cage), &ca->sias.caRepository,
+ &ca->rpp);
end: free(cage);
return error;
error = handle_vcard(&sobj);
if (error)
goto end3;
- error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, map->url);
+ error = refs_validate_ee(&ee.sias, &parent->rpp.crl.map->url, &map->url);
end3: rpki_certificate_cleanup(&ee);
signed_object_cleanup(&sobj);
*/
static int
-collect_files(char const *mft_url, char const *mft_path,
+collect_files(struct cache_mapping const *map,
struct Manifest *mft, struct cache_cage *cage,
struct rpki_certificate *parent)
{
struct rpp *rpp;
- char *rpp_url;
+ struct uri rpp_url;
unsigned int m;
struct FileAndHash *src;
struct cache_mapping *dst;
return pr_val_err("Manifest's file list is empty.");
rpp = &parent->rpp;
- rpp_url = url_parent(mft_url); // XXX
+ error = uri_parent(&map->url, &rpp_url);
+ if (error)
+ return error;
rpp->files = pzalloc((mft->fileList.list.count + 1) * sizeof(*rpp->files));
rpp->nfiles = 0;
continue;
dst = &rpp->files[rpp->nfiles++];
- dst->url = path_njoin(rpp_url,
- (char const *)src->file.buf,
- src->file.size);
+ uri_child(&rpp_url, (char const *)src->file.buf, src->file.size,
+ &dst->url);
- path = cage_map_file(cage, dst->url);
+ path = cage_map_file(cage, &dst->url);
if (!path) {
error = pr_val_err(
"Manifest file '%s' is absent from the cache.",
- dst->url);
+ uri_str(&dst->url));
goto revert;
}
dst->path = pstrdup(path);
/* Manifest */
dst = &rpp->files[rpp->nfiles++];
- dst->url = pstrdup(mft_url);
- dst->path = pstrdup(mft_path);
+ uri_copy(&dst->url, &map->url);
+ dst->path = pstrdup(map->path);
return 0;
revert: rpp_cleanup(rpp);
- free(rpp_url);
return error;
}
rpp = &parent->rpp;
for (f = 0; f < rpp->nfiles; f++)
- if (str_ends_with(rpp->files[f].url, ".crl")) {
+ if (uri_has_extension(&rpp->files[f].url, ".crl")) {
if (rpp->crl.map != NULL)
return pr_val_err("Manifest has more than one CRL.");
rpp->crl.map = &rpp->files[f];
}
static int
-build_rpp(char const *mft_url, char const *mft_path, struct Manifest *mft,
+build_rpp(struct cache_mapping const *map, struct Manifest *mft,
struct cache_cage *cage, struct rpki_certificate *parent)
{
int error;
- error = collect_files(mft_url, mft_path, mft, cage, parent);
+ error = collect_files(map, mft, cage, parent);
if (error)
return error;
}
int
-manifest_traverse(char const *mft_url, char const *mft_path,
- struct cache_cage *cage, struct rpki_certificate *parent)
+manifest_traverse(struct cache_mapping const *map, struct cache_cage *cage,
+ struct rpki_certificate *parent)
{
static OID oid = OID_MANIFEST;
struct oid_arcs arcs = OID2ARCS("manifest", oid);
int error;
/* Prepare */
- fnstack_push(mft_url);
+ fnstack_push_map(map);
/* Decode */
- error = signed_object_decode(&sobj, mft_path);
+ error = signed_object_decode(&sobj, map->path);
if (error)
goto end1;
error = decode_manifest(&sobj, &mft);
goto end2;
/* Initialize @summary */
- error = build_rpp(mft_url, mft_path, mft, cage, parent);
+ error = build_rpp(map, mft, cage, parent);
if (error)
goto end3;
error = validate_manifest(mft, cage, &parent->rpp.mft);
if (error)
goto end5;
- error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, mft_url);
+ error = refs_validate_ee(&ee.sias, &parent->rpp.crl.map->url, &map->url);
end5: rpki_certificate_cleanup(&ee);
if (error)
#include "cache.h"
#include "object/certificate.h"
-int manifest_traverse(char const *, char const *, struct cache_cage *,
+int manifest_traverse(struct cache_mapping const *, struct cache_cage *,
struct rpki_certificate *);
#endif /* SRC_OBJECT_MANIFEST_H_ */
error = __handle_roa(roa, ee.resources);
if (error)
goto end4;
- error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, map->url);
+ error = refs_validate_ee(&ee.sias, &parent->rpp.crl.map->url, &map->url);
end4: rpki_certificate_cleanup(&ee);
ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
struct tal {
char const *file_name;
- struct strlist urls;
+ struct uris urls;
unsigned char *spki; /* Decoded; not base64. */
size_t spki_len;
};
{
char *nl; /* New Line */
bool cr; /* Carriage return */
+ struct uri url;
/* Comment section */
while (fc[0] == '#') {
if (is_blank(fc))
break;
- if (url_is_https(fc) || url_is_rsync(fc))
- strlist_add(&tal->urls, pstrdup(fc));
+ if (uri_init(&url, fc) == 0) {
+ if (uri_is_https(&url) || uri_is_rsync(&url))
+ uris_add(&tal->urls, &url);
+ else
+ uri_cleanup(&url);
+ } else {
+ pr_op_debug("Cannot parse '%s' as a URI; ignoring.", fc);
+ }
fc = nl + cr + 1;
if (*fc == '\0')
tal->file_name = path_filename(file_path);
- strlist_init(&tal->urls);
+ uris_init(&tal->urls);
error = read_content((char *)file.buffer, tal);
if (error)
- strlist_cleanup(&tal->urls);
+ uris_cleanup(&tal->urls, uri_cleanup);
file_free(&file);
return error;
tal_cleanup(struct tal *tal)
{
free(tal->spki);
- strlist_cleanup(&tal->urls);
+ uris_cleanup(&tal->urls, uri_cleanup);
}
char const *
}
static int
-try_urls(struct tal *tal, bool (*url_is_protocol)(char const *),
- char *(*get_path)(char const *))
+try_urls(struct tal *tal, bool (*url_is_protocol)(struct uri const *),
+ char *(*get_path)(struct uri const *))
{
- char **url;
+ struct uri *url;
struct cache_mapping map;
int error;
ARRAYLIST_FOREACH(&tal->urls, url) {
map.url = *url;
- if (!url_is_protocol(map.url))
+ if (!url_is_protocol(&map.url))
continue;
- map.path = get_path(*url);
+ map.path = get_path(url);
if (!map.path)
continue;
error = validate_ta(tal, &map);
goto end1;
/* Online attempts */
- error = try_urls(&tal, url_is_https, cache_refresh_by_url);
+ error = try_urls(&tal, uri_is_https, cache_refresh_by_url);
if (!error || error == EBUSY)
goto end2;
- error = try_urls(&tal, url_is_rsync, cache_refresh_by_url);
+ error = try_urls(&tal, uri_is_rsync, cache_refresh_by_url);
if (!error || error == EBUSY)
goto end2;
/* Offline fallback attempts */
- error = try_urls(&tal, url_is_https, cache_get_fallback);
+ error = try_urls(&tal, uri_is_https, cache_get_fallback);
if (!error || error == EBUSY)
goto end2;
- error = try_urls(&tal, url_is_rsync, cache_get_fallback);
+ error = try_urls(&tal, uri_is_rsync, cache_get_fallback);
if (!error || error == EBUSY)
goto end2;
static BIO *
__rsync2bio(char const *src, char const *dst)
{
+ struct uri url;
int error;
+ if (uri_init(&url, src) != 0)
+ return NULL;
+
// XXX use the cache
- error = rsync_queue(src, dst);
+ error = rsync_queue(&url, dst);
+
+ uri_cleanup(&url);
+
if (error) {
pr_op_err("rsync download failed: %s", strerror(abs(error)));
return NULL;
if (filename == NULL || strcmp(filename, "-") == 0)
return BIO_new_fp(stdin, BIO_NOCLOSE);
- if (url_is_rsync(filename))
+ if (str_starts_with(filename, "rsync://"))
return rsync2bio(filename);
return BIO_new_file(filename, "rb");
};
struct file_metadata {
- char *uri;
+ struct uri uri;
unsigned char *hash; /* Array. Sometimes omitted. */
size_t hash_len;
};
struct rrdp_session session;
struct file_metadata snapshot;
struct notification_deltas deltas;
- char const *url;
+ struct uri const *url;
};
/* A deserialized <publish> tag, from a snapshot or delta. */
}
static struct cache_file *
-state_find_file(struct rrdp_state const *state, char const *url, size_t len)
+state_find_file(struct rrdp_state const *state, struct uri const *url)
{
+ char const *str;
+ size_t len;
struct cache_file *file;
- HASH_FIND(hh, state->files, url, len, file);
+
+ str = uri_str(url);
+ len = uri_len(url);
+
+ HASH_FIND(hh, state->files, str, len, file);
+
return file;
}
+static void
+state_add_file(struct rrdp_state *state, struct cache_file *file)
+{
+ char const *url;
+ size_t urlen;
+
+ url = uri_str(&file->map.url);
+ urlen = uri_len(&file->map.url);
+
+ HASH_ADD_KEYPTR(hh, state->files, url, urlen, file);
+}
+
static struct cache_file *
-cache_file_add(struct rrdp_state *state, char *url, char *path)
+cache_file_add(struct rrdp_state *state, struct uri const *url, char *path)
{
struct cache_file *file;
- size_t urlen;
file = pzalloc(sizeof(struct cache_file));
- file->map.url = url;
+ uri_copy(&file->map.url, url);
file->map.path = path;
- urlen = strlen(url);
- HASH_ADD_KEYPTR(hh, state->files, file->map.url, urlen, file);
+
+ state_add_file(state, file);
return file;
}
static void
metadata_cleanup(struct file_metadata *meta)
{
- free(meta->uri);
+ uri_cleanup(&meta->uri);
free(meta->hash);
}
}
static void
-update_notification_init(struct update_notification *notif, char const *url)
+update_notification_init(struct update_notification *notif,
+ struct uri const *url)
{
memset(¬if->session, 0, sizeof(notif->session));
memset(¬if->snapshot, 0, sizeof(notif->snapshot));
return result;
}
-static char *
-parse_uri(xmlTextReaderPtr reader)
-{
- xmlChar *xmlattr;
- char *result;
-
- xmlattr = parse_string(reader, RRDP_ATTR_URI);
- if (xmlattr == NULL)
- return NULL;
-
- result = pstrdup((char const *)xmlattr);
-
- xmlFree(xmlattr);
- return result;
-}
-
static unsigned int
hexchar2uint(xmlChar xmlchar)
{
static int
parse_file_metadata(xmlTextReaderPtr reader, struct file_metadata *meta)
{
+ xmlChar *xmlattr;
int error;
memset(meta, 0, sizeof(*meta));
- meta->uri = parse_uri(reader);
- if (meta->uri == NULL)
+ xmlattr = parse_string(reader, RRDP_ATTR_URI);
+ if (xmlattr == NULL)
+ return -EINVAL;
+ error = uri_init(&meta->uri, (char const *)xmlattr);
+ xmlFree(xmlattr);
+ if (error)
return -EINVAL;
error = parse_hash(reader, &meta->hash, &meta->hash_len);
if (error) {
- free(meta->uri);
- meta->uri = NULL;
+ uri_cleanup(&meta->uri);
return error;
}
}
static bool
-is_known_extension(char const *uri)
+is_known_extension(struct uri const *uri)
{
size_t len;
char const *ext;
- len = strlen(uri);
+ len = uri_len(uri);
if (len < 4)
return false;
- ext = uri + len - 4;
+ ext = uri_str(uri) + len - 4;
return ((strcmp(ext, ".cer") == 0)
|| (strcmp(ext, ".roa") == 0)
|| (strcmp(ext, ".mft") == 0)
if (xmlTextReaderRead(reader) != 1) {
error = pr_val_err(
"Couldn't read publish content of element '%s'",
- tag.meta.uri
+ uri_str(&tag.meta.uri)
);
goto end;
}
- if (!is_known_extension(tag.meta.uri))
+ if (!is_known_extension(&tag.meta.uri))
goto end; /* Mirror rsync filters */
/* Parse tag content */
pr_clutter("Publish %s", logv_filename(tag.meta.uri));
- file = state_find_file(args->state, tag.meta.uri, strlen(tag.meta.uri));
+ file = state_find_file(args->state, &tag.meta.uri);
/* rfc8181#section-2.2 */
if (file) {
error = pr_val_err("RRDP desync: "
"<publish> is attempting to create '%s', "
"but the file is already cached.",
- tag.meta.uri);
+ uri_str(&tag.meta.uri));
goto end;
}
error = pr_val_err("RRDP desync: "
"<publish> is attempting to overwrite '%s', "
"but the file is absent in the cache.",
- tag.meta.uri);
+ uri_str(&tag.meta.uri));
goto end;
}
error = -EINVAL;
goto end;
}
- file = cache_file_add(args->state, pstrdup(tag.meta.uri), path);
+ file = cache_file_add(args->state, &tag.meta.uri, path);
}
error = file_write_bin(file->map.path, tag.content, tag.content_len);
{
struct withdraw tag = { 0 };
struct cache_file *file;
- size_t len;
int error;
error = parse_file_metadata(reader, &tag.meta);
if (error)
- goto end;
- if (!is_known_extension(tag.meta.uri))
+ return error;
+ if (!is_known_extension(&tag.meta.uri))
goto end; /* Mirror rsync filters */
if (!tag.meta.hash) {
error = pr_val_err("Withdraw '%s' is missing a hash.",
- tag.meta.uri);
+ uri_str(&tag.meta.uri));
goto end;
}
pr_clutter("Withdraw %s", logv_filename(tag.meta.uri));
- len = strlen(tag.meta.uri);
- file = state_find_file(args->state, tag.meta.uri, len);
+ file = state_find_file(args->state, &tag.meta.uri);
if (!file) {
error = pr_val_err("Broken RRDP: "
"<withdraw> is attempting to delete unknown file '%s'.",
- tag.meta.uri);
+ uri_str(&tag.meta.uri));
goto end;
}
if (!notif->snapshot.hash)
return pr_val_err("Snapshot '%s' is missing a hash.",
- notif->snapshot.uri);
+ uri_str(¬if->snapshot.uri));
- if (!url_same_origin(notif->url, notif->snapshot.uri))
+ if (!uri_same_origin(notif->url, ¬if->snapshot.uri))
return pr_val_err("Notification '%s' and Snapshot '%s' are not hosted by the same origin.",
- notif->url, notif->snapshot.uri);
+ uri_str(notif->url), uri_str(¬if->snapshot.uri));
return 0;
}
error = parse_file_metadata(reader, &delta.meta);
if (error)
- goto fail;
+ goto srl;
if (!delta.meta.hash) {
error = pr_val_err("Delta '%s' is missing a hash.",
- delta.meta.uri);
- goto fail;
+ uri_str(&delta.meta.uri));
+ goto mta;
}
- if (!url_same_origin(notif->url, delta.meta.uri)) {
+ if (!uri_same_origin(notif->url, &delta.meta.uri)) {
error = pr_val_err("Notification %s and Delta %s are not hosted by the same origin.",
- notif->url, delta.meta.uri);
- goto fail;
+ uri_str(notif->url), uri_str(&delta.meta.uri));
+ goto mta;
}
notification_deltas_add(¬if->deltas, &delta);
return 0;
-fail: serial_cleanup(&delta.serial);
- metadata_cleanup(&delta.meta);
+mta: metadata_cleanup(&delta.meta);
+srl: serial_cleanup(&delta.serial);
return error;
}
}
static int
-parse_notification(char const *url, char const *path,
+parse_notification(struct uri const *url, char const *path,
struct update_notification *result)
{
int error;
/* TODO (performance) Stream instead of caching notifs, snapshots & deltas. */
static int
-dl_tmp(char const *url, char *path)
+dl_tmp(struct uri const *url, char *path)
{
cache_tmpfile(path);
return http_download(url, path, 0, NULL);
handle_snapshot(struct update_notification *new, struct rrdp_state *state)
{
char tmppath[CACHE_TMPFILE_BUFLEN];
+ struct uri *url;
int error;
- pr_val_debug("Processing snapshot.");
- fnstack_push(new->snapshot.uri);
+ url = &new->snapshot.uri;
+ pr_val_debug("Processing snapshot '%s'.", uri_str(url));
+ fnstack_push(uri_str(url));
- error = dl_tmp(new->snapshot.uri, tmppath);
+ error = dl_tmp(url, tmppath);
if (error)
goto end;
error = validate_hash(&new->snapshot, tmppath);
struct notification_delta *delta, struct rrdp_state *state)
{
char tmppath[CACHE_TMPFILE_BUFLEN];
+ struct uri const *url;
int error;
- pr_val_debug("Processing delta '%s'.", delta->meta.uri);
- fnstack_push(delta->meta.uri);
+ url = &delta->meta.uri;
- error = dl_tmp(delta->meta.uri, tmppath);
+ pr_val_debug("Processing delta '%s'.", uri_str(url));
+ fnstack_push(uri_str(url));
+
+ error = dl_tmp(url, tmppath);
if (error)
goto end;
error = parse_delta(notif, delta, tmppath, state);
}
static int
-dl_notif(char const *url, time_t mtim, bool *changed,
+dl_notif(struct uri const *url, time_t mtim, bool *changed,
struct update_notification *new)
{
char tmppath[CACHE_TMPFILE_BUFLEN];
* snapshot, and explodes them into @notif->path.
*/
int
-rrdp_update(char const *notif, char const *path, time_t mtim,
+rrdp_update(struct uri const *notif, char const *path, time_t mtim,
bool *changed, struct rrdp_state **state)
{
struct rrdp_state *old;
int serial_cmp;
int error;
- fnstack_push(notif);
+ fnstack_push(uri_str(notif));
pr_val_debug("Processing notification.");
error = dl_notif(notif, mtim, changed, &new);
}
char const *
-rrdp_file(struct rrdp_state const *state, char const *url)
+rrdp_file(struct rrdp_state const *state, struct uri const *url)
{
struct cache_file *file;
- file = state_find_file(state, url, strlen(url));
+ file = state_find_file(state, url);
return file ? file->map.path : NULL;
}
char const *
-rrdp_create_fallback(char *cage, struct rrdp_state **_state, char const *url)
+rrdp_create_fallback(char *cage, struct rrdp_state **_state,
+ struct uri const *url)
{
struct rrdp_state *state;
struct cache_file *file;
+ char const *str;
size_t len;
state = *_state;
}
file = pzalloc(sizeof(struct cache_file));
- file->map.url = pstrdup(url);
+ uri_copy(&file->map.url, url);
file->map.path = cseq_next(&state->seq);
if (!file->map.path) {
- free(file->map.url);
+ uri_cleanup(&file->map.url);
free(file);
return NULL;
}
- len = strlen(file->map.url);
- HASH_ADD_KEYPTR(hh, state->files, file->map.url, len, file);
+ str = uri_str(&file->map.url);
+ len = uri_len(&file->map.url);
+ HASH_ADD_KEYPTR(hh, state->files, str, len, file);
return file->map.path;
}
return NULL;
HASH_ITER(hh, state->files, file, tmp)
- if (json_add_str(json, file->map.url, file->map.path))
+ if (json_add_str(json, uri_str(&file->map.url), file->map.path))
goto fail;
return json;
char const *jkey;
json_t *jvalue;
size_t parent_len;
+ struct uri url;
char const *path;
unsigned long id, max_id;
int error;
pr_op_warn("RRDP file URL '%s' is not a string.", jkey);
continue;
}
+ error = uri_init(&url, jkey);
+ if (error) {
+ pr_op_warn("Cannot parse '%s' as a URI.", jkey);
+ continue;
+ }
- // XXX sanitize more
+ // XXX sanitize more?
path = json_string_value(jvalue);
if (strncmp(path, parent, parent_len) != 0 || path[parent_len] != '/') {
pr_op_warn("RRDP path '%s' is not child of '%s'.",
path, parent);
+ uri_cleanup(&url);
continue;
}
error = hex2ulong(path + parent_len + 1, &id);
if (error) {
pr_op_warn("RRDP file '%s' is not a hexadecimal number.", path);
+ uri_cleanup(&url);
continue;
}
if (id > max_id)
max_id = id;
- cache_file_add(state, pstrdup(jkey), pstrdup(path));
+ cache_file_add(state, &url, pstrdup(path));
+ uri_cleanup(&url);
}
if (HASH_COUNT(state->files) == 0) {
if (rs == NULL)
return;
- printf("session:%s/%s\n", rs->session.session_id, rs->session.serial.str);
+ /* printf("session:%s/%s\n", rs->session.session_id, rs->session.serial.str); */
+ printf("\n");
HASH_ITER(hh, rs->files, file, tmp)
- printf("\t\tfile: %s\n", /* file->map.url, */ file->map.path);
- printf("\t\tseq:%s/%lx\n", rs->seq.prefix, rs->seq.next_id);
+ printf("\t\tfile: %s (%s)\n", file->map.path, uri_str(&file->map.url));
+ printf("\t\tseq: %s/%lx\n", rs->seq.prefix, rs->seq.next_id);
STAILQ_FOREACH(hash, &rs->delta_hashes, hook) {
printf("\t\thash: ");
#include <time.h>
#include "file.h"
+#include "types/url.h"
struct rrdp_state;
-int rrdp_update(char const *, char const *, time_t, bool *,
+int rrdp_update(struct uri const *, char const *, time_t, bool *,
struct rrdp_state **);
-char const *rrdp_file(struct rrdp_state const *, char const *);
+char const *rrdp_file(struct rrdp_state const *, struct uri const *);
-char const *rrdp_create_fallback(char *, struct rrdp_state **, char const *);
+char const *rrdp_create_fallback(char *, struct rrdp_state **,
+ struct uri const *);
json_t *rrdp_state2json(struct rrdp_state *);
int rrdp_json2state(json_t *, char *, struct rrdp_state **);
struct rsync_task {
int pid;
- char *url;
+ struct uri url;
char *path;
int stdoutfd; /* Child rsync's standard output */
int stderrfd; /* Child rsync's standard error */
* The asn1 code needs better error reporting.
*/
- if (RsyncRequest_init(&req, task->url, task->path) < 0) {
+ if (RsyncRequest_init(&req, &task->url, task->path) < 0) {
pr_op_err(RSP "Cannot message parent process: "
"The request object cannot be created");
return;
{
notify_parent(task);
- free(task->url);
+ uri_cleanup(&task->url);
free(task->path);
free(task);
}
}
static void
-prepare_rsync_args(char **args, char const *url, char const *path)
+prepare_rsync_args(char **args, struct uri const *url, char const *path)
{
size_t i;
for (i = 0; rsync_args[i] != NULL; i++)
args[i] = (char *)rsync_args[i];
- args[i++] = (char *)url;
+ args[i++] = (char *)uri_str(url);
args[i++] = (char *)path;
args[i++] = NULL;
}
}
static int
-execvp_rsync(char const *url, char const *path, int fds[2][2])
+execvp_rsync(struct uri const *url, char const *path, int fds[2][2])
{
char *args[20];
}
if (task->pid == 0) /* Child code */
- exit(execvp_rsync(task->url, task->path, fork_fds));
+ exit(execvp_rsync(&task->url, task->path, fork_fds));
/* Parent code */
tasks->a++;
}
+/* Steals ownership of @map. */
static void
post_task(struct cache_mapping *map, struct rsync_tasks *tasks,
struct timespec *now)
switch (decres.code) {
case RC_OK:
- result->url = OCTET_STRING_toString(&pssk.rr->url);
+ __uri_init(&result->url,
+ OCTET_STRING_toString(&pssk.rr->url),
+ pssk.rr->url.size);
result->path = OCTET_STRING_toString(&pssk.rr->path);
ASN_STRUCT_RESET(asn_DEF_RsyncRequest, pssk.rr);
return 0;
return;
pr_op_debug(RSP "Activating queued task %s -> %s.",
- task->url, task->path);
+ uri_str(&task->url), task->path);
LIST_REMOVE(task, lh);
activate_task(tasks, task, now);
}
struct cache_mapping map = { 0 };
while (next_task(&map) == 0) {
- rsync_finished(map.url, map.path);
+ rsync_finished(&map.url, map.path);
map_cleanup(&map);
}
* will be automatically called.
*/
int
-rsync_queue(char const *url, char const *path)
+rsync_queue(struct uri const *url, char const *path)
{
struct RsyncRequest req;
asn_enc_rval_t result;
#ifndef SRC_RSYNC_RSYNC_H_
#define SRC_RSYNC_RSYNC_H_
+#include "types/url.h"
+
void rsync_setup(char const *, ...);
-int rsync_queue(char const *, char const *);
-void rsync_finished(char const *, char const *);
+int rsync_queue(struct uri const *, char const *);
+void rsync_finished(struct uri const *, char const *);
void rsync_teardown(void);
#endif /* SRC_RSYNC_RSYNC_H_ */
atomic_fetch_add(&parent->refcount, 1);
ca = pzalloc(sizeof(struct rpki_certificate));
- ca->map.url = pstrdup(map->url);
+ uri_copy(&ca->map.url, &map->url);
ca->map.path = pstrdup(map->path);
ca->parent = parent;
atomic_init(&ca->refcount, 1);
STAILQ_REMOVE_HEAD(&waiting, lh);
mutex_unlock(&lock);
pr_op_debug("task_dequeue(): Claimed task '%s'.",
- task->u.ca->map.url);
+ uri_str(&task->u.ca->map.url));
return task;
}
{
switch (format) {
case FNF_GLOBAL:
- return map->url;
+ return uri_str(&map->url);
case FNF_LOCAL:
return map->path;
case FNF_NAME:
- return path_filename(map->url);
+ return path_filename(uri_str(&map->url));
}
pr_crit("Unknown file name format: %u", format);
void
map_copy(struct cache_mapping *dst, struct cache_mapping const *src)
{
- dst->url = pstrdup(src->url);
+ uri_copy(&dst->url, &src->url);
dst->path = pstrdup(src->path);
}
void
map_cleanup(struct cache_mapping *map)
{
- free(map->url);
+ uri_cleanup(&map->url);
free(map->path);
}
#ifndef SRC_TYPES_MAP_H_
#define SRC_TYPES_MAP_H_
+#include "types/url.h"
+
// XXX document this better
struct cache_mapping {
- /* Normalized, ASCII-only, NULL-terminated. */
- char *url;
- /* Normalized, ASCII-only, NULL-terminated. */
- char *path;
+ struct uri url; /* Normalized */
+ char *path; /* Normalized */
};
char const *map_val_get_printable(struct cache_mapping const *);
#include "types/str.h"
#include <errno.h>
+#include <string.h>
#include <openssl/bio.h>
+#include "alloc.h"
+#include "array.h"
#include "log.h"
#include "types/path.h"
int
ia5s2string(ASN1_IA5STRING *ia5, char **result)
{
- if (ia5->flags & ASN1_STRING_FLAG_BITS_LEFT)
- return pr_val_err("CRL URI IA5String has unused bits.");
+ unsigned char const *data;
+ size_t len;
+ array_index i;
+
+ /* Implementation-aware */
+ if (ia5->flags & ASN1_STRING_FLAG_BITS_LEFT) {
+ pr_val_warn("CRL URI IA5String has unused bits.");
+ return EINVAL;
+ }
- *result = string_clone(ia5->data, ia5->length);
+ /* TODO (asn1c) This might already be done by the asn1 code. */
+ data = ASN1_STRING_get0_data(ia5);
+ len = ASN1_STRING_length(ia5);
+ for (i = 0; i < len; i++)
+ if (data[i] == 0) {
+ pr_val_warn("Null character found in IA5String index %zu. (Length: %zu)",
+ i, len);
+ return EINVAL;
+ }
+
+ /* No NULL termination guarantee */
+ *result = pstrndup((char const *)data, len);
return 0;
}
return count;
}
-
-void
-strlist_init(struct strlist *list)
-{
- list->array = NULL;
- list->len = 0;
- list->capacity = 0;
-}
-
-void
-strlist_add(struct strlist *list, char *str)
-{
- if (list->array == NULL) {
- list->capacity = 8;
- list->array = pmalloc(list->capacity * sizeof(char *));
- }
-
- list->len++;
- while (list->len >= list->capacity) {
- list->capacity *= 2;
- list->array = prealloc(list->array,
- list->capacity * sizeof(char *));
- }
-
- list->array[list->len - 1] = str;
-}
-
-/* Call strlist_init() again if you want to reuse the list. */
-void
-strlist_cleanup(struct strlist *list)
-{
- array_index i;
- for (i = 0; i < list->len; i++)
- free(list->array[i]);
- free(list->array);
-}
#include <openssl/bn.h>
#include <stdbool.h>
-#include "types/arraylist.h"
-
char *str_concat(char const *, char const *);
int hex2ulong(char const *, unsigned long *);
char *token_read(struct string_tokenizer *);
size_t token_count(struct string_tokenizer *);
-/* Plural */
-
-DEFINE_ARRAY_LIST_STRUCT(strlist, char *);
-
-void strlist_init(struct strlist *);
-void strlist_cleanup(struct strlist *);
-void strlist_add(struct strlist *, char *);
-
#endif /* SRC_TYPES_STR_H_ */
#include "types/url.h"
#include <curl/curl.h>
+#include <errno.h>
#include "alloc.h"
#include "common.h"
#include "types/path.h"
bool
-url_is_rsync(char const *url)
+uri_is_rsync(struct uri const *url)
{
- return str_starts_with(url, "rsync://");
+ return str_starts_with(url->_str, "rsync://");
}
bool
-url_is_https(char const *url)
+uri_is_https(struct uri const *url)
{
- return str_starts_with(url, "https://");
+ return str_starts_with(url->_str, "https://");
}
/*
* whose implementation is somewhat flawed (at least until version 8.12.1):
* https://github.com/curl/curl/issues/16829
*
- * On the other hand, since Fort 2 no longer maps URI paths to literal local
- * paths, all normalization does for us is prevent some theoretical redundant
- * downloading, so it might not even be that necessary.
+ * That said, since Fort 2 no longer maps URI paths to literal local paths, all
+ * normalization does for us is prevent some theoretical redundant downloading,
+ * so it's fine.
*/
-char *
+static char *
url_normalize(char const *url)
{
CURLU *curlu;
return NULL;
}
-char *
-url_parent(char const *child)
+int
+uri_init(struct uri *url, char const *str)
{
- char *slash = strrchr(child, '/');
- return (slash != NULL) ? pstrndup(child, slash - child) : NULL;
+ str = url_normalize(str);
+ if (!str)
+ return EINVAL;
+
+ __URI_INIT(url, str);
+ return 0;
+}
+
+/* @str must already be normalized. */
+void
+__uri_init(struct uri *url, char const *str, size_t len)
+{
+ url->_str = (char *)str;
+ url->_len = len;
+}
+
+void
+uri_copy(struct uri *dst, struct uri const *src)
+{
+ dst->_str = src->_str ? pstrdup(src->_str) : NULL;
+ dst->_len = src->_len;
+}
+
+void
+uri_cleanup(struct uri *url)
+{
+ free(url->_str);
+ url->_str = NULL;
+}
+
+bool
+uri_equals(struct uri const *u1, struct uri const *u2)
+{
+ return (u1->_len == u2->_len)
+ ? (memcmp(u1->_str, u2->_str, u1->_len) == 0)
+ : false;
+}
+
+bool
+uri_has_extension(struct uri const *url, char const *ext)
+{
+ return strcmp(url->_str + url->_len - strlen(ext), ext) == 0;
+}
+
+/* Result is a shallow copy; do not clean. */
+int
+uri_parent(struct uri const *child, struct uri *parent)
+{
+ char *slash;
+
+ slash = strrchr(child->_str, '/');
+ if (slash == NULL)
+ return EINVAL;
+
+ parent->_str = child->_str;
+ parent->_len = slash - child->_str;
+ return 0;
}
bool
-url_same_origin(char const *url1, char const *url2)
+uri_same_origin(struct uri const *uri1, struct uri const *uri2)
{
+ char const *str1, *str2;
size_t c, slashes;
+ str1 = uri1->_str;
+ str2 = uri2->_str;
slashes = 0;
- for (c = 0; url1[c] == url2[c]; c++) {
- switch (url1[c]) {
+
+ for (c = 0; str1[c] == str2[c]; c++) {
+ switch (str1[c]) {
case '/':
slashes++;
if (slashes == 3)
}
}
- if (url1[c] == '\0')
- return (slashes == 2) && url2[c] == '/';
- if (url2[c] == '\0')
- return (slashes == 2) && url1[c] == '/';
+ if (str1[c] == '\0')
+ return (slashes == 2) && str2[c] == '/';
+ if (str2[c] == '\0')
+ return (slashes == 2) && str1[c] == '/';
return false;
}
+
+void
+uri_child(struct uri const *parent, char const *name, size_t len,
+ struct uri *child)
+{
+ size_t slash;
+
+ slash = parent->_str[parent->_len - 1] != '/';
+
+ child->_len = parent->_len + slash + len;
+ child->_str = pmalloc(child->_len + 1);
+ strncpy(child->_str, parent->_str, parent->_len);
+ if (slash)
+ child->_str[parent->_len] = '/';
+ strncpy(child->_str + parent->_len + slash, name, len);
+ child->_str[child->_len] = '\0';
+}
+
+DEFINE_ARRAY_LIST_FUNCTIONS(uris, struct uri, )
#define SRC_TYPES_URL_H_
#include <stdbool.h>
+#include <stddef.h>
+
+#include "types/arraylist.h"
#define RPKI_SCHEMA_LEN 8 /* strlen("rsync://"), strlen("https://") */
-bool url_is_rsync(char const *);
-bool url_is_https(char const *);
+struct uri {
+ char *_str;
+ size_t _len;
+};
+
+int uri_init(struct uri *, char const *);
+void __uri_init(struct uri *, char const *, size_t);
+#define __URI_INIT(uri, str) __uri_init(uri, str, strlen(str))
+void uri_copy(struct uri *, struct uri const *);
+void uri_cleanup(struct uri *);
+
+#define uri_str(u) ((char const *)((u)->_str))
+#define uri_len(u) ((u)->_len)
+
+bool uri_is_rsync(struct uri const *);
+bool uri_is_https(struct uri const *);
+
+bool uri_equals(struct uri const *, struct uri const *);
+bool uri_has_extension(struct uri const *, char const *);
+bool uri_same_origin(struct uri const *, struct uri const *);
+
+int uri_parent(struct uri const *, struct uri *);
+void uri_child(struct uri const *, char const *, size_t, struct uri *);
+#define URI_CHILD(uri, name, child) uri_child(uri, name, strlen(name), child)
+
+/* Plural */
-char *url_normalize(char const *);
-char *url_parent(char const *);
-bool url_same_origin(char const *, char const *);
+DEFINE_ARRAY_LIST_STRUCT(uris, struct uri);
+DECLARE_ARRAY_LIST_FUNCTIONS(uris, struct uri)
#endif /* SRC_TYPES_URL_H_ */
check_PROGRAMS += cache.test
cache_test_SOURCES = cache_test.c
cache_test_LDADD = ${CHECK_LIBS}
+cache_test_LDADD += ${CURL_LIBS}
cache_test_LDADD += ${XML2_LIBS}
cache_test_LDADD += ${JANSSON_LIBS}
check_PROGRAMS += rrdp.test
rrdp_test_SOURCES = rrdp_test.c
rrdp_test_LDADD = ${CHECK_LIBS}
+rrdp_test_LDADD += ${CURL_LIBS}
rrdp_test_LDADD += ${XML2_LIBS}
rrdp_test_LDADD += ${JANSSON_LIBS}
check_PROGRAMS += rrdp_update.test
rrdp_update_test_SOURCES = rrdp_update_test.c
rrdp_update_test_LDADD = ${CHECK_LIBS}
+rrdp_update_test_LDADD += ${CURL_LIBS}
rrdp_update_test_LDADD += ${XML2_LIBS}
rrdp_update_test_LDADD += ${JANSSON_LIBS}
check_PROGRAMS += rsync.test
rsync_test_SOURCES = rsync_test.c
rsync_test_LDADD = ${CHECK_LIBS}
+rsync_test_LDADD += ${CURL_LIBS}
check_PROGRAMS += serial.test
serial_test_SOURCES = types/serial_test.c
check_PROGRAMS += tal.test
tal_test_SOURCES = object/tal_test.c
tal_test_LDADD = ${CHECK_LIBS}
+tal_test_LDADD += ${CURL_LIBS}
check_PROGRAMS += task.test
task_test_SOURCES = task_test.c
ck_assert_int_eq(0, system(cmd));
}
-static char *queued_url;
+static struct uri queued_url;
static char *queued_path;
int
-rsync_queue(char const *url, char const *path)
+rsync_queue(struct uri const *url, char const *path)
{
rsync_counter++;
return dl_error;
}
- printf("Simulating rsync: %s -> %s\n", url, path);
+ printf("Simulating rsync: %s -> %s\n", uri_str(url), path);
ck_assert_int_eq(0, mkdir(path, CACHE_FILEMODE));
touch_file(path);
- queued_url = pstrdup(url);
+ uri_copy(&queued_url, url);
queued_path = pstrdup(path);
return 0;
static struct cache_cage *
run_dl_rsync(char *caRepository, int expected_err, unsigned int expected_calls)
{
- struct sia_uris sias = { .caRepository = caRepository };
- struct cache_cage *cage = NULL;
+ struct sia_uris sias = { 0 };
+ struct cache_cage *cage;
+
+ ck_assert_int_eq(0, uri_init(&sias.caRepository, caRepository));
+ cage = NULL;
rsync_counter = 0;
https_counter = 0;
ck_assert_uint_eq(expected_calls, rsync_counter);
ck_assert_uint_eq(0, https_counter);
+ uri_cleanup(&sias.caRepository);
return cage;
}
static void
finish_rsync(void)
{
- rsync_finished(queued_url, queued_path);
- free(queued_url);
+ rsync_finished(&queued_url, queued_path);
+ uri_cleanup(&queued_url);
free(queued_path);
}
run_dl_https(char const *url, unsigned int expected_calls,
char const *expected_result)
{
+ struct uri uri;
char const *result;
+ ck_assert_int_eq(0, uri_init(&uri, url));
+
rsync_counter = 0;
https_counter = 0;
printf("---- Downloading... ----\n");
- result = cache_refresh_by_url(url);
+ result = cache_refresh_by_url(&uri);
printf("---- Downloaded. ----\n");
ck_assert_uint_eq(0, rsync_counter);
ck_assert_uint_eq(expected_calls, https_counter);
ck_assert_str(expected_result, result);
- ck_assert_str(NULL, cache_get_fallback(url));
+ ck_assert_str(NULL, cache_get_fallback(&uri));
+
+ uri_cleanup(&uri);
}
ck_cage(struct cache_cage *cage, char const *url,
char const *refresh, char const *fallback)
{
+ struct uri uri;
struct cache_node const *bkp;
- ck_assert_str(refresh, cage_map_file(cage, url));
+ ck_assert_int_eq(0, uri_init(&uri, url));
+
+ ck_assert_str(refresh, cage_map_file(cage, &uri));
bkp = cage->refresh;
cage_disable_refresh(cage);
-
- ck_assert_str(fallback, cage_map_file(cage, url));
-
+ ck_assert_str(fallback, cage_map_file(cage, &uri));
cage->refresh = bkp;
+
+ uri_cleanup(&uri);
}
static int
char const *path1, char const *path2)
{
struct rpp rpp = { 0 };
+ struct uri rn, cr;
+
+ if (rpkiNotify)
+ ck_assert_int_eq(0, uri_init(&rn, rpkiNotify));
+ else
+ memset(&rn, 0, sizeof(rn));
+ if (caRepository)
+ ck_assert_int_eq(0, uri_init(&cr, caRepository));
+ else
+ memset(&cr, 0, sizeof(cr));
rpp.nfiles = 2;
rpp.files = pzalloc(rpp.nfiles * sizeof(struct cache_mapping));
- rpp.files[0].url = path_join(caRepository, "manifest.mft");
+ URI_CHILD(&cr, "manifest.mft", &rpp.files[0].url);
rpp.files[0].path = pstrdup(path1);
- rpp.files[1].url = path_join(caRepository, "cert.cer");
+ URI_CHILD(&cr, "cert.cer", &rpp.files[1].url);
rpp.files[1].path = pstrdup(path2);
- cache_commit_rpp(rpkiNotify, caRepository, &rpp);
+ cache_commit_rpp(&rn, &cr, &rpp);
+
+ uri_cleanup(&cr);
+ uri_cleanup(&rn);
}
/* Only validates the first character of the file. */
{
node->key.id = url;
node->key.idlen = strlen(url);
- node->key.rsync = url;
+ ck_assert_int_eq(0, uri_init(&node->key.rsync, url));
node->path = path;
node->state = fresh ? DLS_FRESH : DLS_OUTDATED; /* XXX (test) */
node->dlerr = dlerr;
{
node->key.id = url;
node->key.idlen = strlen(url);
- node->key.http = url;
+ ck_assert_int_eq(0, uri_init(&node->key.http, url));
node->path = path;
node->state = fresh ? DLS_FRESH : DLS_OUTDATED;
node->dlerr = dlerr;
static void
ck_node_key(struct node_key *expected, struct node_key *actual)
{
- if (expected->http)
- ck_assert_str_eq(expected->http, actual->http);
- else
- ck_assert_ptr_eq(NULL, actual->http);
- if (expected->rsync)
- ck_assert_str_eq(expected->rsync, actual->rsync);
- else
- ck_assert_ptr_eq(NULL, actual->rsync);
+ ck_assert(uri_equals(&expected->http, &actual->http));
+ ck_assert(uri_equals(&expected->rsync, &actual->rsync));
ck_assert_uint_eq(expected->idlen, actual->idlen);
ck_assert_mem_eq(expected->id, actual->id, expected->idlen);
}
}
/* 3 */
- map.url = "https://domain/rpki/ta50.cer";
- map.path = "https/50";
+ ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta50.cer"));
+ map.path = pstrdup("https/50");
cache_commit_file(&map);
- map.url = "https://domain/rpki/ta52.cer";
- map.path = "https/52";
+ map_cleanup(&map);
+
+ ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta52.cer"));
+ map.path = pstrdup("https/52");
cache_commit_file(&map);
+ map_cleanup(&map);
+
cleanup_cache();
ck_filesystem("fallback",
"fallback/0", "A", "fallback/0.json", "{",
new_iteration(false);
/* 4 */
- map.url = "https://domain/rpki/ta50.cer";
- map.path = "fallback/0";
+ ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta50.cer"));
+ map.path = pstrdup("fallback/0");
cache_commit_file(&map);
- map.url = "https://domain/rpki/ta51.cer";
- map.path = "https/51";
+ map_cleanup(&map);
+
+ ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta51.cer"));
+ map.path = pstrdup("https/51");
cache_commit_file(&map);
+ map_cleanup(&map);
+
cleanup_cache();
ck_filesystem("fallback",
"fallback/0", "A", "fallback/0.json", "{",
char *FILE_RSYNC_PATH = "rsync/0/rpp3/a.cer";
struct sia_uris sias = { 0 };
+ struct uri file_url;
struct cache_cage *cage;
struct rpp rpp = { 0 };
dls[1] = SHDR("3") PBLSH("rsync://x.y.z/mod5/rpp3/a.cer", "Rm9ydAo=") STAIL;
dls[2] = NULL;
- /* 1. 1st CA succeeds on RRDP */
- sias.rpkiNotify = RPKI_NOTIFY;
- sias.caRepository = CA_REPOSITORY;
+ ck_assert_int_eq(0, uri_init(&file_url, FILE_URL));
+
+ printf("1. 1st CA succeeds on RRDP\n");
+ print_tree();
+ ck_assert_int_eq(0, uri_init(&sias.rpkiNotify, RPKI_NOTIFY));
+ ck_assert_int_eq(0, uri_init(&sias.caRepository, CA_REPOSITORY));
ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage));
- ck_assert_str_eq(RPKI_NOTIFY, cage->rpkiNotify);
- ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, FILE_URL));
+ ck_assert_str_eq(RPKI_NOTIFY, uri_str(&cage->rpkiNotify));
+ ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, &file_url));
ck_assert_int_eq(false, cage_disable_refresh(cage));
- ck_assert_ptr_eq(NULL, cage_map_file(cage, FILE_URL));
+ ck_assert_ptr_eq(NULL, cage_map_file(cage, &file_url));
- /*
- * 2. 2nd CA points to the same caRepository,
- * but does not provide RRDP as an option.
- */
- sias.rpkiNotify = NULL;
+ printf("2. 2nd CA points to the same caRepository,\n");
+ printf(" but does not provide RRDP as an option.\n");
+ print_tree();
+ uri_cleanup(&sias.rpkiNotify);
ck_assert_int_eq(EBUSY, cache_refresh_by_sias(&sias, &cage));
finish_rsync();
ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage));
- ck_assert_ptr_eq(NULL, cage->rpkiNotify);
- ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, FILE_URL));
+ ck_assert_ptr_eq(NULL, uri_str(&cage->rpkiNotify));
+ ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, &file_url));
ck_assert_int_eq(false, cage_disable_refresh(cage));
- ck_assert_ptr_eq(NULL, cage_map_file(cage, FILE_URL));
+ ck_assert_ptr_eq(NULL, cage_map_file(cage, &file_url));
+
+ printf("3. Commit\n");
- /* 3. Commit */
+ print_tree();
rpp.nfiles = 1;
rpp.files = pzalloc(sizeof(struct cache_mapping));
- rpp.files->url = pstrdup(FILE_URL);
+ uri_copy(&rpp.files->url, &file_url);
rpp.files->path = pstrdup(FILE_RRDP_PATH);
- cache_commit_rpp(RPKI_NOTIFY, CA_REPOSITORY, &rpp);
+ ck_assert_int_eq(0, uri_init(&sias.rpkiNotify, RPKI_NOTIFY));
+ cache_commit_rpp(&sias.rpkiNotify, &sias.caRepository, &rpp);
rpp.nfiles = 1;
rpp.files = pzalloc(sizeof(struct cache_mapping));
- rpp.files->url = pstrdup(FILE_URL);
+ uri_copy(&rpp.files->url, &file_url);
rpp.files->path = pstrdup(FILE_RSYNC_PATH);
- cache_commit_rpp(NULL, CA_REPOSITORY, &rpp);
+ uri_cleanup(&sias.rpkiNotify);
+ cache_commit_rpp(&sias.rpkiNotify, &sias.caRepository, &rpp);
commit_fallbacks(time_fatal());
- /* 4. Redo both CAs, check the fallbacks too */
+ printf("4. Redo both CAs, check the fallbacks too\n");
+ print_tree();
ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage));
- ck_assert_ptr_eq(NULL, cage->rpkiNotify);
- ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, FILE_URL));
+ ck_assert_ptr_eq(NULL, uri_str(&cage->rpkiNotify));
+ ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, &file_url));
ck_assert_int_eq(true, cage_disable_refresh(cage));
- ck_assert_str_eq("fallback/1/0", cage_map_file(cage, FILE_URL));
+ ck_assert_str_eq("fallback/1/0", cage_map_file(cage, &file_url));
- sias.rpkiNotify = RPKI_NOTIFY;
+ ck_assert_int_eq(0, uri_init(&sias.rpkiNotify, RPKI_NOTIFY));
ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage));
- ck_assert_str_eq(RPKI_NOTIFY, cage->rpkiNotify);
- ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, FILE_URL));
+ ck_assert_str_eq(RPKI_NOTIFY, uri_str(&cage->rpkiNotify));
+ ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, &file_url));
ck_assert_int_eq(true, cage_disable_refresh(cage));
- ck_assert_str_eq("fallback/0/0", cage_map_file(cage, FILE_URL));
+ ck_assert_str_eq("fallback/0/0", cage_map_file(cage, &file_url));
+
+ uri_cleanup(&sias.rpkiNotify);
+ uri_cleanup(&sias.caRepository);
+ uri_cleanup(&file_url);
cleanup_test();
relax_ng_cleanup();
ck_assert_int_eq(HASH_COUNT(expected->files), HASH_COUNT(actual->files));
HASH_ITER(hh, expected->files, expf, tmp) {
- HASH_FIND(hh, actual->files, expf->map.url, strlen(expf->map.url), actf);
+ HASH_FIND(hh, actual->files, uri_str(&expf->map.url), uri_len(&expf->map.url), actf);
ck_assert_ptr_ne(NULL, actf);
- ck_assert_str_eq(expf->map.url, actf->map.url);
+ ck_assert(uri_equals(&expf->map.url, &actf->map.url));
ck_assert_str_eq(expf->map.path, actf->map.path);
}
node->key.id = pstrdup("https://a.b.c/sample.cer");
node->key.idlen = strlen(node->key.id);
- node->key.http = node->key.id;
+ __uri_init(&node->key.http, node->key.id, node->key.idlen);
node->path = pstrdup("tmp/sample.cer");
node->state = DLS_FRESH;
node->dlerr = ENOENT;
ck_json(node);
}
+static void
+CACHE_FILE_ADD(struct rrdp_state *state, char const *url, char *path)
+{
+ struct uri uri;
+
+ ck_assert_int_eq(0, uri_init(&uri, url));
+ ck_assert_ptr_ne(NULL, cache_file_add(state, &uri, pstrdup(path)));
+ uri_cleanup(&uri);
+}
+
START_TEST(test_json_rrdp_min)
{
struct cache_node *node = pzalloc(sizeof(struct cache_node));
node->key.id = pstrdup("https://a.b.c/sample.cer");
node->key.idlen = strlen(node->key.id);
- node->key.http = node->key.id;
+ __uri_init(&node->key.http, node->key.id, node->key.idlen);
node->path = pstrdup("rrdp/123");
node->state = DLS_FRESH;
node->dlerr = ENOENT;
ck_assert_ptr_ne(NULL, node->rrdp->session.serial.num);
BN_add_word(node->rrdp->session.serial.num, 1357);
node->rrdp->session.serial.str = pstrdup("1357");
- cache_file_add(node->rrdp, pstrdup("rsync://a.b.c/d/e.mft"), pstrdup("rrdp/123/0"));
+ CACHE_FILE_ADD(node->rrdp, "rsync://a.b.c/d/e.mft", "rrdp/123/0");
cseq_init(&node->rrdp->seq, node->path, 1, false);
STAILQ_INIT(&node->rrdp->delta_hashes);
node->key.id = pstrdup("https://a.b.c/sample.cer");
node->key.idlen = strlen(node->key.id);
- node->key.http = node->key.id;
+ __uri_init(&node->key.http, node->key.id, node->key.idlen);
node->path = pstrdup("rrdp/123");
node->state = DLS_FRESH;
node->dlerr = ENOENT;
ck_assert_ptr_ne(NULL, node->rrdp->session.serial.num);
BN_add_word(node->rrdp->session.serial.num, 1357);
node->rrdp->session.serial.str = pstrdup("1357");
- cache_file_add(node->rrdp, pstrdup("rsync://a.b.c/d/e.mft"), pstrdup("rrdp/123/0"));
- cache_file_add(node->rrdp, pstrdup("rsync://a.b.c/d/f.crl"), pstrdup("rrdp/123/1"));
+ CACHE_FILE_ADD(node->rrdp, "rsync://a.b.c/d/e.mft", "rrdp/123/0");
+ CACHE_FILE_ADD(node->rrdp, "rsync://a.b.c/d/f.crl", "rrdp/123/1");
cseq_init(&node->rrdp->seq, node->path, 2, false);
STAILQ_INIT(&node->rrdp->delta_hashes);
hash = pmalloc(sizeof(struct rrdp_hash));
{
static char const *NOTIF = "https://a.b.c/notif.xml";
static char const *CAREPO = "rsync://a.b.c/rpp";
+ size_t nlen;
+ size_t clen;
+ struct cache_node *node;
- struct cache_node *node = pzalloc(sizeof(struct cache_node));
+ nlen = strlen(NOTIF);
+ clen = strlen(CAREPO);
+ node = pzalloc(sizeof(struct cache_node));
- node->key.idlen = strlen(NOTIF) + strlen(CAREPO) + 1;
+ node->key.idlen = nlen + clen + 1;
node->key.id = pmalloc(node->key.idlen + 1);
strcpy(node->key.id, NOTIF);
- strcpy(node->key.id + strlen(NOTIF) + 1, CAREPO);
- node->key.http = node->key.id;
- node->key.rsync = node->key.id + strlen(NOTIF) + 1;
+ strcpy(node->key.id + nlen + 1, CAREPO);
+ __uri_init(&node->key.http, node->key.id, nlen);
+ __uri_init(&node->key.rsync, node->key.id + nlen + 1, clen);
node->path = pstrdup("tmp/sample.cer");
node->state = DLS_FRESH;
node->dlerr = ENOENT;
else
ck_assert_ptr_eq(NULL, actual);
}
+
+void
+ck_assert_uri(char const *expected, struct uri const *actual)
+{
+ ck_assert_str_eq(expected, uri_str(actual));
+ ck_assert_uint_eq(strlen(expected), uri_len(actual));
+}
static unsigned int https_counter; /* Times http_download() was called */
int
-http_download(char const *url, char const *path, curl_off_t ims, bool *changed)
+http_download(struct uri const *url, char const *path,
+ curl_off_t ims, bool *changed)
{
char const *content;
return dl_error;
}
- printf("Simulating HTTP download: %s -> %s\n", url, path);
+ printf("Simulating HTTP download: %s -> %s\n", uri_str(url), path);
content = dls[https_counter++];
if (!content)
ck_assert_int_eq(0, tal_init(&tal, file));
ck_assert_uint_eq(1, tal.urls.len);
- ck_assert_str_eq("rsync://example.com/rpki/ta.cer", tal.urls.array[0]);
+ ck_assert_uri("rsync://example.com/rpki/ta.cer", &tal.urls.array[0]);
check_spki(&tal);
tal_cleanup(&tal);
ck_assert_int_eq(0, tal_init(&tal, file));
ck_assert_uint_eq(4, tal.urls.len);
- ck_assert_str_eq("rsync://example.com/rpki/ta.cer", tal.urls.array[0]);
- ck_assert_str_eq("https://example.com/rpki/ta.cer", tal.urls.array[1]);
- ck_assert_str_eq("rsync://www.example.com/potato/ta.cer", tal.urls.array[2]);
- ck_assert_str_eq("https://wx3.example.com/tomato/ta.cer", tal.urls.array[3]);
+ ck_assert_uri("rsync://example.com/rpki/ta.cer", &tal.urls.array[0]);
+ ck_assert_uri("https://example.com/rpki/ta.cer", &tal.urls.array[1]);
+ ck_assert_uri("rsync://www.example.com/potato/ta.cer", &tal.urls.array[2]);
+ ck_assert_uri("https://wx3.example.com/tomato/ta.cer", &tal.urls.array[3]);
check_spki(&tal);
struct rrdp_hash *hash;
size_t i;
- notif = pmalloc(sizeof(struct rrdp_state));
+ notif = pzalloc(sizeof(struct rrdp_state));
*result = notif;
init_rrdp_session(¬if->session, serial);
va_start(args, serial);
while ((hash_byte = va_arg(args, int)) >= 0) {
init_serial(&delta.serial, serial--);
- delta.meta.uri = NULL; /* Not needed for now */
+ memset(&delta.meta.uri, 0, sizeof(delta.meta.uri)); /* Not needed for now */
delta.meta.hash = pmalloc(RRDP_HASH_LEN);
for (i = 0; i < RRDP_HASH_LEN; i++)
delta.meta.hash[i] = hash_byte;
START_TEST(test_parse_notification_ok)
{
struct update_notification notif;
+ struct uri nurl;
ck_assert_int_eq(0, relax_ng_init());
- ck_assert_int_eq(0, parse_notification("https://host/notification.xml",
+ ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml"));
+ ck_assert_int_eq(0, parse_notification(&nurl,
"resources/rrdp/notif-ok.xml", ¬if));
+ uri_cleanup(&nurl);
ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28",
(char const *)notif.session.session_id);
ck_assert_str_eq("3", (char const *)notif.session.serial.str);
- ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri);
+ ck_assert_uri("https://host/9d-8/3/snapshot.xml", ¬if.snapshot.uri);
ck_assert_uint_eq(32, notif.snapshot.hash_len);
validate_aaaa_hash(notif.snapshot.hash);
ck_assert_uint_eq(2, notif.deltas.len);
ck_assert_str_eq("2", (char const *)notif.deltas.array[0].serial.str);
- ck_assert_str_eq("https://host/9d-8/2/delta.xml",
- notif.deltas.array[0].meta.uri);
+ ck_assert_uri("https://host/9d-8/2/delta.xml",
+ ¬if.deltas.array[0].meta.uri);
ck_assert_uint_eq(32, notif.deltas.array[0].meta.hash_len);
validate_01234_hash(notif.deltas.array[0].meta.hash);
ck_assert_str_eq("3", (char const *)notif.deltas.array[1].serial.str);
- ck_assert_str_eq("https://host/9d-8/3/delta.xml",
- notif.deltas.array[1].meta.uri);
+ ck_assert_uri("https://host/9d-8/3/delta.xml",
+ ¬if.deltas.array[1].meta.uri);
ck_assert_uint_eq(32, notif.deltas.array[1].meta.hash_len);
validate_01234_hash(notif.deltas.array[0].meta.hash);
START_TEST(test_parse_notification_0deltas)
{
struct update_notification notif;
+ struct uri nurl;
ck_assert_int_eq(0, relax_ng_init());
- ck_assert_int_eq(0, parse_notification("https://host/notification.xml",
+ ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml"));
+ ck_assert_int_eq(0, parse_notification(&nurl,
"resources/rrdp/notif-0deltas.xml", ¬if));
+ uri_cleanup(&nurl);
ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28",
(char const *)notif.session.session_id);
ck_assert_str_eq("3", (char const *)notif.session.serial.str);
- ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri);
+ ck_assert_uri("https://host/9d-8/3/snapshot.xml", ¬if.snapshot.uri);
ck_assert_uint_eq(32, notif.snapshot.hash_len);
validate_01234_hash(notif.snapshot.hash);
START_TEST(test_parse_notification_large_serial)
{
struct update_notification notif;
+ struct uri nurl;
ck_assert_int_eq(0, relax_ng_init());
- ck_assert_int_eq(0, parse_notification("https://host/notification.xml",
+ ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml"));
+ ck_assert_int_eq(0, parse_notification(&nurl,
"resources/rrdp/notif-large-serial.xml", ¬if));
+ uri_cleanup(&nurl);
ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28",
(char const *)notif.session.session_id);
ck_assert_str_eq("999999999999999999999999",
(char const *)notif.session.serial.str);
- ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri);
+ ck_assert_uri("https://host/9d-8/3/snapshot.xml", ¬if.snapshot.uri);
ck_assert_uint_eq(32, notif.snapshot.hash_len);
validate_01234_hash(notif.snapshot.hash);
test_parse_notification_error(char *file)
{
struct update_notification notif;
+ struct uri nurl;
ck_assert_int_eq(0, relax_ng_init());
- ck_assert_int_eq(-EINVAL,
- parse_notification("https://host/notification.xml", file, ¬if));
+ ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml"));
+ ck_assert_int_eq(-EINVAL, parse_notification(&nurl, file, ¬if));
+ uri_cleanup(&nurl);
relax_ng_cleanup();
}
ck_assert_str_eq(session, actual->session.session_id);
ck_assert_str_eq(serial, actual->session.serial.str);
- for (m = 0; maps[m].url != NULL; m++)
+ for (m = 0; uri_str(&maps[m].url) != NULL; m++)
;
ck_assert_int_eq(m, HASH_COUNT(actual->files));
m = 0;
HASH_ITER(hh, actual->files, node, tmp) {
- ck_assert_str_eq(maps[m].url, node->map.url);
+ ck_assert(uri_equals(&maps[m].url, &node->map.url));
ck_assert_str_eq(maps[m].path, node->map.path);
m++;
}
static char const *URL = "https://host/notification.xml";
static char const *PATH = "rrdp/0";
struct cache_sequence seq;
+ struct uri url;
struct rrdp_state *state = NULL;
struct cache_mapping maps[4];
bool changed;
seq.pathlen = strlen(seq.prefix);
seq.free_prefix = false;
+ ck_assert_int_eq(0, uri_init(&url, URL));
+
dls[0] = NHDR("3")
NSS("https://host/9d-8/3/snapshot.xml",
"0c84fb949e7b5379ae091b86c41bb1a33cb91636b154b86ad1b1dedd44651a25")
dls[2] = NULL;
https_counter = 0;
- ck_assert_int_eq(0, rrdp_update(URL, PATH, 0, &changed, &state));
+ ck_assert_int_eq(0, rrdp_update(&url, PATH, 0, &changed, &state));
ck_assert_uint_eq(2, https_counter);
ck_assert_uint_eq(true, changed);
ck_file("rrdp/0/0"); /* "rrdp/<first-cage>/<c.cer>" */
- maps[0].url = "rsync://a/b/c.cer";
+ ck_assert_int_eq(0, uri_init(&maps[0].url, "rsync://a/b/c.cer"));
maps[0].path = "rrdp/0/0";
- maps[1].url = NULL;
+ memset(&maps[1], 0, sizeof(maps[1]));
ck_state(TEST_SESSION, "3", 1, maps, state);
/* Attempt to update, server hasn't changed anything. */
dls[1] = NULL; /* Snapshot should not redownload */
https_counter = 0;
- ck_assert_int_eq(0, rrdp_update(URL, PATH, 0, &changed, &state));
+ ck_assert_int_eq(0, rrdp_update(&url, PATH, 0, &changed, &state));
ck_assert_uint_eq(1, https_counter);
ck_assert_uint_eq(false, changed);
ck_file("rrdp/0/0");
// XXX Missing a looooooooooooooooooot of tests
+ uri_cleanup(&url);
cleanup_test();
}
END_TEST
#include "rsync.c"
#include "stream.c"
#include "types/map.c"
+#include "types/url.c"
#include "asn1/asn1c/ber_decoder.c"
#include "asn1/asn1c/ber_tlv_length.c"
static int rsyncs_done = 0;
void
-rsync_finished(char const *url, char const *path)
+rsync_finished(struct uri const *url, char const *path)
{
struct timespec now;
int delta;
/* Test RsyncRequest decode, feeding as few bytes as possible every time. */
START_TEST(test_decode_extremely_fragmented)
{
+ struct uri uri;
struct RsyncRequest src, *dst;
unsigned char encoded[BUFSIZE];
asn_enc_rval_t encres;
asn_dec_rval_t decres;
unsigned int start, end, max;
- ck_assert_int_eq(0, RsyncRequest_init(&src,
- "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789",
+ __URI_INIT(&uri, "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789");
+
+ ck_assert_int_eq(0, RsyncRequest_init(&src, &uri,
"AbCdEfGhIjKlMnOpQrStUvWxYz1234567890"));
encres = der_encode_to_buffer(&asn_DEF_RsyncRequest, &src,
encoded, sizeof(encoded));
struct cache_mapping map;
ck_assert_int_eq(0, next_task(&map));
- ck_assert_str_eq(url, map.url);
+ ck_assert_uri(url, &map.url);
ck_assert_str_eq(path, map.path);
map_cleanup(&map);
static void
encode_request(char const *url, char const *path, unsigned char *buffer)
{
+ struct uri uri;
struct RsyncRequest rr;
asn_enc_rval_t encres;
- ck_assert_int_eq(0, RsyncRequest_init(&rr, url, path));
+ __URI_INIT(&uri, url);
+
+ ck_assert_int_eq(0, RsyncRequest_init(&rr, &uri, path));
encres = der_encode_to_buffer(&asn_DEF_RsyncRequest, &rr, buffer, BUFSIZE);
ck_assert_int_gt(encres.encoded, 0);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RsyncRequest, &rr);
}
END_TEST
+static int
+RSYNC_QUEUE(char const *a, char const *b)
+{
+ struct uri uri;
+ __URI_INIT(&uri, a);
+ return rsync_queue(&uri, b);
+}
+
/* Makes sure @count rsyncs finish after roughly @millis milliseconds. */
static void
wait_rsyncs(unsigned int count, unsigned int millis)
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
wait_rsyncs(1, 0);
rsync_teardown();
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
wait_rsyncs(1, 3000);
rsync_teardown();
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
wait_rsyncs(1, 4000); /* 4000 = timeout */
rsync_teardown();
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
wait_rsyncs(1, 3000);
rsync_teardown();
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
wait_rsyncs(1, 4000); /* 4000 = timeout */
rsync_teardown();
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
- ck_assert_int_eq(0, rsync_queue("C", "D"));
- ck_assert_int_eq(0, rsync_queue("E", "F"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("C", "D"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("E", "F"));
wait_rsyncs(3, 1000);
ck_assert_int_ne(-1, pssk.rd.fd);
ck_assert_int_ne(-1, pssk.wr);
- ck_assert_int_eq(0, rsync_queue("A", "B"));
- ck_assert_int_eq(0, rsync_queue("C", "D"));
- ck_assert_int_eq(0, rsync_queue("E", "F"));
- ck_assert_int_eq(0, rsync_queue("G", "H"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("A", "B"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("C", "D"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("E", "F"));
+ ck_assert_int_eq(0, RSYNC_QUEUE("G", "H"));
wait_rsyncs(3, 2000);
/* 2k minus the 100 extra we slept during the previous wait_rsyncs() */
#include "mock.c"
#include "types/array.h"
#include "types/map.c"
+#include "types/url.c"
void
rpki_certificate_free(struct rpki_certificate *cert)
struct cache_mapping map;
struct rpki_certificate parent = { 0 };
- map.url = map.path = mapstr;
+ __URI_INIT(&map.url, mapstr);
+ map.path = mapstr;
ck_assert_int_eq(1, task_enqueue_rpp(&map, &parent));
}
{
struct validation_task *task;
task = task_dequeue(prev);
- ck_assert_str_eq(mapstr, task->u.ca->map.url);
+ ck_assert_uri(mapstr, &task->u.ca->map.url);
return task;
}
printf("th%d: Started.\n", thid);
while ((task = task_dequeue(task)) != NULL) {
- printf("- th%d: Dequeued '%s'\n", thid, task->u.ca->map.url);
+ printf("- th%d: Dequeued '%s'\n", thid, uri_str(&task->u.ca->map.url));
total_dequeued++;
if (certificate_traverse_mock(task->u.ca, thid) == EBUSY) {
printf("+ th%d: Requeuing '%s'\n",
- thid, task->u.ca->map.url);
+ thid, uri_str(&task->u.ca->map.url));
task_requeue_dormant(task);
task = NULL;
}
}
END_TEST
+#define ck_assert_origin(expected, s1, s2) \
+ do { \
+ __URI_INIT(&u1, s1); \
+ __URI_INIT(&u2, s2); \
+ ck_assert_int_eq(expected, uri_same_origin(&u1, &u2)); \
+ } while (0)
+
START_TEST(test_same_origin)
{
- ck_assert_int_eq(true, url_same_origin("https://a.b.c/d/e/f", "https://a.b.c/g/h/i"));
- ck_assert_int_eq(false, url_same_origin("https://a.b.cc/d/e/f", "https://a.b.c/g/h/i"));
- ck_assert_int_eq(false, url_same_origin("https://a.b.c/d/e/f", "https://a.b.cc/g/h/i"));
- ck_assert_int_eq(true, url_same_origin("https://a.b.c", "https://a.b.c"));
- ck_assert_int_eq(true, url_same_origin("https://a.b.c/", "https://a.b.c"));
- ck_assert_int_eq(true, url_same_origin("https://a.b.c", "https://a.b.c/"));
- ck_assert_int_eq(true, url_same_origin("https://", "https://"));
- ck_assert_int_eq(false, url_same_origin("https://", "https://a"));
- ck_assert_int_eq(false, url_same_origin("https://a", "https://b"));
+ struct uri u1, u2;
+
+ ck_assert_origin(true, "https://a.b.c/d/e/f", "https://a.b.c/g/h/i");
+ ck_assert_origin(false, "https://a.b.cc/d/e/f", "https://a.b.c/g/h/i");
+ ck_assert_origin(false, "https://a.b.c/d/e/f", "https://a.b.cc/g/h/i");
+ ck_assert_origin(true, "https://a.b.c", "https://a.b.c");
+ ck_assert_origin(true, "https://a.b.c/", "https://a.b.c");
+ ck_assert_origin(true, "https://a.b.c", "https://a.b.c/");
+ ck_assert_origin(true, "https://", "https://");
+ ck_assert_origin(false, "https://", "https://a");
+ ck_assert_origin(false, "https://a", "https://b");
/* Undefined, but manhandle the code anyway */
- ck_assert_int_eq(false, url_same_origin("", ""));
- ck_assert_int_eq(false, url_same_origin("ht", "ht"));
- ck_assert_int_eq(false, url_same_origin("https:", "https:"));
- ck_assert_int_eq(false, url_same_origin("https:/", "https:/"));
- ck_assert_int_eq(false, url_same_origin("https:/a", "https:/a"));
- ck_assert_int_eq(true, url_same_origin("https:/a/", "https:/a/"));
+ ck_assert_origin(false, "", "");
+ ck_assert_origin(false, "ht", "ht");
+ ck_assert_origin(false, "https:", "https:");
+ ck_assert_origin(false, "https:/", "https:/");
+ ck_assert_origin(false, "https:/a", "https:/a");
+ ck_assert_origin(true, "https:/a/", "https:/a/");
}
END_TEST