diff options
-rw-r--r-- | src/tool_cfgable.h | 1 | ||||
-rw-r--r-- | src/tool_getparam.c | 8 | ||||
-rw-r--r-- | src/tool_help.c | 2 | ||||
-rw-r--r-- | src/tool_metalink.c | 52 | ||||
-rw-r--r-- | src/tool_metalink.h | 10 | ||||
-rw-r--r-- | src/tool_operate.c | 55 | ||||
-rw-r--r-- | src/tool_sdecls.h | 10 |
7 files changed, 97 insertions, 41 deletions
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 2183c04df..1f6f94852 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -201,6 +201,7 @@ struct Configurable { long gssapi_delegation; bool ssl_allow_beast; /* allow this SSL vulnerability */ + bool use_metalink; /* process given URLs as metalink XML file */ metalinkfile *metalinkfile_list; /* point to the first node */ metalinkfile *metalinkfile_last; /* point to the last/current node */ }; /* struct Configurable */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index ab8ed1d5e..4bdf0a59d 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -171,7 +171,7 @@ static const struct LongShort aliases[]= { {"$G", "delegation", TRUE}, {"$H", "mail-auth", TRUE}, {"$I", "post303", FALSE}, - {"$J", "metalink", TRUE}, + {"$J", "metalink", FALSE}, {"0", "http1.0", FALSE}, {"1", "tlsv1", FALSE}, {"2", "sslv2", FALSE}, @@ -824,11 +824,7 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ case 'J': /* --metalink */ { #ifdef USE_METALINK - 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; - } + config->use_metalink = toggle; #else warnf(config, "--metalink option is ignored because the binary is " "built without the Metalink support.\n"); diff --git a/src/tool_help.c b/src/tool_help.c index ac9246931..124f6404d 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -125,7 +125,7 @@ static const char *const helptext[] = { " --max-filesize BYTES Maximum file size to download (H/F)", " --max-redirs NUM Maximum number of redirects allowed (H)", " -m, --max-time SECONDS Maximum time allowed for the transfer", - " --metalink Process local Metalink file and use mirrors", + " --metalink Process given URLs as metalink XML file", " --negotiate Use HTTP Negotiate Authentication (H)", " -n, --netrc Must read .netrc for user name and password", " --netrc-optional Use either .netrc or URL; overrides -n", diff --git a/src/tool_metalink.c b/src/tool_metalink.c index 8f6a1f870..74a0012ac 100644 --- a/src/tool_metalink.c +++ b/src/tool_metalink.c @@ -33,8 +33,6 @@ # include <fcntl.h> #endif -#include <metalink/metalink_parser.h> - #ifdef USE_SSLEAY # ifdef USE_OPENSSL # include <openssl/md5.h> @@ -68,6 +66,7 @@ #include "tool_paramhlp.h" #include "tool_cfgable.h" #include "tool_metalink.h" +#include "tool_msgs.h" #include "memdebug.h" /* keep this as LAST include */ @@ -331,8 +330,8 @@ static int check_hash(const char *filename, digest_context *dctx; int check_ok; int fd; - fprintf(error, "Checking %s checksum of file %s\n", digest_def->hash_name, - filename); + fprintf(error, "Validating %s checksum (This may take some time)...\n", + digest_def->hash_name); fd = open(filename, O_RDONLY); if(fd == -1) { fprintf(error, "Could not open file %s: %s\n", filename, strerror(errno)); @@ -358,6 +357,12 @@ static int check_hash(const char *filename, Curl_digest_final(dctx, result); check_ok = memcmp(result, digest, digest_def->dparams->digest_resultlen) == 0; + /* sha*sum style verdict output */ + if(check_ok) + fprintf(error, "%s: OK\n", filename); + else + fprintf(error, "%s: FAILED\n", filename); + free(result); close(fd); return check_ok; @@ -373,12 +378,6 @@ int metalink_check_hash(struct Configurable *config, } rv = check_hash(filename, mlfile->checksum->digest_def, mlfile->checksum->digest, config->errors); - if(rv == 1) { - fprintf(config->errors, "Checksum matched\n"); - } - else if(rv == 0) { - fprintf(config->errors, "Checksum didn't match\n"); - } return rv; } @@ -468,13 +467,15 @@ static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo) return f; } -int parse_metalink(struct Configurable *config, const char *infile) +int parse_metalink(struct Configurable *config, struct OutStruct *outs) { metalink_error_t r; metalink_t* metalink; metalink_file_t **files; - r = metalink_parse_file(infile, &metalink); + /* metlaink_parse_final deletes outs->metalink_parser */ + r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink); + outs->metalink_parser = NULL; if(r != 0) { return -1; } @@ -531,6 +532,33 @@ int parse_metalink(struct Configurable *config, const char *infile) return 0; } +size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, + void *userdata) +{ + struct OutStruct *outs = userdata; + struct Configurable *config = outs->config; + int rv; + + /* + * Once that libcurl has called back tool_write_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + const size_t failure = (sz * nmemb) ? 0 : 1; + + if(!config) + return failure; + + rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb); + if(rv == 0) + return sz * nmemb; + else { + warnf(config, "Failed to parse Metalink XML\n"); + return failure; + } +} + /* * Returns nonzero if content_type includes mediatype. */ diff --git a/src/tool_metalink.h b/src/tool_metalink.h index 36b4b02c7..c2568a31e 100644 --- a/src/tool_metalink.h +++ b/src/tool_metalink.h @@ -82,13 +82,21 @@ extern const digest_params MD5_DIGEST_PARAMS[1]; extern const digest_params SHA1_DIGEST_PARAMS[1]; extern const digest_params SHA256_DIGEST_PARAMS[1]; +#include <metalink/metalink_parser.h> + /* * Counts the resource in the metalinkfile. */ int count_next_metalink_resource(metalinkfile *mlfile); void clean_metalink(struct Configurable *config); -int parse_metalink(struct Configurable *config, const char *infile); +int parse_metalink(struct Configurable *config, struct OutStruct *outs); + +/* + * Callback function for CURLOPT_WRITEFUNCTION + */ +size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, + void *userdata); /* * Returns nonzero if content_type includes "application/metalink+xml" diff --git a/src/tool_operate.c b/src/tool_operate.c index 8a5569bd8..6d02fb667 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -586,8 +586,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } } - if((urlnode->flags&GETOUT_USEREMOTE) || - (outfile && !curlx_strequal("-", outfile)) ) { + if(((urlnode->flags&GETOUT_USEREMOTE) || + (outfile && !curlx_strequal("-", outfile))) && + (metalink || !config->use_metalink)) { /* * We have specified a file name to store the result in, or we have @@ -826,8 +827,15 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) /* where to store */ my_setopt(curl, CURLOPT_WRITEDATA, &outs); - /* what call to write */ - my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); + if(metalink || !config->use_metalink) + /* what call to write */ + my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); +#ifdef USE_METALINK + else + /* Set Metalink specific write callback function to parse + XML data progressively. */ + my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb); +#endif /* USE_METALINK */ /* for uploads */ input.fd = infd; @@ -1316,6 +1324,19 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) #endif for(;;) { +#ifdef USE_METALINK + if(!metalink && config->use_metalink) { + /* If outs.metalink_parser is non-NULL, delete it first. */ + if(outs.metalink_parser) + metalink_parser_context_delete(outs.metalink_parser); + outs.metalink_parser = metalink_parser_context_new(); + if(outs.metalink_parser == NULL) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } + } +#endif /* USE_METALINK */ + res = curl_easy_perform(curl); if(outs.is_cd_filename && outs.stream && !config->mute && @@ -1569,22 +1590,12 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) #endif #ifdef USE_METALINK - 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 && check_metalink_content_type(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"); - } + if(!metalink && config->use_metalink && res == CURLE_OK) { + if(parse_metalink(config, &outs) == 0) + fprintf(config->errors, + "Metalink XML is parsed successfully\n"); + else + fprintf(config->errors, "Could not parse Metalink XML.\n"); } else if(metalink && res == CURLE_OK && !metalink_next_res) { int rv = metalink_check_hash(config, mlfile, outs.filename); @@ -1597,6 +1608,10 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) /* No more business with this output struct */ if(outs.alloc_filename) Curl_safefree(outs.filename); +#ifdef USE_METALINK + if(outs.metalink_parser) + metalink_parser_context_delete(outs.metalink_parser); +#endif /* USE_METALINK */ memset(&outs, 0, sizeof(struct OutStruct)); hdrcbdata.outs = NULL; diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h index da6253604..8038ad7a3 100644 --- a/src/tool_sdecls.h +++ b/src/tool_sdecls.h @@ -22,7 +22,9 @@ * ***************************************************************************/ #include "tool_setup.h" - +#ifdef USE_METALINK +# include <metalink/metalink_parser.h> +#endif /* USE_METALINK */ /* * OutStruct variables keep track of information relative to curl's @@ -55,6 +57,9 @@ * * 'init' member holds original file size or offset at which truncation is * taking place. Always zero unless appending to a non-empty regular file. + * + * 'metalink_parser' member is a pointer to Metalink XML parser + * context. */ struct OutStruct { @@ -67,6 +72,9 @@ struct OutStruct { struct Configurable *config; curl_off_t bytes; curl_off_t init; +#ifdef USE_METALINK + metalink_parser_context_t *metalink_parser; +#endif /* USE_METALINK */ }; |