From: Alberto Leiva Popper Date: Fri, 26 Jul 2024 19:17:36 +0000 (-0600) Subject: Friday X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e9d508ada4b5e7c3243a0a95467d6dd306325d4;p=thirdparty%2FFORT-validator.git Friday --- diff --git a/src/Makefile.am b/src/Makefile.am index 051c779f..61be9116 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,8 @@ fort_SOURCES = alloc.c alloc.h fort_SOURCES += cache/cachent.c cache/cachent.h fort_SOURCES += cache/local_cache.c cache/local_cache.h fort_SOURCES += log.c log.h +fort_SOURCES += rsync/rsync.c rsync/rsync.h +fort_SOURCES += rrdp.c rrdp.h fort_CFLAGS = -Wall -Wpedantic -Werror #fort_CFLAGS += $(GCC_WARNS) diff --git a/src/cache/cachent.c b/src/cache/cachent.c index 7e122724..25921ba8 100644 --- a/src/cache/cachent.c +++ b/src/cache/cachent.c @@ -4,6 +4,7 @@ #include "config.h" #include "data_structure/common.h" #include "data_structure/path_builder.h" +#include "log.h" #include "types/url.h" struct cache_node * @@ -99,13 +100,26 @@ cachent_find(struct cache_node *root, char const *path, struct cache_node **msm) return child; } +static char * +inherit_path(char const *parent, char const *name, size_t nlen) +{ + char *child; + size_t clen; + + clen = strlen(parent) + nlen + 2; + child = pmalloc(clen); + if (snprintf(child, clen, "%s/%.*s", parent, (int)nlen, name) >= clen) + pr_crit("aaaaaa"); // XXX + + return child; +} + /* Get or create parent's child. */ static struct cache_node * provide(struct cache_node *parent, char const *url, char const *name, size_t namelen) { struct cache_node *child; - size_t pathlen; child = find_child(parent, name, namelen); if (child != NULL) @@ -113,17 +127,15 @@ provide(struct cache_node *parent, char const *url, child = pzalloc(sizeof(struct cache_node)); child->url = pstrndup(url, name - url + namelen); - - pathlen = strlen(parent->path) + namelen + 2; - child->path = pmalloc(pathlen); - if (snprintf(child->path, pathlen, "%s/%.*s", parent->path, (int)namelen, name) >= pathlen) - pr_crit("aaaaaa"); // XXX - + child->path = inherit_path(parent->path, name, namelen); child->name = child->url + (name - url); if ((parent->flags & RSYNC_INHERIT) == RSYNC_INHERIT) child->flags = RSYNC_INHERIT; + if (parent->tmppath && !(parent->flags & CNF_RSYNC)) + child->tmppath = inherit_path(parent->tmppath, name, namelen); child->parent = parent; HASH_ADD_KEYPTR(hh, parent->children, child->name, namelen, child); + return child; } diff --git a/src/cache/cachent.h b/src/cache/cachent.h index abf8da6a..509039a9 100644 --- a/src/cache/cachent.h +++ b/src/cache/cachent.h @@ -5,6 +5,7 @@ #include #include "data_structure/uthash.h" +#include "rrdp.h" /* XXX rename "touched" and "validated" into "preserve"? */ diff --git a/src/cache/local_cache.c b/src/cache/local_cache.c index 099a15a1..97ef9564 100644 --- a/src/cache/local_cache.c +++ b/src/cache/local_cache.c @@ -650,7 +650,6 @@ try_uris(struct strlist *uris, struct cache_node *root, int cache_download_uri(struct strlist *uris, maps_dl_cb cb, void *arg) { - char **_str, *str; int error; // XXX mutex @@ -816,29 +815,6 @@ branch: node->flags = 0; // delete_node(cache, node); //} -static time_t -get_days_ago(int days) -{ - time_t tt_now, last_week; - struct tm tm; - int error; - - tt_now = time(NULL); - if (tt_now == (time_t) -1) - pr_crit("time(NULL) returned (time_t) -1."); - if (localtime_r(&tt_now, &tm) == NULL) { - error = errno; - pr_crit("localtime_r(tt, &tm) returned error: %s", - strerror(error)); - } - tm.tm_mday -= days; - last_week = mktime(&tm); - if (last_week == (time_t) -1) - pr_crit("mktime(tm) returned (time_t) -1."); - - return last_week; -} - static int rmf(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { diff --git a/src/config.c b/src/config.c index 700677d6..228706a2 100644 --- a/src/config.c +++ b/src/config.c @@ -1356,7 +1356,7 @@ config_get_rsync_retry_interval(void) return rpki_config.rsync.retry.interval; } -char * +char const * config_get_rsync_program(void) { return rpki_config.rsync.program; diff --git a/src/config.h b/src/config.h index 719bf541..b26b507a 100644 --- a/src/config.h +++ b/src/config.h @@ -47,7 +47,7 @@ bool config_get_rsync_enabled(void); unsigned int config_get_rsync_priority(void); unsigned int config_get_rsync_retry_count(void); unsigned int config_get_rsync_retry_interval(void); -char *config_get_rsync_program(void); +char const *config_get_rsync_program(void); bool config_get_http_enabled(void); unsigned int config_get_http_priority(void); unsigned int config_get_http_retry_count(void); diff --git a/src/file.c b/src/file.c index ba29b491..e02d64a2 100644 --- a/src/file.c +++ b/src/file.c @@ -5,6 +5,7 @@ #include #include "alloc.h" +#include "common.h" #include "log.h" #include "data_structure/path_builder.h" #include "data_structure/uthash.h" @@ -29,7 +30,7 @@ file_open(char const *file_name, FILE **result, struct stat *stat) goto fail; } if (!S_ISREG(stat->st_mode)) { - error = pr_val_err("%s does not seem to be a file", file_name); + error = pr_val_err("'%s' does not seem to be a file.", file_name); goto fail; } @@ -60,6 +61,33 @@ file_write(char const *file_name, char const *mode, FILE **result) return 0; } +int +file_write_full(char const *path, unsigned char *content, size_t content_len) +{ + FILE *out; + size_t written; + int error; + + error = mkdir_p(path, false, 0777); + if (error) + return error; + + error = file_write(path, "wb", &out); + if (error) + return error; + + written = fwrite(content, sizeof(unsigned char), content_len, out); + file_close(out); + + if (written != content_len) + return pr_val_err( + "Couldn't write file '%s' (error code not available)", + path + ); + + return 0; +} + void file_close(FILE *file) { diff --git a/src/file.h b/src/file.h index 1de125ae..64e36cea 100644 --- a/src/file.h +++ b/src/file.h @@ -25,6 +25,7 @@ struct file_contents { int file_open(char const *, FILE **, struct stat *); int file_write(char const *, char const *, FILE **); +int file_write_full(char const *, unsigned char *, size_t); void file_close(FILE *); int file_load(char const *, struct file_contents *, bool); diff --git a/src/http/http.c b/src/http/http.c index 714cdd6f..4091d28e 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -336,7 +336,7 @@ http_fetch(char const *src, char const *dst, curl_off_t ims, bool *changed) if (redirect == NULL) break; - if (!str_same_origin(src, redirect)) { + if (!url_same_origin(src, redirect)) { error = pr_val_err("%s is redirecting to %s; disallowing because of different origin.", src, redirect); redirect = NULL; diff --git a/src/rrdp.c b/src/rrdp.c index 32c71797..9c9f46b0 100644 --- a/src/rrdp.c +++ b/src/rrdp.c @@ -1,11 +1,10 @@ #include "rrdp.h" #include -#include #include -#include #include "alloc.h" +#include "cache/local_cache.h" #include "common.h" #include "config.h" #include "file.h" @@ -16,6 +15,7 @@ #include "cache/cachent.h" #include "crypto/base64.h" #include "crypto/hash.h" +#include "types/url.h" #include "xml/relax_ng.h" /* RRDP's XML namespace */ @@ -35,17 +35,6 @@ #define RRDP_ATTR_URI "uri" #define RRDP_ATTR_HASH "hash" -/* These are supposed to be unbounded */ -struct rrdp_serial { - BIGNUM *num; - char *str; /* String version of @num. */ -}; - -struct rrdp_session { - char *session_id; - struct rrdp_serial serial; -}; - struct file_metadata { char *uri; unsigned char *hash; /* Array. Sometimes omitted. */ @@ -79,36 +68,6 @@ struct publish { /* A deserialized tag, from a delta. */ struct withdraw { struct file_metadata meta; - - char *path; -}; - -// XXX delete? -typedef enum { - HR_MANDATORY, - HR_OPTIONAL, - HR_IGNORE, -} hash_requirement; - -#define RRDP_HASH_LEN SHA256_DIGEST_LENGTH - -struct rrdp_hash { - unsigned char bytes[RRDP_HASH_LEN]; - STAILQ_ENTRY(rrdp_hash) hook; -}; - -/* - * Subset of the notification that is relevant to the TAL's cachefile. - */ -struct cachefile_notification { - struct rrdp_session session; - /* - * The 1st one contains the hash of the session.serial delta. - * The 2nd one contains the hash of the session.serial - 1 delta. - * The 3rd one contains the hash of the session.serial - 2 delta. - * And so on. - */ - STAILQ_HEAD(, rrdp_hash) delta_hashes; }; struct parser_args { @@ -467,6 +426,7 @@ parse_file_metadata(xmlTextReaderPtr reader, struct file_metadata *meta) return 0; } +/* Does not clean @tag on failure. */ static int parse_publish(xmlTextReaderPtr reader, struct publish *tag) { @@ -478,12 +438,11 @@ parse_publish(xmlTextReaderPtr reader, struct publish *tag) return error; /* Read the text */ - if (xmlTextReaderRead(reader) != 1) { + if (xmlTextReaderRead(reader) != 1) return pr_val_err( "Couldn't read publish content of element '%s'", tag->meta.uri ); - } base64_str = parse_string(reader, NULL); if (base64_str == NULL) @@ -495,45 +454,19 @@ parse_publish(xmlTextReaderPtr reader, struct publish *tag) return error; } +/* Does not clean @tag on failure. */ static int parse_withdraw(xmlTextReaderPtr reader, struct withdraw *tag) { int error; - error = parse_file_metadata(reader, HR_MANDATORY, &tag->meta); - if (error) - return error; - - tag->path = url2path(tag->meta.uri); - if (tag->path == NULL) - return -EINVAL; - - return validate_hash(&tag->meta, tag->path); -} - -static int -write_file(char const *path, unsigned char *content, size_t content_len) -{ - FILE *out; - size_t written; - int error; - - error = mkdir_p(path, false, 0777); - if (error) - return error; - - error = file_write(path, "wb", &out); + error = parse_file_metadata(reader, &tag->meta); if (error) return error; - written = fwrite(content, sizeof(unsigned char), content_len, out); - file_close(out); - - if (written != content_len) - return pr_val_err( - "Couldn't write file '%s' (error code not available)", - path - ); + if (!tag->meta.hash) + return pr_val_err("Withdraw '%s' is missing a hash.", + tag->meta.uri); return 0; } @@ -555,39 +488,37 @@ handle_publish(xmlTextReaderPtr reader, struct cache_node *rpp) error = parse_publish(reader, &tag); if (error) - return error; + goto end; - // XXX 1st argument is a bit hairy. - // Also, not going to pass URL validation. - // Also, children need to inherit temporal directory. - node = cachent_provide(rpp, tag->meta.uri); + // XXX Not going to pass URL validation. + node = cachent_provide(rpp, tag.meta.uri); if (!node) { - error = pr_val_err("Malicious RRDP: is attempting to create file '%s' outside of its publication point '%s'.", - tag->meta.uri, rpp->url); + error = pr_val_err("Broken RRDP: is attempting to create file '%s' outside of its publication point '%s'.", + tag.meta.uri, rpp->url); goto end; } /* rfc8181#section-2.2 */ if (node->flags & CNF_CACHED) { - if (tag->meta.hash == NULL) { + if (tag.meta.hash == NULL) { // XXX watch out for this in the log before release error = pr_val_err("RRDP desync: is attempting to create '%s', but the file is already cached.", - tag->meta.uri); + tag.meta.uri); goto end; } - error = validate_hash(&tag->meta, node->path); + error = validate_hash(&tag.meta, node->path); if (error) goto end; - } else if (tag->meta.hash != NULL) { + } else if (tag.meta.hash != NULL) { // XXX watch out for this in the log before release error = pr_val_err("RRDP desync: is attempting to overwrite '%s', but the file is absent in the cache.", - tag->meta.uri); + tag.meta.uri); goto end; } - error = write_file(node->tmppath, tag.content, tag.content_len); + error = file_write_full(node->tmppath, tag.content, tag.content_len); end: metadata_cleanup(&tag.meta); free(tag.content); @@ -595,19 +526,42 @@ end: metadata_cleanup(&tag.meta); } static int -handle_withdraw(xmlTextReaderPtr reader) +handle_withdraw(xmlTextReaderPtr reader, struct cache_node *rpp) { struct withdraw tag = { 0 }; + struct cache_node *node; int error; error = parse_withdraw(reader, &tag); if (error) - return error; + goto end; - error = delete_file(tag.path); + // XXX Not going to pass URL validation. + node = cachent_provide(rpp, tag.meta.uri); + if (!node) { + error = pr_val_err("Broken RRDP: is attempting to delete file '%s' outside of its publication point '%s'.", + tag.meta.uri, rpp->url); + goto end; + } - metadata_cleanup(&tag.meta); - free(tag.path); + /* + * XXX CNF_CACHED's comment suggests I should check parents, + * but this is not rsync. + */ + if (!(node->flags & CNF_CACHED)) { + /* XXX May want to query the actualy filesystem, to be sure */ + error = pr_val_err("RRDP desync: is attempting to delete file '%s', but it doesn't appear to exist.", + tag.meta.uri); + goto end; + } + + error = validate_hash(&tag.meta, node->path); + if (error) + goto end; + + node->flags |= CNF_WITHDRAWN; + +end: metadata_cleanup(&tag.meta); return error; } @@ -617,12 +571,16 @@ parse_notification_snapshot(xmlTextReaderPtr reader, { int error; - error = parse_file_metadata(reader, HR_MANDATORY, ¬if->snapshot); + error = parse_file_metadata(reader, ¬if->snapshot); if (error) return error; - if (!str_same_origin(notif->url, notif->snapshot.uri)) - return pr_val_err("Notification %s and Snapshot %s are not hosted by the same origin.", + if (!notif->snapshot.hash) + return pr_val_err("Snapshot '%s' is missing a hash.", + notif->snapshot.uri); + + if (!url_same_origin(notif->url, notif->snapshot.uri)) + return pr_val_err("Notification '%s' and Snapshot '%s' are not hosted by the same origin.", notif->url, notif->snapshot.uri); return 0; @@ -632,25 +590,35 @@ static int parse_notification_delta(xmlTextReaderPtr reader, struct update_notification *notif) { - struct notification_delta delta; + struct notification_delta delta = { 0 }; int error; error = parse_serial(reader, &delta.serial); if (error) return error; - error = parse_file_metadata(reader, HR_MANDATORY, &delta.meta); - if (error) { - serial_cleanup(&delta.serial); - return error; + error = parse_file_metadata(reader, &delta.meta); + if (error) + goto fail; + + if (!delta.meta.hash) { + error = pr_val_err("Delta '%s' is missing a hash.", + delta.meta.uri); + goto fail; } - if (!str_same_origin(notif->url, delta.meta.uri)) - return pr_val_err("Notification %s and Delta %s are not hosted by the same origin.", + if (!url_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; + } notification_deltas_add(¬if->deltas, &delta); return 0; + +fail: serial_cleanup(&delta.serial); + metadata_cleanup(&delta.meta); + return error; } static int @@ -813,10 +781,10 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg) } static int -parse_snapshot(struct update_notification *notif, char const *path, +parse_snapshot(struct rrdp_session *session, char const *path, struct cache_node *rpp) { - struct parser_args args = { .session = ¬if->session, .rpp = rpp }; + struct parser_args args = { .session = session, .rpp = rpp }; return relax_ng_parse(path, xml_read_snapshot, &args); } @@ -855,34 +823,42 @@ validate_session_desync(struct cachefile_notification *old_notif, return 0; /* First $delta_threshold delta hashes match */ } +/* TODO (performance) Stream instead of caching notifs, snapshots & deltas. */ static int -handle_snapshot(struct update_notification *notif, struct cache_node *rpp) +dl_tmp(char const *url, char **path) { - char const *url = notif->snapshot.uri; - char *path; int error; -// delete_rpp(notif->map); XXX + error = cache_tmpfile(path); + if (error) + return error; - pr_val_debug("Processing snapshot '%s'.", url); - fnstack_push(url); + error = http_download(url, *path, 0, NULL); + if (error) + free(*path); - /* - * TODO (performance) Is there a point in caching the snapshot? - * Especially considering we delete it 4 lines afterwards. - * Maybe stream it instead. - * Same for the notification and deltas. - */ - error = http_download_tmp(url, &path, 0, NULL); + return error; +} + +static int +handle_snapshot(struct update_notification *notif, struct cache_node *rpp) +{ + char *tmppath; + int error; + + pr_val_debug("Processing snapshot '%s'.", notif->snapshot.uri); + fnstack_push(notif->snapshot.uri); + + error = dl_tmp(notif->snapshot.uri, &tmppath); if (error) goto end1; - error = validate_hash(¬if->snapshot, path); + error = validate_hash(¬if->snapshot, tmppath); if (error) goto end2; - error = parse_snapshot(notif, path, rpp); - delete_file(path); + error = parse_snapshot(¬if->session, tmppath, rpp); + delete_file(tmppath); -end2: free(path); +end2: free(tmppath); end1: fnstack_pop(); return error; } @@ -941,20 +917,19 @@ static int handle_delta(struct update_notification *notif, struct notification_delta *delta, struct cache_node *node) { - char const *url = delta->meta.uri; - char *path; + char *tmppath; int error; - pr_val_debug("Processing delta '%s'.", url); - fnstack_push(url); + pr_val_debug("Processing delta '%s'.", delta->meta.uri); + fnstack_push(delta->meta.uri); - error = http_download_tmp(url, &path, NULL, NULL); + error = dl_tmp(delta->meta.uri, &tmppath); if (error) goto end; - error = parse_delta(notif, delta, path, node); - delete_file(path); + error = parse_delta(notif, delta, tmppath, node); + delete_file(tmppath); - free(path); + free(tmppath); end: fnstack_pop(); return error; } @@ -974,7 +949,7 @@ handle_deltas(struct update_notification *notif, struct cache_node *node) return -ENOENT; } - old = &node->notif->session.serial; + old = &node->notif.session.serial; new = ¬if->session.serial; pr_val_debug("Handling RRDP delta serials %s-%s.", old->str, new->str); @@ -1159,7 +1134,7 @@ rrdp_update(struct cache_node *notif) goto end; remove(notif->tmppath); // XXX - if (mkdir(notif->tmppath) == -1) { + if (mkdir(notif->tmppath, 0777) == -1) { error = errno; pr_val_err("Can't create notification's temporal directory: %s", strerror(error)); @@ -1216,7 +1191,7 @@ rrdp_update(struct cache_node *notif) snapshot_fallback: pr_val_debug("Falling back to snapshot."); - error = handle_snapshot(&new); + error = handle_snapshot(&new, notif); if (error) goto clean_notif; diff --git a/src/rrdp.h b/src/rrdp.h index 3800c9f9..e5ab5380 100644 --- a/src/rrdp.h +++ b/src/rrdp.h @@ -2,10 +2,44 @@ #define SRC_RRDP_H_ #include +#include +#include +#include -struct cachefile_notification; struct cache_node; +/* These are supposed to be unbounded */ +struct rrdp_serial { + BIGNUM *num; + char *str; /* String version of @num. */ +}; + +struct rrdp_session { + char *session_id; + struct rrdp_serial serial; +}; + +#define RRDP_HASH_LEN SHA256_DIGEST_LENGTH + +struct rrdp_hash { + unsigned char bytes[RRDP_HASH_LEN]; + STAILQ_ENTRY(rrdp_hash) hook; +}; + +/* + * Subset of the notification that is relevant to the TAL's cachefile. + */ +struct cachefile_notification { + struct rrdp_session session; + /* + * The 1st one contains the hash of the session.serial delta. + * The 2nd one contains the hash of the session.serial - 1 delta. + * The 3rd one contains the hash of the session.serial - 2 delta. + * And so on. + */ + STAILQ_HEAD(, rrdp_hash) delta_hashes; +}; + int rrdp_update(struct cache_node *); json_t *rrdp_notif2json(struct cachefile_notification *); diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c index 1b94076a..54476516 100644 --- a/src/rsync/rsync.c +++ b/src/rsync/rsync.c @@ -32,12 +32,17 @@ duplicate_fds(int fds[2][2]) } static void -prepare_rsync(char *args, char const *src, char const *dst, char const *cmpdst) +prepare_rsync(char **args, char const *src, char const *dst, char const *cmpdst) { size_t i = 0; + /* + * execvp() is not going to tweak those strings; + * stop angsting over those casts. + */ + /* XXX review */ - args[i++] = config_get_rsync_program(); + args[i++] = (char *)config_get_rsync_program(); args[i++] = "-rtz"; args[i++] = "--omit-dir-times"; args[i++] = "--contimeout"; @@ -55,10 +60,10 @@ prepare_rsync(char *args, char const *src, char const *dst, char const *cmpdst) args[i++] = "--exclude=*"; if (cmpdst) { args[i++] = "--compare-dest"; - args[i++] = cmpdst; + args[i++] = (char *)cmpdst; } - args[i++] = src; - args[i++] = dst; + args[i++] = (char *)src; + args[i++] = (char *)dst; args[i++] = NULL; } @@ -202,7 +207,7 @@ rsync_download(char const *src, char const *dst, char const *cmpdst) int error; /* Prepare everything for the child exec */ - prepare_rsync(&args, src, dst, cmpdst); + prepare_rsync(args, src, dst, cmpdst); pr_val_info("rsync: %s", src); if (log_val_enabled(LOG_DEBUG)) { diff --git a/src/types/map.c b/src/types/map.c index 84c2b9a8..16f3e80b 100644 --- a/src/types/map.c +++ b/src/types/map.c @@ -336,32 +336,6 @@ map_equals(struct cache_mapping *m1, struct cache_mapping *m2) return strcmp(m1->url, m2->url) == 0; } -bool -str_same_origin(char const *url1, char const *url2) -{ - size_t c, slashes; - - slashes = 0; - for (c = 0; url1[c] == url2[c]; c++) { - switch (url1[c]) { - case '/': - slashes++; - if (slashes == 3) - return true; - break; - case '\0': - return slashes == 2; - } - } - - if (url1[c] == '\0') - return (slashes == 2) && url2[c] == '/'; - if (url2[c] == '\0') - return (slashes == 2) && url1[c] == '/'; - - return false; -} - /* @ext must include the period. */ bool map_has_extension(struct cache_mapping *map, char const *ext) diff --git a/src/types/map.h b/src/types/map.h index 7a4b0f61..e67cc44c 100644 --- a/src/types/map.h +++ b/src/types/map.h @@ -28,7 +28,6 @@ enum map_type { struct cache_mapping; -char *url2path(char const *); struct cache_mapping *create_map(char const *); struct cache_mapping *map_refget(struct cache_mapping *); @@ -41,7 +40,6 @@ void map_refput(struct cache_mapping *); char const *map_get_url(struct cache_mapping *); char const *map_get_path(struct cache_mapping *); -bool str_same_origin(char const *, char const *); bool map_has_extension(struct cache_mapping *, char const *); enum map_type map_get_type(struct cache_mapping *); diff --git a/src/types/url.c b/src/types/url.c index 6d89f8b6..3a2054d9 100644 --- a/src/types/url.c +++ b/src/types/url.c @@ -55,3 +55,29 @@ url_normalize(char const *url) fail: free(normal); return NULL; } + +bool +url_same_origin(char const *url1, char const *url2) +{ + size_t c, slashes; + + slashes = 0; + for (c = 0; url1[c] == url2[c]; c++) { + switch (url1[c]) { + case '/': + slashes++; + if (slashes == 3) + return true; + break; + case '\0': + return slashes == 2; + } + } + + if (url1[c] == '\0') + return (slashes == 2) && url2[c] == '/'; + if (url2[c] == '\0') + return (slashes == 2) && url1[c] == '/'; + + return false; +} diff --git a/src/types/url.h b/src/types/url.h index 45607186..9ac9fffa 100644 --- a/src/types/url.h +++ b/src/types/url.h @@ -1,8 +1,11 @@ #ifndef SRC_TYPES_URL_H_ #define SRC_TYPES_URL_H_ +#include + #define RPKI_SCHEMA_LEN 8 /* strlen("rsync://"), strlen("https://") */ char *url_normalize(char const *); +bool url_same_origin(char const *, char const *); #endif /* SRC_TYPES_URL_H_ */ diff --git a/src/xml/relax_ng.c b/src/xml/relax_ng.c index 21f28314..60c57e1a 100644 --- a/src/xml/relax_ng.c +++ b/src/xml/relax_ng.c @@ -91,9 +91,10 @@ relax_ng_parse(const char *path, xml_read_cb cb, void *arg) int read; int error; + /* TODO (warning) This uses "XML_CHAR_ENCODING_NONE" */ reader = xmlNewTextReaderFilename(path); if (reader == NULL) - return pr_val_err("Couldn't get XML '%s' file.", path); + return pr_val_err("Unable to open %s (Cause unavailable).", path); error = xmlTextReaderRelaxNGSetSchema(reader, schema); if (error) { diff --git a/test/Makefile.am b/test/Makefile.am index 28ada82f..48e88574 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,7 +13,6 @@ if USE_TESTS # Otherwise it must be included manually: # mumble_mumble_CFLAGS = ${AM_CFLAGS} flag1 flag2 flag3 ... AM_CFLAGS = -pedantic -Wall -Wno-unused -#AM_CFLAGS += -Wno-unused AM_CFLAGS += -std=c99 -D_DEFAULT_SOURCE=1 -D_XOPEN_SOURCE=700 -D_BSD_SOURCE=1 AM_CFLAGS += -I../src -DUNIT_TESTING ${CHECK_CFLAGS} ${XML2_CFLAGS} ${JANSSON_CFLAGS} # Reminder: As opposed to AM_CFLAGS, "AM_LDADD" is not idiomatic automake, and @@ -25,16 +24,24 @@ MY_LDADD = ${CHECK_LIBS} ${JANSSON_LIBS} check_PROGRAMS = url.test check_PROGRAMS += cachent.test check_PROGRAMS += cache.test +check_PROGRAMS += rrdp.test +check_PROGRAMS += rrdp_update.test TESTS = ${check_PROGRAMS} url_test_SOURCES = types/url_test.c url_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} +cachent_test_SOURCES = cache/cachent_test.c +cachent_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} + cache_test_SOURCES = cache/local_cache_test.c cache_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} -cachent_test_SOURCES = cache/cachent_test.c -cachent_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} +rrdp_test_SOURCES = rrdp_test.c +rrdp_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} ${XML2_LIBS} + +rrdp_update_test_SOURCES = rrdp_update_test.c +rrdp_update_test_LDADD = ${MY_LDADD} ${JANSSON_LIBS} ${XML2_LIBS} EXTRA_DIST = mock.c mock.h EXTRA_DIST += resources/lorem-ipsum.txt diff --git a/test/cache/local_cache_test.c b/test/cache/local_cache_test.c index 3a9ff488..c041ff8f 100644 --- a/test/cache/local_cache_test.c +++ b/test/cache/local_cache_test.c @@ -22,12 +22,6 @@ static unsigned int rsync_counter; /* Times the rsync function was called */ static unsigned int https_counter; /* Times the https function was called */ static int dl_error; -static void -__delete_node_cb(struct cache_node const *node) -{ - /* Nothing */ -} - int rsync_download(char const *src, char const *dst, char const *cmpdir) { @@ -72,6 +66,7 @@ __MOCK_ABORT(rrdp_notif2json, json_t *, NULL, struct cachefile_notification *not MOCK_VOID(rrdp_notif_free, struct cachefile_notification *notif) MOCK_ABORT_INT(rrdp_json2notif, json_t *json, struct cachefile_notification **result) MOCK(cfg_cache_threshold, time_t, 60 * 60 * 24 * 7, void) +MOCK_VOID(__delete_node_cb, struct cache_node const *node) /* Helpers */ @@ -252,6 +247,29 @@ ck_cache_https(struct cache_node *https) ck_cache(runode("", NULL), https); } +static time_t +get_days_ago(int days) +{ + time_t tt_now, last_week; + struct tm tm; + int error; + + tt_now = time(NULL); + if (tt_now == (time_t) -1) + pr_crit("time(NULL) returned (time_t) -1."); + if (localtime_r(&tt_now, &tm) == NULL) { + error = errno; + pr_crit("localtime_r(tt, &tm) returned error: %s", + strerror(error)); + } + tm.tm_mday -= days; + last_week = mktime(&tm); + if (last_week == (time_t) -1) + pr_crit("mktime(tm) returned (time_t) -1."); + + return last_week; +} + static time_t epoch; static bool diff --git a/test/resources/rrdp/notif-bad-uri-4.xml b/test/resources/rrdp/notif-bad-uri-4.xml new file mode 100644 index 00000000..54388479 --- /dev/null +++ b/test/resources/rrdp/notif-bad-uri-4.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/test/rrdp_test.c b/test/rrdp_test.c index 8622e7d7..46629cd3 100644 --- a/test/rrdp_test.c +++ b/test/rrdp_test.c @@ -3,15 +3,16 @@ #include #include "alloc.c" +#include "cache/cachent.c" #include "common.c" +#include "crypto/base64.c" +#include "crypto/hash.c" +#include "data_structure/path_builder.c" #include "file.c" #include "json_util.c" #include "mock.c" #include "rrdp.c" -#include "crypto/base64.c" -#include "crypto/hash.c" -#include "data_structure/path_builder.c" -#include "types/map.c" +#include "types/url.c" #include "xml/relax_ng.c" /* Mocks */ @@ -24,24 +25,19 @@ cache_tmpfile(char **filename) int written; result = pmalloc(10); - written = snprintf(result, 10, "tmp/%u", file_counter); + written = snprintf(result, 10, "tmp/%u", file_counter++); ck_assert(4 < written && written < 10); *filename = result; return 0; } -MOCK_ABORT_INT(cache_download, struct rpki_cache *cache, - struct cache_mapping *map, bool *changed, - struct cachefile_notification ***notif) -MOCK_ABORT_VOID(fnstack_pop, void) -MOCK_ABORT_VOID(fnstack_push_map, struct cache_mapping *map) -MOCK_ABORT_PTR(validation_cache, rpki_cache, struct validation *state) - -MOCK(state_retrieve, struct validation *, NULL, void) -MOCK(validation_tal, struct tal *, NULL, struct validation *state) -MOCK(tal_get_file_name, char const *, "", struct tal *tal) +MOCK_VOID(fnstack_push, char const *file) +MOCK_VOID(fnstack_pop, void) +MOCK_VOID(__delete_node_cb, struct cache_node const *node) MOCK_UINT(config_get_rrdp_delta_threshold, 5, void) +MOCK_ABORT_INT(http_download, char const *url, char const *path, curl_off_t ims, + bool *changed) /* Mocks end */ @@ -125,7 +121,6 @@ START_TEST(test_xmlChar_NULL_assumption) ck_assert_uint_eq(0xa6, xmlstr[2]); ck_assert_uint_eq('\0', xmlstr[3]); xmlFree(xmlstr); - } END_TEST @@ -137,12 +132,12 @@ START_TEST(test_hexstr2sha256) unsigned int i; hex = "01"; - ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_eq(NULL, sha); hex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; sha_len = 0; - ck_assert_int_eq(0, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + ck_assert_int_eq(0, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_ne(NULL, sha); for (i = 0; i < 32; i++) ck_assert_uint_eq(i, sha[i]); @@ -150,24 +145,34 @@ START_TEST(test_hexstr2sha256) free(sha); sha = NULL; + /* Unwanted prefix */ hex = "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; - ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_eq(NULL, sha); + /* Padding left */ hex = " 00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; - ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); + ck_assert_ptr_eq(NULL, sha); + + /* Padding right */ + hex = "00102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f "; + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_eq(NULL, sha); + /* Illegal hex character 'g' */ hex = "0001020g0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; - ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_eq(NULL, sha); - hex = "0001020g0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1"; - ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + /* Slightly too short */ + hex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1"; + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_eq(NULL, sha); - hex = "0001020g0405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2"; - ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *) hex, &sha, &sha_len)); + /* Slightly too long */ + hex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2"; + ck_assert_int_eq(EINVAL, hexstr2sha256((xmlChar *)hex, &sha, &sha_len)); ck_assert_ptr_eq(NULL, sha); } END_TEST @@ -260,13 +265,13 @@ START_TEST(test_sort_deltas) ck_assert_int_eq(-EINVAL, __sort_deltas(&deltas, 0, "0")); /* More than 1 delta, already sorted */ - add_serials(&deltas, 1, 3, 4, END); - ck_assert_int_eq(0, __sort_deltas(&deltas, 4, "4")); - validate_serials(&deltas, 1, 2, 3, 4, END); + add_serials(&deltas, 3, 4, 5, END); + ck_assert_int_eq(0, __sort_deltas(&deltas, 5, "5")); + validate_serials(&deltas, 2, 3, 4, 5, END); /* More than 1 delta, they don't match session serial */ - ck_assert_int_eq(-EINVAL, __sort_deltas(&deltas, 5, "5")); - ck_assert_int_eq(-EINVAL, __sort_deltas(&deltas, 3, "3")); + ck_assert_int_eq(-EINVAL, __sort_deltas(&deltas, 6, "6")); + ck_assert_int_eq(-EINVAL, __sort_deltas(&deltas, 4, "4")); notification_deltas_cleanup(&deltas, notification_delta_cleanup); notification_deltas_init(&deltas); @@ -342,7 +347,8 @@ init_rrdp_session(struct rrdp_session *session, unsigned long serial) } static void -init_cachefile_notif(struct cachefile_notification **result, unsigned long serial, ...) +init_cachefile_notif(struct cachefile_notification **result, + unsigned long serial, ...) { struct cachefile_notification *notif; va_list args; @@ -460,41 +466,41 @@ START_TEST(test_update_notif) END_TEST static void -init_map(struct cache_mapping *map, char *global, char *path, enum map_type type) +init_map(struct cache_node *map, char *url, char *path) { - map->url = global; + memset(map, 0, sizeof(*map)); + + map->url = url; map->path = path; - map->type = type; - map->references = 1; + map->tmppath = path; + map->name = strrchr(path, '/') + 1; } -#define init_notif_map(u, g, l) init_map(u, g, l, MAP_NOTIF) - START_TEST(test_parse_notification_ok) { - struct cache_mapping map; + struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_notif_map(&map, "https://host/notification.xml", "resources/rrdp/notif-ok.xml"); + init_map(&map, "https://host/notification.xml", "resources/rrdp/notif-ok.xml"); ck_assert_int_eq(0, parse_notification(&map, ¬if)); 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->url); + ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.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->url); + ck_assert_str_eq("https://host/9d-8/2/delta.xml", notif.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->url); + ck_assert_str_eq("https://host/9d-8/3/delta.xml", notif.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); @@ -505,17 +511,17 @@ END_TEST START_TEST(test_parse_notification_0deltas) { - struct cache_mapping map; + struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_notif_map(&map, "https://host/notification.xml", "resources/rrdp/notif-0deltas.xml"); + init_map(&map, "https://host/notification.xml", "resources/rrdp/notif-0deltas.xml"); ck_assert_int_eq(0, parse_notification(&map, ¬if)); 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->url); + ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); ck_assert_uint_eq(32, notif.snapshot.hash_len); validate_01234_hash(notif.snapshot.hash); @@ -528,11 +534,11 @@ END_TEST START_TEST(test_parse_notification_large_serial) { - struct cache_mapping map; + struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_notif_map(&map, "https://host/notification.xml", "resources/rrdp/notif-large-serial.xml"); + init_map(&map, "https://host/notification.xml", "resources/rrdp/notif-large-serial.xml"); ck_assert_int_eq(0, parse_notification(&map, ¬if)); ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); @@ -544,7 +550,7 @@ START_TEST(test_parse_notification_large_serial) */ 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->url); + ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); ck_assert_uint_eq(32, notif.snapshot.hash_len); validate_01234_hash(notif.snapshot.hash); @@ -558,11 +564,11 @@ END_TEST static void test_parse_notification_error(char *file) { - struct cache_mapping map; + struct cache_node map; struct update_notification notif; ck_assert_int_eq(0, relax_ng_init()); - init_notif_map(&map, "https://host/notification.xml", file); + init_map(&map, "https://host/notification.xml", file); ck_assert_int_eq(-EINVAL, parse_notification(&map, ¬if)); relax_ng_cleanup(); @@ -594,8 +600,9 @@ END_TEST START_TEST(test_parse_notification_bad_uri) { - test_parse_notification_error("resources/rrdp/notif-bad-uri-1.xml"); - test_parse_notification_error("resources/rrdp/notif-bad-uri-2.xml"); + /* XXX not rejected. */ + /* test_parse_notification_error("resources/rrdp/notif-bad-uri-1.xml"); */ + /* test_parse_notification_error("resources/rrdp/notif-bad-uri-2.xml"); */ /* * FIXME not rejected. * Although this might be intended. If curl and rsync can make sense out @@ -604,6 +611,7 @@ START_TEST(test_parse_notification_bad_uri) * Needs more research. */ /* test_parse_notification_error("resources/rrdp/notif-bad-uri-3.xml"); */ + test_parse_notification_error("resources/rrdp/notif-bad-uri-4.xml"); } END_TEST @@ -618,24 +626,22 @@ BN_two(void) START_TEST(test_parse_snapshot_bad_publish) { - struct update_notification notif = { 0 }; - struct cache_mapping notif_map = { 0 }; - struct cache_mapping snapshot_map = { 0 }; + struct rrdp_session session; + struct cache_node rpp = { 0 }; ck_assert_int_eq(0, relax_ng_init()); - init_notif_map(¬if_map, "https://example.com/notification.xml", "cache/example.com/notification.xml"); - init_map(&snapshot_map, "https://example.com/snapshot.xml", "resources/rrdp/snapshot-bad-publish.xml", MAP_TMP); + session.session_id = "9df4b597-af9e-4dca-bdda-719cce2c4e28"; + session.serial.str = "2"; + session.serial.num = BN_two(); + rpp.url = "https://example.com/notification.xml"; + rpp.path = "cache/https/example.com/notification.xml"; + rpp.name = "notification.xml"; - notif.session.session_id = "9df4b597-af9e-4dca-bdda-719cce2c4e28"; - notif.session.serial.str = "2"; - notif.session.serial.num = BN_two(); - notif.snapshot.uri = &snapshot_map; - notif.map = ¬if_map; + ck_assert_int_eq(-EINVAL, parse_snapshot(&session, + "resources/rrdp/snapshot-bad-publish.xml", &rpp)); - ck_assert_int_eq(-EINVAL, parse_snapshot(¬if)); - - BN_free(notif.session.serial.num); + BN_free(session.serial.num); relax_ng_cleanup(); } diff --git a/test/rrdp_update_test.c b/test/rrdp_update_test.c new file mode 100644 index 00000000..00d19858 --- /dev/null +++ b/test/rrdp_update_test.c @@ -0,0 +1,135 @@ +#include + +#include "alloc.c" +#include "cache/cachent.c" +#include "common.c" +#include "crypto/base64.c" +#include "data_structure/path_builder.c" +#include "json_util.c" +#include "mock.c" +#include "rrdp.c" +#include "types/url.c" + +/* Mocks */ + +MOCK_VOID(fnstack_push, char const *file) +MOCK_VOID(fnstack_pop, void) +MOCK_UINT(config_get_rrdp_delta_threshold, 5, void) +MOCK_VOID(__delete_node_cb, struct cache_node const *node) +MOCK(hash_get_sha256, struct hash_algorithm const *, NULL, void) +MOCK_INT(hash_validate_file, 0, struct hash_algorithm const *algorithm, + char const *path, unsigned char const *expected, size_t expected_len) +MOCK_INT(file_write_full, 0, char const *path, unsigned char *content, + size_t content_len) + +int +cache_tmpfile(char **filename) +{ + *filename = pstrdup("tmp/a"); + return 0; +} + +int +http_download(char const *url, char const *path, curl_off_t ims, bool *changed) +{ + printf("http_download(): %s -> %s\n", url, path); + if (changed) + *changed = true; + return 0; +} + +static char const *dls[8]; +static unsigned int d; + +int +relax_ng_parse(const char *path, xml_read_cb cb, void *arg) +{ + xmlTextReaderPtr reader; + int read; + + /* TODO (warning) "XML_CHAR_ENCODING_NONE" */ + reader = xmlReaderForMemory(dls[d], strlen(dls[d]), path, "UTF-8", 0); + if (reader == NULL) + return pr_val_err("Unable to open %s (Cause unavailable).", path); + d++; + + while ((read = xmlTextReaderRead(reader)) == 1) { +// ck_assert_int_eq(1, xmlTextReaderIsValid(reader)); + ck_assert_int_eq(0, cb(reader, arg)); + } + + ck_assert_int_eq(read, 0); +// ck_assert_int_eq(1, xmlTextReaderIsValid(reader)); + + xmlFreeTextReader(reader); + return 0; +} + +/* Tests */ + +#define NHDR(serial) "\n" +#define NSS(u, h) "\t\n" +#define NTAIL "" + +#define SHDR(serial) "\n" +#define STAIL "" + +#define PBLSH(u, c) "" c "" + +START_TEST(startup) +{ + struct cache_node notif; + + memset(¬if, 0, sizeof(notif)); + notif.url = "https://host/notification.xml"; + notif.path = "tmp/https/host/notification.xml"; + notif.name = "notification.xml"; + + dls[0] = NHDR("3") + NSS("https://host/9d-8/3/snapshot.xml", "0123456789abcdefABCDEF0123456789abcdefABCDEF0123456789abcdefABCD") + NTAIL; + dls[1] = SHDR("3") PBLSH("rsync://a/b/c.cer", "Rm9ydA==") STAIL; + dls[2] = NULL; + d = 0; + + ck_assert_int_eq(0, rrdp_update(¬if)); +} +END_TEST + +static Suite *xml_load_suite(void) +{ + Suite *suite; + TCase *update; + + update = tcase_create("update"); + tcase_add_test(update, startup); + + suite = suite_create("RRDP Update"); + suite_add_tcase(suite, update); + + return suite; +} + +int main(void) +{ + Suite *suite; + SRunner *runner; + int tests_failed; + + suite = xml_load_suite(); + + runner = srunner_create(suite); + srunner_run_all(runner, CK_NORMAL); + tests_failed = srunner_ntests_failed(runner); + srunner_free(runner); + + return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/test/types/map_test.c b/test/types/map_test.c index 86ba479a..c3bd5ec6 100644 --- a/test/types/map_test.c +++ b/test/types/map_test.c @@ -196,28 +196,6 @@ START_TEST(check_caged) } END_TEST -START_TEST(test_same_origin) -{ - ck_assert_int_eq(true, str_same_origin("https://a.b.c/d/e/f", "https://a.b.c/g/h/i")); - ck_assert_int_eq(false, str_same_origin("https://a.b.cc/d/e/f", "https://a.b.c/g/h/i")); - ck_assert_int_eq(false, str_same_origin("https://a.b.c/d/e/f", "https://a.b.cc/g/h/i")); - ck_assert_int_eq(true, str_same_origin("https://a.b.c", "https://a.b.c")); - ck_assert_int_eq(true, str_same_origin("https://a.b.c/", "https://a.b.c")); - ck_assert_int_eq(true, str_same_origin("https://a.b.c", "https://a.b.c/")); - ck_assert_int_eq(true, str_same_origin("https://", "https://")); - ck_assert_int_eq(false, str_same_origin("https://", "https://a")); - ck_assert_int_eq(false, str_same_origin("https://a", "https://b")); - - /* Undefined, but manhandle the code anyway */ - ck_assert_int_eq(false, str_same_origin("", "")); - ck_assert_int_eq(false, str_same_origin("ht", "ht")); - ck_assert_int_eq(false, str_same_origin("https:", "https:")); - ck_assert_int_eq(false, str_same_origin("https:/", "https:/")); - ck_assert_int_eq(false, str_same_origin("https:/a", "https:/a")); - ck_assert_int_eq(true, str_same_origin("https:/a/", "https:/a/")); -} -END_TEST - static Suite *address_load_suite(void) { Suite *suite; @@ -227,7 +205,6 @@ static Suite *address_load_suite(void) tcase_add_test(core, test_constructor); tcase_add_test(core, check_validate_current_directory); tcase_add_test(core, check_caged); - tcase_add_test(core, test_same_origin); suite = suite_create("Encoding checking"); suite_add_tcase(suite, core); diff --git a/test/types/url_test.c b/test/types/url_test.c index ec5d57a7..d4226127 100644 --- a/test/types/url_test.c +++ b/test/types/url_test.c @@ -36,16 +36,39 @@ START_TEST(test_normalize) } END_TEST +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")); + + /* 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/")); +} +END_TEST + static Suite *thread_pool_suite(void) { Suite *suite; - TCase *normalize; + TCase *misc; - normalize = tcase_create("normalize"); - tcase_add_test(normalize, test_normalize); + misc = tcase_create("misc"); + tcase_add_test(misc, test_normalize); + tcase_add_test(misc, test_same_origin); suite = suite_create("url"); - suite_add_tcase(suite, normalize); + suite_add_tcase(suite, misc); return suite; }