metalink: parse downloaded Metalink file

Parse downloaded Metalink file and add downloads described there. Fixed
compile error without metalink support.
This commit is contained in:
Tatsuhiro Tsujikawa 2012-04-28 23:46:32 +09:00 committed by Daniel Stenberg
parent 1919352a10
commit 53f2c02ac7
4 changed files with 126 additions and 70 deletions

View File

@ -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 "

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;