From 9de96c678417b8e869b9f01756e3699dd8b27f4e Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 29 Dec 2021 15:43:56 -0800 Subject: [PATCH] ... --- Makefile.am | 4 + inc/rss.h | 5 ++ src/feed.c | 2 +- src/meta.c | 37 ++++++--- src/rss/free.c | 19 +++++ src/rss/init.c | 31 +++++++ test/unit/Makefile.am | 15 +++- test/unit/meta.tests.c | 70 ++++++++++++++++ test/unit/rss.tests.c | 178 +++++++++++++++++++++++++---------------- test/unit/test_utils.c | 2 + test/unit/test_utils.h | 4 + 11 files changed, 285 insertions(+), 82 deletions(-) create mode 100644 src/rss/free.c create mode 100644 src/rss/init.c create mode 100644 test/unit/meta.tests.c diff --git a/Makefile.am b/Makefile.am index 4480da7..1442513 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,6 +28,7 @@ seederd_SOURCES = \ src/init.c \ src/log.c \ src/main.c \ + src/meta.c \ src/opt/config.c \ src/opt/env.c \ src/opt/filter.c \ @@ -39,8 +40,10 @@ seederd_SOURCES = \ src/opt/worker.c \ src/rss/entry.c \ src/rss/footer.c \ + src/rss/free.c \ src/rss/header.c \ src/rss/info.c \ + src/rss/init.c \ src/server/start.c \ src/session.c \ src/setup.c \ @@ -70,6 +73,7 @@ seederd_SOURCES += \ inc/init.h \ inc/log.h \ inc/main.h \ + inc/meta.h \ inc/opt.h \ inc/rss.h \ inc/server.h \ diff --git a/inc/rss.h b/inc/rss.h index 848b320..f2e27d1 100644 --- a/inc/rss.h +++ b/inc/rss.h @@ -2,6 +2,7 @@ #define __RSS_H_ #include +#include #include #include @@ -56,7 +57,11 @@ struct rss_entry { #define RSS_DEFAULT_ENTRY_DESCRIPTION "no description" #define RSS_DEFAULT_LANGUAGE "en-us" +void rss_channel_info_free(struct rss_channel_info*); +int rss_channel_info_init(struct rss_channel_info**); int rss_entry(FILE*,struct rss_entry*); +void rss_entry_free(struct rss_entry*); +int rss_entry_init(struct rss_entry**); int rss_footer(FILE*); int rss_header(FILE*); int rss_info(FILE*,struct rss_channel_info*); diff --git a/src/feed.c b/src/feed.c index afe6fac..502ac5d 100644 --- a/src/feed.c +++ b/src/feed.c @@ -2,8 +2,8 @@ static int feed_entries(FILE*,struct torrent*); static int feed_generate(struct torrent*); +static int feed_info(struct torrent*,struct rss_channel_info*); static char *feed_path(const char*,const char*); -//static int feed_now(char*,size_t); int feed() { for(size_t i=0;i0) { + while((i = next_line(fp,&key,&value,buf,META_MAX_LINE_SIZE))>0) { if(strcmp(key,RSS_TAG_TITLE)==0) { entry->title = strndup(value,i); } else if(strcmp(key,RSS_TAG_LINK)==0) { @@ -51,7 +55,7 @@ static int meta_escape(char *buf, size_t buf_size) { case '<': if(left<=4) { return -1; } memmove(&(p[4]),p,len); - strcpy(p,"<") + strcpy(p,"<"); p += 4; break; case '\\': @@ -61,16 +65,16 @@ static int meta_escape(char *buf, size_t buf_size) { p++; } break; - case '>'; + case '>': if(left<=4) { return -1; } memmove(&(p[4]),p,len); - strcpy(p,">") + strcpy(p,">"); p += 4; break; case '&': if(left<=5) { return -1; } memmove(&(p[5]),p,len); - strcpy(p,"&") + strcpy(p,"&"); p += 5; break; default: @@ -87,11 +91,15 @@ int meta_info(const char *path, struct rss_channel_info *info) { char buf[META_MAX_LINE_SIZE]; char *key, *value; FILE *fp; + ssize_t i; + + if(NULL==path) { return -1; } + if(NULL==info) { return -1; } fp = meta_search(path); if(NULL==fp) { return 0; } - while((i = next_line(fp,&key,&value,buf,META_MAX_SIZE))>0) { + while((i = next_line(fp,&key,&value,buf,META_MAX_LINE_SIZE))>0) { if(strcmp(key,RSS_TAG_TITLE)==0) { info->title = strndup(value,i); } else if(strcmp(key,RSS_TAG_LINK)==0) { @@ -99,7 +107,7 @@ int meta_info(const char *path, struct rss_channel_info *info) { } else if(strcmp(key,RSS_TAG_DESCRIPTION)==0) { info->description = strndup(value,i); } else if(strcmp(key,RSS_TAG_LANGUAGE)==0) { - entry->language = strndup(value,i); + info->language = strndup(value,i); } else if(strcmp(key,RSS_TAG_LASTBUILDDATE)==0) { return -1; } else { goto panic; } @@ -116,6 +124,7 @@ panic: } static FILE *meta_search(const char *path) { + FILE *fp; char *p; size_t len; @@ -132,17 +141,23 @@ static FILE *meta_search(const char *path) { if(NULL==p) { return NULL; } strcpy(p,path); - strncat(p,".meta",5); + strcat(p,".meta"); } fp = fopen(p,"r"); return fp; } -static ssize_t next_line(FILE *fp, char *buf, size_t buf_size) { +static ssize_t next_line(FILE *fp, char **key, char **value, char *buf, size_t buf_size) { if(fgets(buf,buf_size,fp)==NULL) { return -1; } if(meta_escape(buf,buf_size)<0) { return -1; } - return 1; + (*key) = buf; + (*value) = strchr(buf,'='); + if(NULL==(*value)) { return -1; } + + (*value) = '\0'; + (*value)++; + return buf_size - strlen(*key); } diff --git a/src/rss/free.c b/src/rss/free.c new file mode 100644 index 0000000..2e46d5f --- /dev/null +++ b/src/rss/free.c @@ -0,0 +1,19 @@ +#include + +void rss_channel_info_free(struct rss_channel_info *p) { + if(p->title!=NULL) { free(p->title); } + if(p->link!=NULL) { free(p->link); } + if(p->description!=NULL) { free(p->description); } + if(p->language!=NULL) { free(p->language); } + + free(p); +} + +void rss_entry_free(struct rss_entry *p) { + if(p->title!=NULL) { free(p->title); } + if(p->link!=NULL) { free(p->link); } + if(p->description!=NULL) { free(p->description); } + if(p->guid!=NULL) { free(p->guid); } + + free(p); +} diff --git a/src/rss/init.c b/src/rss/init.c new file mode 100644 index 0000000..6f0729e --- /dev/null +++ b/src/rss/init.c @@ -0,0 +1,31 @@ +#include + +int rss_channel_info_init(struct rss_channel_info **p) { + if(NULL==p) { return -1; } + + (*p) = malloc(sizeof(struct rss_channel_info)); + if(NULL==(*p)) { return -1; } + + (*p)->title = NULL; + (*p)->link = NULL; + (*p)->description = NULL; + (*p)->language = NULL; + memset(&((*p)->last_build_date),0,sizeof(struct tm)); + + return 1; +} + +int rss_entry_init(struct rss_entry **p) { + if(NULL==p) { return -1; } + + (*p) = malloc(sizeof(struct rss_entry)); + if(NULL==(*p)) { return -1; } + + (*p)->title = NULL; + (*p)->link = NULL; + memset(&((*p)->pub_date),0,sizeof(struct tm)); + (*p)->description = NULL; + (*p)->guid = NULL; + + return 1; +} diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am index 3420737..dc6cc48 100644 --- a/test/unit/Makefile.am +++ b/test/unit/Makefile.am @@ -12,7 +12,7 @@ AM_CPPFLAGS += \ -DNDEBUG endif -check_PROGRAMS = bencode.tests block.tests file.tests fs.concat.tests fs.filter.tests hash.tests hashmap.tests rss.tests torrent.tests tree.tests +check_PROGRAMS = bencode.tests block.tests file.tests fs.concat.tests fs.filter.tests hash.tests hashmap.tests meta.tests rss.tests torrent.tests tree.tests TESTS = $(check_PROGRAMS) if ENABLE_MEMCHECK @@ -61,13 +61,24 @@ hashmap_tests_SOURCES = \ hashmap.tests.c \ $(top_srcdir)/src/hashmap.c +meta_tests_SOURCES = \ + $(common_SOURCES) \ + meta.tests.c \ + $(top_srcdir)/src/fs/concat.c \ + $(top_srcdir)/src/fs/dir.c \ + $(top_srcdir)/src/meta.c \ + $(top_srcdir)/src/rss/free.c \ + $(top_srcdir)/src/rss/init.c + rss_tests_SOURCES = \ $(common_SOURCES) \ rss.tests.c \ $(top_srcdir)/src/rss/entry.c \ $(top_srcdir)/src/rss/footer.c \ + $(top_srcdir)/src/rss/free.c \ $(top_srcdir)/src/rss/header.c \ - $(top_srcdir)/src/rss/info.c + $(top_srcdir)/src/rss/info.c \ + $(top_srcdir)/src/rss/init.c torrent_tests_SOURCES = \ $(common_SOURCES) \ diff --git a/test/unit/meta.tests.c b/test/unit/meta.tests.c new file mode 100644 index 0000000..b1f17bd --- /dev/null +++ b/test/unit/meta.tests.c @@ -0,0 +1,70 @@ +#include + +#include + +int main(); +static void meta_entry_basic_test(); +static void meta_info_basic_test(); + +int main() { + setup_env(); + + meta_entry_basic_test(); + meta_info_basic_test(); + + clean_env(); + + return EXIT_SUCCESS; +} + +static void meta_entry_basic_test() { + struct rss_entry *entry; + + assert(1==rss_entry_init(&entry)); + + assert(meta_entry(NULL,NULL)==-1); + assert(meta_entry(TEST_FILE_1,NULL)==-1); + + // TEST_FILE_3's .meta file contains invalid fields + assert(meta_entry(TEST_FILE_3,entry)==-1); + + // PREFIX's .meta file is meant to contain channel info + // (and as such will have invalid fields) + assert(meta_entry(PREFIX,entry)==-1); + + assert(meta_entry(TEST_FILE_1,entry)==1); + + assert(strcmp(entry->title,"test title")==0); + assert(strcmp(entry->link,"https://whatisarealink.com")==0); +// assert(strcmp(entry->pub_date,"")==0); + assert(strcmp(entry->description,"I wonder if \n this'll properly be formatted/escaped \\><?")==0); + assert(strcmp(entry->guid,"magnet=asldkfjsldkfjslkdjfldsdjlfkjsdf")==0); + + rss_entry_free(entry); +} + +static void meta_info_basic_test() { + struct rss_channel_info *info; + + assert(rss_channel_info_init(&info)==1); + + assert(meta_info(NULL,NULL)==-1); + assert(meta_info(PREFIX,NULL)==-1); + + // TEST_FILE_3's .meta file contains invalid fields + assert(meta_info(TEST_FILE_3,info)==-1); + + // TEST_FILE_1's .meta file is meant to contain entry fields + // (and as such will have invalid fields) + assert(meta_info(TEST_FILE_1,info)==-1); + + assert(meta_info(PREFIX,info)==1); + + assert(strcmp(info->title,"TITLE")==0); + assert(strcmp(info->link,"http://test.com")==0); + assert(strcmp(info->description,"what is a description")==0); + assert(strcmp(info->language,"en-us")==0); +// assert(strcmp(info->last_build_date,"")==0); + + rss_channel_info_free(info); +} diff --git a/test/unit/rss.tests.c b/test/unit/rss.tests.c index ff0cc3d..1c0822a 100644 --- a/test/unit/rss.tests.c +++ b/test/unit/rss.tests.c @@ -4,8 +4,10 @@ int main(); static FILE *setup_file_pointer(); +static void rss_channel_info_init_basic_test(); static void rss_entry_basic_test(); static void rss_entry_correctness_test(); +static void rss_entry_init_basic_test(); static void rss_footer_basic_test(); static void rss_footer_correctness_test(); static void rss_header_basic_test(); @@ -16,6 +18,8 @@ static void rss_info_correctness_test(); int main() { setup_env(); + rss_entry_init_basic_test(); + rss_channel_info_init_basic_test(); rss_entry_basic_test(); rss_entry_correctness_test(); rss_footer_basic_test(); @@ -30,18 +34,28 @@ int main() { return EXIT_SUCCESS; } +static void rss_channel_info_init_basic_test() { + struct rss_channel_info *p; + + assert(rss_channel_info_init(NULL)==-1); + assert(rss_channel_info_init(&p)==1); + + rss_channel_info_free(p); +} + static void rss_entry_basic_test() { FILE *fp; - struct rss_entry p; + struct rss_entry *p; + char *tmp; - memset(&p,0,sizeof(struct rss_entry)); + assert(rss_entry_init(&p)==1); fp = setup_file_pointer(); assert(rss_entry(NULL,NULL)==-1); assert(rss_entry(fp,NULL)==-1); - assert(rss_entry(fp,&p)==-1); + assert(rss_entry(fp,p)==-1); char bad_title[] = ""; char sample_title[] = "sample title"; @@ -51,43 +65,50 @@ static void rss_entry_basic_test() { char sample_description[] = "sample description"; char sample_guid[] = "laskdjflkasdjf"; - p.title = sample_title; - p.link = sample_link; - p.description = sample_description; - p.guid = sample_guid; - p.pub_date = *localtime(&(time_t){time(NULL)}); + p->title = strdup(sample_title); + p->link = strdup(sample_link); + p->description = strdup(sample_description); + p->guid = strdup(sample_guid); + p->pub_date = *localtime(&(time_t){time(NULL)}); - assert(rss_entry(fp,&p)==1); + assert(rss_entry(fp,p)==1); - p.title = bad_title; - assert(rss_entry(fp,&p)==-1); - p.title = sample_title; - - p.link = bad_link; - assert(rss_entry(fp,&p)==-1); - p.link = sample_link; - - p.description = bad_description; - assert(rss_entry(fp,&p)==1); - p.description = sample_description; - assert(rss_entry(fp,&p)==1); + tmp = p->title; + p->title = bad_title; + assert(rss_entry(fp,p)==-1); + p->title = tmp; + + tmp = p->link; + p->link = bad_link; + assert(rss_entry(fp,p)==-1); + p->link = tmp; + + tmp = p->description; + p->description = bad_description; + assert(rss_entry(fp,p)==1); + p->description = tmp; + assert(rss_entry(fp,p)==1); - p.guid = NULL; - assert(rss_entry(fp,&p)==1); - p.guid = sample_guid; - assert(rss_entry(fp,&p)==1); + tmp = p->guid; + p->guid = NULL; + assert(rss_entry(fp,p)==1); + p->guid = tmp; + assert(rss_entry(fp,p)==1); fclose(fp); + + rss_entry_free(p); + reset_env(); } static void rss_entry_correctness_test() { FILE *fp; - struct rss_entry p; + struct rss_entry *p; unsigned char hash[crypto_hash_sha256_BYTES]; unsigned char expected[crypto_hash_sha256_BYTES] = {252,1,77,6,36,221,191,114,180,137,47,54,77,39,151,196,0,85,115,184,127,210,230,152,114,130,36,140,33,239,194,30}; - memset(&p,0,sizeof(struct rss_entry)); + assert(1==rss_entry_init(&p)); fp = setup_file_pointer(); @@ -96,23 +117,34 @@ static void rss_entry_correctness_test() { char sample_description[] = "sample description"; char sample_guid[] = "laskdjflkasdjf"; - p.title = sample_title; - p.link = sample_link; - p.description = sample_description; - p.guid = sample_guid; + p->title = strdup(sample_title); + p->link = strdup(sample_link); + p->description = strdup(sample_description); + p->guid = strdup(sample_guid); time_t seconds = 1231006505; - memcpy(&(p.pub_date), gmtime(&seconds), sizeof(struct tm)); + memcpy(&(p->pub_date), gmtime(&seconds), sizeof(struct tm)); - assert(rss_entry(fp,&p)==1); + assert(rss_entry(fp,p)==1); fclose(fp); hash_file(TEST_FILE_7,hash,crypto_hash_sha256_BYTES); assert(memcmp(hash,expected,crypto_hash_sha256_BYTES)==0); + rss_entry_free(p); + reset_env(); } +static void rss_entry_init_basic_test() { + struct rss_entry *p; + + assert(rss_entry_init(NULL)==-1); + assert(rss_entry_init(&p)==1); + + rss_entry_free(p); +} + static void rss_footer_basic_test() { FILE *fp; @@ -173,9 +205,10 @@ static void rss_header_correctness_test() { static void rss_info_basic_test() { FILE *fp; - struct rss_channel_info p; + struct rss_channel_info *p; + char *tmp; - memset(&p,0,sizeof(struct rss_channel_info)); + assert(1==rss_channel_info_init(&p)); fp = setup_file_pointer(); @@ -192,44 +225,51 @@ static void rss_info_basic_test() { char bad_language_2[] = "alskdjflkasdjfaslkdf"; char sample_language[] = "en-us"; - p.title = sample_title; - p.link = sample_link; - p.description = sample_description; - p.language = sample_language; - p.last_build_date = *localtime(&(time_t){time(NULL)}); - - assert(rss_info(fp,&p)==1); - - p.title = bad_title; - assert(rss_info(fp,&p)==-1); - p.title = sample_title; + p->title = strdup(sample_title); + p->link = strdup(sample_link); + p->description = strdup(sample_description); + p->language = strdup(sample_language); + p->last_build_date = *localtime(&(time_t){time(NULL)}); + + assert(rss_info(fp,p)==1); + + tmp = p->title; + p->title = bad_title; + assert(rss_info(fp,p)==-1); + p->title = tmp; + + tmp = p->link; + p->link = bad_link; + assert(rss_info(fp,p)==-1); + p->link = tmp; + + tmp = p->description; + p->description = bad_description; + assert(rss_info(fp,p)==1); + p->description = tmp; + assert(rss_info(fp,p)==1); + + tmp = p->language; + p->language = bad_language_1; + assert(rss_info(fp,p)==1); // should succeed (fills with default) + p->language = bad_language_2; + assert(rss_info(fp,p)==1); // no locale checking done (out of scope of rss_info) + p->language = tmp; - p.link = bad_link; - assert(rss_info(fp,&p)==-1); - p.link = sample_link; - - p.description = bad_description; - assert(rss_info(fp,&p)==1); - p.description = sample_description; - assert(rss_info(fp,&p)==1); + fclose(fp); - p.language = bad_language_1; - assert(rss_info(fp,&p)==1); // should succeed (fills with default) - p.language = bad_language_2; - assert(rss_info(fp,&p)==1); // no locale checking done (out of scope of rss_info) - p.language = sample_language; + rss_channel_info_free(p); - fclose(fp); reset_env(); } static void rss_info_correctness_test() { FILE *fp; - struct rss_channel_info p; + struct rss_channel_info *p; unsigned char hash[crypto_hash_sha256_BYTES]; unsigned char expected[crypto_hash_sha256_BYTES] = {175,238,191,8,225,134,109,105,86,61,240,232,31,206,163,165,243,43,229,34,169,83,166,18,54,229,225,99,110,47,38,243}; - memset(&p,0,sizeof(struct rss_channel_info)); + assert(1==rss_channel_info_init(&p)); fp = setup_file_pointer(); @@ -238,20 +278,22 @@ static void rss_info_correctness_test() { char sample_description[] = "alsdjflaksdjfoikasjdfliasjdfoijawdf"; char sample_language[] = "en-us"; - p.title = sample_title; - p.link = sample_link; - p.description = sample_description; - p.language = sample_language; + p->title = strdup(sample_title); + p->link = strdup(sample_link); + p->description = strdup(sample_description); + p->language = strdup(sample_language); time_t seconds = 1231006505; - memcpy(&(p.last_build_date), gmtime(&seconds), sizeof(struct tm)); + memcpy(&(p->last_build_date), gmtime(&seconds), sizeof(struct tm)); - assert(rss_info(fp,&p)==1); + assert(rss_info(fp,p)==1); fclose(fp); hash_file(TEST_FILE_7,hash,crypto_hash_sha256_BYTES); assert(memcmp(hash,expected,crypto_hash_sha256_BYTES)==0); + rss_channel_info_free(p); + reset_env(); } diff --git a/test/unit/test_utils.c b/test/unit/test_utils.c index 924e55c..9017305 100644 --- a/test/unit/test_utils.c +++ b/test/unit/test_utils.c @@ -25,6 +25,8 @@ void setup_env() { create_test_file(TEST_FILE_2,TEST_FILE_2_CONTENTS); create_test_file(TEST_FILE_3,TEST_FILE_3_CONTENTS); create_test_file(TEST_FILE_4,TEST_FILE_4_CONTENTS); + create_test_file(TEST_FILE_8,TEST_FILE_8_CONTENTS); + create_test_file(TEST_FILE_9,TEST_FILE_9_CONTENTS); } static void create_test_directory(const char *directory) { diff --git a/test/unit/test_utils.h b/test/unit/test_utils.h index 063aacd..cc42904 100644 --- a/test/unit/test_utils.h +++ b/test/unit/test_utils.h @@ -23,6 +23,10 @@ #define TEST_FILE_5 PREFIX "/random.test" #define TEST_FILE_6 PREFIX "/file.torrent" #define TEST_FILE_7 PREFIX "/file.feed" +#define TEST_FILE_8 PREFIX "/test.meta" +#define TEST_FILE_8_CONTENTS "title=test title\nlink=https://whatisarealink.com\npubDate=0000\ndescription=I wonder if \\n this'll properly be formatted/escaped \\>