From 53f2c02ac75360b53a8eba8d575e5fa55f8b3372 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 28 Apr 2012 23:46:32 +0900 Subject: [PATCH] metalink: parse downloaded Metalink file Parse downloaded Metalink file and add downloads described there. Fixed compile error without metalink support. --- src/tool_getparam.c | 63 +++--------------------------------- src/tool_metalink.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ src/tool_metalink.h | 2 ++ src/tool_operate.c | 53 +++++++++++++++++++++++------- 4 files changed, 126 insertions(+), 70 deletions(-) diff --git a/src/tool_getparam.c b/src/tool_getparam.c index bdb4b04ae..34f6420e0 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -829,65 +829,10 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ case 'J': /* --metalink */ { #ifdef HAVE_LIBMETALINK - metalink_error_t r; - metalink_t* metalink; - metalink_file_t **files; - struct metalink *ml; - - r = metalink_parse_file(nextarg, &metalink); - - if(r != 0) { - fprintf(stderr, "ERROR: code=%d\n", r); - exit(EXIT_FAILURE); - } - ml = new_metalink(metalink); - - if(config->metalink_list) { - config->metalink_last->next = ml; - config->metalink_last = ml; - } - else { - config->metalink_list = config->metalink_last = ml; - } - - for(files = metalink->files; *files; ++files) { - struct getout *url; - /* Skip an entry which has no resource. */ - if(!(*files)->resources[0]) continue; - if(config->url_get || - ((config->url_get = config->url_list) != NULL)) { - /* there's a node here, if it already is filled-in continue to - find an "empty" node */ - while(config->url_get && (config->url_get->flags & GETOUT_URL)) - config->url_get = config->url_get->next; - } - - /* now there might or might not be an available node to fill in! */ - - if(config->url_get) - /* existing node */ - url = config->url_get; - else - /* there was no free node, create one! */ - url=new_getout(config); - - if(url) { - struct metalinkfile *mlfile; - /* Set name as url */ - GetStr(&url->url, (*files)->name); - - /* set flag metalink here */ - url->flags |= GETOUT_URL | GETOUT_METALINK; - mlfile = new_metalinkfile(*files); - - if(config->metalinkfile_list) { - config->metalinkfile_last->next = mlfile; - config->metalinkfile_last = mlfile; - } - else { - config->metalinkfile_list = config->metalinkfile_last = mlfile; - } - } + if(parse_metalink(config, nextarg) == -1) { + warnf(config, "Could not parse Metalink file: %s\n", nextarg); + /* TODO Is PARAM_BAD_USE appropriate here? */ + return PARAM_BAD_USE; } #else warnf(config, "--metalink option is ignored because the binary is " diff --git a/src/tool_metalink.c b/src/tool_metalink.c index a57297b78..4b4c6bcd3 100644 --- a/src/tool_metalink.c +++ b/src/tool_metalink.c @@ -21,9 +21,23 @@ ***************************************************************************/ #include "tool_setup.h" #include "tool_metalink.h" +#include "tool_getparam.h" +#include "tool_paramhlp.h" #include "memdebug.h" /* keep this as LAST include */ +/* Copied from tool_getparam.c */ +#define GetStr(str,val) do { \ + if(*(str)) { \ + free(*(str)); \ + *(str) = NULL; \ + } \ + if((val)) \ + *(str) = strdup((val)); \ + if(!(val)) \ + return PARAM_NO_MEM; \ +} WHILE_FALSE + struct metalinkfile *new_metalinkfile(metalink_file_t *metalinkfile) { struct metalinkfile *f; f = (struct metalinkfile*)malloc(sizeof(struct metalinkfile)); @@ -64,3 +78,67 @@ void clean_metalink(struct Configurable *config) } config->metalink_last = 0; } + +int parse_metalink(struct Configurable *config, const char *infile) +{ + metalink_error_t r; + metalink_t* metalink; + metalink_file_t **files; + struct metalink *ml; + + r = metalink_parse_file(infile, &metalink); + + if(r != 0) { + return -1; + } + ml = new_metalink(metalink); + + if(config->metalink_list) { + config->metalink_last->next = ml; + config->metalink_last = ml; + } + else { + config->metalink_list = config->metalink_last = ml; + } + + for(files = metalink->files; *files; ++files) { + struct getout *url; + /* Skip an entry which has no resource. */ + if(!(*files)->resources[0]) continue; + if(config->url_get || + ((config->url_get = config->url_list) != NULL)) { + /* there's a node here, if it already is filled-in continue to + find an "empty" node */ + while(config->url_get && (config->url_get->flags & GETOUT_URL)) + config->url_get = config->url_get->next; + } + + /* now there might or might not be an available node to fill in! */ + + if(config->url_get) + /* existing node */ + url = config->url_get; + else + /* there was no free node, create one! */ + url=new_getout(config); + + if(url) { + struct metalinkfile *mlfile; + /* Set name as url */ + GetStr(&url->url, (*files)->name); + + /* set flag metalink here */ + url->flags |= GETOUT_URL | GETOUT_METALINK; + mlfile = new_metalinkfile(*files); + + if(config->metalinkfile_list) { + config->metalinkfile_last->next = mlfile; + config->metalinkfile_last = mlfile; + } + else { + config->metalinkfile_list = config->metalinkfile_last = mlfile; + } + } + } + return 0; +} diff --git a/src/tool_metalink.h b/src/tool_metalink.h index e9f8162ab..39e6674d1 100644 --- a/src/tool_metalink.h +++ b/src/tool_metalink.h @@ -48,4 +48,6 @@ int count_next_metalink_resource(struct metalinkfile *mlfile); void clean_metalink(struct Configurable *config); +int parse_metalink(struct Configurable *config, const char *infile); + #endif /* HEADER_CURL_TOOL_METALINK_H */ diff --git a/src/tool_operate.c b/src/tool_operate.c index 669d2dd46..4bcc8b40d 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -130,7 +130,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) struct OutStruct heads; #ifdef HAVE_LIBMETALINK - struct metalinkfile *mlfile_last; + struct metalinkfile *mlfile_last = NULL; #endif /* HAVE_LIBMETALINK */ CURL *curl = NULL; @@ -392,10 +392,6 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } } -#ifdef HAVE_LIBMETALINK - mlfile_last = config->metalinkfile_list; -#endif /* HAVE_LIBMETALINK */ - /* ** Nested loops start here. */ @@ -409,16 +405,23 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) char *outfiles; int infilenum; URLGlob *inglob; + +#ifdef HAVE_LIBMETALINK int metalink; /* nonzero for metalink download */ struct metalinkfile *mlfile; metalink_resource_t **mlres; +#endif /* HAVE_LIBMETALINK */ outfiles = NULL; infilenum = 1; inglob = NULL; +#ifdef HAVE_LIBMETALINK if(urlnode->flags & GETOUT_METALINK) { metalink = 1; + if(mlfile_last == NULL) { + mlfile_last = config->metalinkfile_list; + } mlfile = mlfile_last; mlfile_last = mlfile_last->next; mlres = mlfile->file->resources; @@ -428,6 +431,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) mlfile = NULL; mlres = NULL; } +#endif /* HAVE_LIBMETALINK */ /* urlnode->url is the full URL (it might be NULL) */ @@ -497,12 +501,15 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) break; } +#ifdef HAVE_LIBMETALINK if(metalink) { /* For Metalink download, we don't use glob. Instead we use the number of resources as urlnum. */ urlnum = count_next_metalink_resource(mlfile); } - else if(!config->globoff) { + else +#endif /* HAVE_LIBMETALINK */ + if(!config->globoff) { /* Unless explicitly shut off, we expand '{...}' and '[...]' expressions and return total number of URLs in pattern set */ res = glob_url(&urls, urlnode->url, &urlnum, @@ -533,20 +540,24 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) long retry_sleep; char *this_url; HeaderData hdrdata; - int metalink_next_res; +#ifdef HAVE_LIBMETALINK + int metalink_next_res = 0; +#endif /* HAVE_LIBMETALINK */ outfile = NULL; infdopen = FALSE; infd = STDIN_FILENO; uploadfilesize = -1; /* -1 means unknown */ - metalink_next_res = 0; /* default output stream is stdout */ memset(&outs, 0, sizeof(struct OutStruct)); outs.stream = stdout; outs.config = config; +#ifdef HAVE_LIBMETALINK if(metalink) { + /* For Metalink download, use name in Metalink file as + filename. */ outfile = strdup(mlfile->file->name); if(!outfile) { res = CURLE_OUT_OF_MEMORY; @@ -559,6 +570,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } } else { +#endif /* HAVE_LIBMETALINK */ if(urls) { res = glob_next_url(&this_url, urls); if(res) @@ -583,7 +595,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) goto show_error; } } +#ifdef HAVE_LIBMETALINK } +#endif /* HAVE_LIBMETALINK */ if((urlnode->flags&GETOUT_USEREMOTE) || (outfile && !curlx_strequal("-", outfile)) ) { @@ -1429,6 +1443,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) continue; /* curl_easy_perform loop */ } } /* if retry_numretries */ +#ifdef HAVE_LIBMETALINK else if(metalink) { /* Metalink: Decide to try the next resource or not. Basically, we want to try the next resource if @@ -1451,6 +1466,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) else metalink_next_res = 1; } +#endif /* HAVE_LIBMETALINK */ /* In all ordinary cases, just break out of loop here */ break; /* curl_easy_perform loop */ @@ -1562,10 +1578,21 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) #ifdef HAVE_LIBMETALINK if(!metalink && res == CURLE_OK && outs.filename) { + /* Check the content-type header field and if it indicates + Metalink file, parse it and add getout for them. */ char *content_type; curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type); - if(content_type != NULL) { - printf("file=%s, content-type=%s\n", outs.filename, content_type); + if(content_type && + Curl_raw_equal("application/metalink+xml", content_type)) { + if(!(config->mute)) { + fprintf(config->errors, "\nParsing Metalink file: %s\n", + outs.filename); + } + if(parse_metalink(config, outs.filename) == 0) + fprintf(config->errors, + "Metalink file is parsed successfully\n"); + else + fprintf(config->errors, "Could not parse Metalink file.\n"); } } #endif /* HAVE_LIBMETALINK */ @@ -1586,14 +1613,18 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) infd = STDIN_FILENO; } +#ifdef HAVE_LIBMETALINK if(metalink) { + /* Should exit if error is fatal. */ if(is_fatal_error(res)) { break; } if(!metalink_next_res || *(++mlres) == NULL) break; } - else if(urlnum > 1) { + else +#endif /* HAVE_LIBMETALINK */ + if(urlnum > 1) { /* when url globbing, exit loop upon critical error */ if(is_fatal_error(res)) break;