Commit 53f2c02a authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa Committed by Daniel Stenberg
Browse files

metalink: parse downloaded Metalink file

Parse downloaded Metalink file and add downloads described there. Fixed
compile error without metalink support.
parent 1919352a
Loading
Loading
Loading
Loading
+4 −59
Original line number Diff line number Diff line
@@ -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 "
+78 −0
Original line number Diff line number Diff line
@@ -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;
}
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+42 −11
Original line number Diff line number Diff line
@@ -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;