Fix now broken libmetalink-aware OpenSSL build.
[platform/upstream/curl.git] / src / tool_metalink.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 #include "tool_setup.h"
23
24 #ifdef USE_METALINK
25
26 #ifdef HAVE_UNISTD_H
27 #  include <unistd.h>
28 #endif
29
30 #include <sys/stat.h>
31
32 #ifdef HAVE_FCNTL_H
33 #  include <fcntl.h>
34 #endif
35
36 #ifdef USE_SSLEAY
37 #  ifdef USE_OPENSSL
38 #    include <openssl/md5.h>
39 #    include <openssl/sha.h>
40 #  else
41 #    include <md5.h>
42 #    include <sha.h>
43 #  endif
44 #elif defined(USE_GNUTLS_NETTLE)
45 #  include <nettle/md5.h>
46 #  include <nettle/sha.h>
47 #  define MD5_CTX    struct md5_ctx
48 #  define SHA_CTX    struct sha1_ctx
49 #  define SHA256_CTX struct sha256_ctx
50 #elif defined(USE_GNUTLS)
51 #  include <gcrypt.h>
52 #  define MD5_CTX    gcry_md_hd_t
53 #  define SHA_CTX    gcry_md_hd_t
54 #  define SHA256_CTX gcry_md_hd_t
55 #elif defined(USE_DARWINSSL)
56 /* For darwinssl: CommonCrypto has the functions we need. The library's
57    headers are even backward-compatible with OpenSSL's headers as long as
58    we define COMMON_DIGEST_FOR_OPENSSL first.
59
60    These functions are available on Tiger and later, as well as iOS 5.0
61    and later. If you're building for an older cat, well, sorry. */
62 #  define COMMON_DIGEST_FOR_OPENSSL
63 #  include <CommonCrypto/CommonDigest.h>
64 #elif defined(_WIN32)
65 /* For Windows: If no other crypto library is provided, we fallback
66    to the hash functions provided within the Microsoft Windows CryptoAPI */
67 #  include <wincrypt.h>
68 /* Custom structure in order to store the required provider and hash handle */
69 struct win32_crypto_hash {
70   HCRYPTPROV hCryptProv;
71   HCRYPTHASH hHash;
72 };
73 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
74 #  ifndef ALG_SID_SHA_256
75 #    define ALG_SID_SHA_256  12
76 #  endif
77 #  ifndef CALG_SHA_256
78 #    define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
79 #  endif
80 #  define MD5_CTX    struct win32_crypto_hash
81 #  define SHA_CTX    struct win32_crypto_hash
82 #  define SHA256_CTX struct win32_crypto_hash
83 #else
84 #  error "Can't compile METALINK support without a crypto library."
85 #endif
86
87 #include "rawstr.h"
88
89 #define ENABLE_CURLX_PRINTF
90 /* use our own printf() functions */
91 #include "curlx.h"
92
93 #include "tool_getparam.h"
94 #include "tool_paramhlp.h"
95 #include "tool_cfgable.h"
96 #include "tool_metalink.h"
97 #include "tool_msgs.h"
98
99 #include "memdebug.h" /* keep this as LAST include */
100
101 /* Copied from tool_getparam.c */
102 #define GetStr(str,val) do { \
103   if(*(str)) { \
104     free(*(str)); \
105     *(str) = NULL; \
106   } \
107   if((val)) \
108     *(str) = strdup((val)); \
109   if(!(val)) \
110     return PARAM_NO_MEM; \
111 } WHILE_FALSE
112
113 #ifdef USE_GNUTLS_NETTLE
114
115 static void MD5_Init(MD5_CTX *ctx)
116 {
117   md5_init(ctx);
118 }
119
120 static void MD5_Update(MD5_CTX *ctx,
121                        const unsigned char *input,
122                        unsigned int inputLen)
123 {
124   md5_update(ctx, inputLen, input);
125 }
126
127 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
128 {
129   md5_digest(ctx, 16, digest);
130 }
131
132 static void SHA1_Init(SHA_CTX *ctx)
133 {
134   sha1_init(ctx);
135 }
136
137 static void SHA1_Update(SHA_CTX *ctx,
138                         const unsigned char *input,
139                         unsigned int inputLen)
140 {
141   sha1_update(ctx, inputLen, input);
142 }
143
144 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
145 {
146   sha1_digest(ctx, 20, digest);
147 }
148
149 static void SHA256_Init(SHA256_CTX *ctx)
150 {
151   sha256_init(ctx);
152 }
153
154 static void SHA256_Update(SHA256_CTX *ctx,
155                           const unsigned char *input,
156                           unsigned int inputLen)
157 {
158   sha256_update(ctx, inputLen, input);
159 }
160
161 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
162 {
163   sha256_digest(ctx, 32, digest);
164 }
165
166 #elif defined(USE_GNUTLS)
167
168 static void MD5_Init(MD5_CTX *ctx)
169 {
170   gcry_md_open(ctx, GCRY_MD_MD5, 0);
171 }
172
173 static void MD5_Update(MD5_CTX *ctx,
174                        const unsigned char *input,
175                        unsigned int inputLen)
176 {
177   gcry_md_write(*ctx, input, inputLen);
178 }
179
180 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
181 {
182   memcpy(digest, gcry_md_read(*ctx, 0), 16);
183   gcry_md_close(*ctx);
184 }
185
186 static void SHA1_Init(SHA_CTX *ctx)
187 {
188   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
189 }
190
191 static void SHA1_Update(SHA_CTX *ctx,
192                         const unsigned char *input,
193                         unsigned int inputLen)
194 {
195   gcry_md_write(*ctx, input, inputLen);
196 }
197
198 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
199 {
200   memcpy(digest, gcry_md_read(*ctx, 0), 20);
201   gcry_md_close(*ctx);
202 }
203
204 static void SHA256_Init(SHA256_CTX *ctx)
205 {
206   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
207 }
208
209 static void SHA256_Update(SHA256_CTX *ctx,
210                           const unsigned char *input,
211                           unsigned int inputLen)
212 {
213   gcry_md_write(*ctx, input, inputLen);
214 }
215
216 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
217 {
218   memcpy(digest, gcry_md_read(*ctx, 0), 32);
219   gcry_md_close(*ctx);
220 }
221
222 #elif defined(_WIN32) && !defined(USE_SSLEAY)
223
224 static void win32_crypto_final(struct win32_crypto_hash *ctx,
225                                unsigned char *digest,
226                                unsigned int digestLen)
227 {
228   unsigned long length;
229   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
230   if(length == digestLen)
231     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
232   if(ctx->hHash)
233     CryptDestroyHash(ctx->hHash);
234   if(ctx->hCryptProv)
235     CryptReleaseContext(ctx->hCryptProv, 0);
236 }
237
238 static void MD5_Init(MD5_CTX *ctx)
239 {
240   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
241                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
242     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
243   }
244 }
245
246 static void MD5_Update(MD5_CTX *ctx,
247                        const unsigned char *input,
248                        unsigned int inputLen)
249 {
250   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
251 }
252
253 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
254 {
255   win32_crypto_final(ctx, digest, 16);
256 }
257
258 static void SHA1_Init(SHA_CTX *ctx)
259 {
260   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
261                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
262     CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
263   }
264 }
265
266 static void SHA1_Update(SHA_CTX *ctx,
267                         const unsigned char *input,
268                         unsigned int inputLen)
269 {
270   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
271 }
272
273 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
274 {
275   win32_crypto_final(ctx, digest, 20);
276 }
277
278 static void SHA256_Init(SHA256_CTX *ctx)
279 {
280   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
281                          PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
282     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
283   }
284 }
285
286 static void SHA256_Update(SHA256_CTX *ctx,
287                           const unsigned char *input,
288                           unsigned int inputLen)
289 {
290   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
291 }
292
293 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
294 {
295   win32_crypto_final(ctx, digest, 32);
296 }
297
298 #endif /* CRYPTO LIBS */
299
300 const digest_params MD5_DIGEST_PARAMS[] = {
301   {
302     (Curl_digest_init_func) MD5_Init,
303     (Curl_digest_update_func) MD5_Update,
304     (Curl_digest_final_func) MD5_Final,
305     sizeof(MD5_CTX),
306     16
307   }
308 };
309
310 const digest_params SHA1_DIGEST_PARAMS[] = {
311   {
312     (Curl_digest_init_func) SHA1_Init,
313     (Curl_digest_update_func) SHA1_Update,
314     (Curl_digest_final_func) SHA1_Final,
315     sizeof(SHA_CTX),
316     20
317   }
318 };
319
320 const digest_params SHA256_DIGEST_PARAMS[] = {
321   {
322     (Curl_digest_init_func) SHA256_Init,
323     (Curl_digest_update_func) SHA256_Update,
324     (Curl_digest_final_func) SHA256_Final,
325     sizeof(SHA256_CTX),
326     32
327   }
328 };
329
330 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
331   {"sha-256", SHA256_DIGEST_PARAMS}
332 };
333
334 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
335   {"sha-1", SHA1_DIGEST_PARAMS}
336 };
337
338 static const metalink_digest_def MD5_DIGEST_DEF[] = {
339   {"md5", MD5_DIGEST_PARAMS}
340 };
341
342 /*
343  * The alias of supported hash functions in the order by preference
344  * (basically stronger hash comes first). We included "sha-256" and
345  * "sha256". The former is the name defined in the IANA registry named
346  * "Hash Function Textual Names". The latter is widely (and
347  * historically) used in Metalink version 3.
348  */
349 static const metalink_digest_alias digest_aliases[] = {
350   {"sha-256", SHA256_DIGEST_DEF},
351   {"sha256", SHA256_DIGEST_DEF},
352   {"sha-1", SHA1_DIGEST_DEF},
353   {"sha1", SHA1_DIGEST_DEF},
354   {"md5", MD5_DIGEST_DEF},
355   {NULL, NULL}
356 };
357
358 digest_context *Curl_digest_init(const digest_params *dparams)
359 {
360   digest_context *ctxt;
361
362   /* Create digest context */
363   ctxt = malloc(sizeof *ctxt);
364
365   if(!ctxt)
366     return ctxt;
367
368   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
369
370   if(!ctxt->digest_hashctx) {
371     free(ctxt);
372     return NULL;
373   }
374
375   ctxt->digest_hash = dparams;
376
377   dparams->digest_init(ctxt->digest_hashctx);
378
379   return ctxt;
380 }
381
382 int Curl_digest_update(digest_context *context,
383                        const unsigned char *data,
384                        unsigned int len)
385 {
386   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
387
388   return 0;
389 }
390
391 int Curl_digest_final(digest_context *context, unsigned char *result)
392 {
393   (*context->digest_hash->digest_final)(result, context->digest_hashctx);
394
395   free(context->digest_hashctx);
396   free(context);
397
398   return 0;
399 }
400
401 static unsigned char hex_to_uint(const char *s)
402 {
403   int v[2];
404   int i;
405   for(i = 0; i < 2; ++i) {
406     v[i] = Curl_raw_toupper(s[i]);
407     if('0' <= v[i] && v[i] <= '9') {
408       v[i] -= '0';
409     }
410     else if('A' <= v[i] && v[i] <= 'Z') {
411       v[i] -= 'A'-10;
412     }
413   }
414   return (unsigned char)((v[0] << 4) | v[1]);
415 }
416
417 /*
418  * Check checksum of file denoted by filename. The expected hash value
419  * is given in hex_hash which is hex-encoded string.
420  *
421  * This function returns 1 if it succeeds or one of the following
422  * integers:
423  *
424  * 0:
425  *   Checksum didn't match.
426  * -1:
427  *   Could not open file; or could not read data from file.
428  */
429 static int check_hash(const char *filename,
430                       const metalink_digest_def *digest_def,
431                       const unsigned char *digest, FILE *error)
432 {
433   unsigned char *result;
434   digest_context *dctx;
435   int check_ok, flags, fd;
436
437   flags = O_RDONLY;
438 #ifdef O_BINARY
439   /* O_BINARY is required in order to avoid binary EOF in text mode */
440   flags |= O_BINARY;
441 #endif
442
443   fd = open(filename, flags);
444   if(fd == -1) {
445     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
446             digest_def->hash_name, strerror(errno));
447     return -1;
448   }
449   dctx = Curl_digest_init(digest_def->dparams);
450   result = malloc(digest_def->dparams->digest_resultlen);
451   while(1) {
452     unsigned char buf[4096];
453     ssize_t len = read(fd, buf, sizeof(buf));
454     if(len == 0) {
455       break;
456     }
457     else if(len == -1) {
458       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
459               digest_def->hash_name, strerror(errno));
460       Curl_digest_final(dctx, result);
461       close(fd);
462       return -1;
463     }
464     Curl_digest_update(dctx, buf, (unsigned int)len);
465   }
466   Curl_digest_final(dctx, result);
467   check_ok = memcmp(result, digest,
468                     digest_def->dparams->digest_resultlen) == 0;
469   /* sha*sum style verdict output */
470   if(check_ok)
471     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
472             digest_def->hash_name);
473   else
474     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
475             filename, digest_def->hash_name);
476
477   free(result);
478   close(fd);
479   return check_ok;
480 }
481
482 int metalink_check_hash(struct Configurable *config,
483                         metalinkfile *mlfile,
484                         const char *filename)
485 {
486   int rv;
487   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
488   if(mlfile->checksum == NULL) {
489     fprintf(config->errors,
490             "Metalink: validating (%s) FAILED (digest missing)\n",
491             filename);
492     return -2;
493   }
494   rv = check_hash(filename, mlfile->checksum->digest_def,
495                   mlfile->checksum->digest, config->errors);
496   return rv;
497 }
498
499 static metalink_checksum *new_metalink_checksum_from_hex_digest
500 (const metalink_digest_def *digest_def, const char *hex_digest)
501 {
502   metalink_checksum *chksum;
503   unsigned char *digest;
504   size_t i;
505   size_t len = strlen(hex_digest);
506   digest = malloc(len/2);
507   for(i = 0; i < len; i += 2) {
508     digest[i/2] = hex_to_uint(hex_digest+i);
509   }
510   chksum = malloc(sizeof(metalink_checksum));
511   chksum->digest_def = digest_def;
512   chksum->digest = digest;
513   return chksum;
514 }
515
516 static metalink_resource *new_metalink_resource(const char *url)
517 {
518   metalink_resource *res;
519   res = malloc(sizeof(metalink_resource));
520   res->next = NULL;
521   res->url = strdup(url);
522   return res;
523 }
524
525 /* Returns nonzero if hex_digest is properly formatted; that is each
526    letter is in [0-9A-Za-z] and the length of the string equals to the
527    result length of digest * 2. */
528 static int check_hex_digest(const char *hex_digest,
529                             const metalink_digest_def *digest_def)
530 {
531   size_t i;
532   for(i = 0; hex_digest[i]; ++i) {
533     char c = hex_digest[i];
534     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
535          ('A' <= c && c <= 'Z'))) {
536       return 0;
537     }
538   }
539   return digest_def->dparams->digest_resultlen * 2 == i;
540 }
541
542 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
543 {
544   metalinkfile *f;
545   f = (metalinkfile*)malloc(sizeof(metalinkfile));
546   f->next = NULL;
547   f->filename = strdup(fileinfo->name);
548   f->checksum = NULL;
549   f->resource = NULL;
550   if(fileinfo->checksums) {
551     const metalink_digest_alias *digest_alias;
552     for(digest_alias = digest_aliases; digest_alias->alias_name;
553         ++digest_alias) {
554       metalink_checksum_t **p;
555       for(p = fileinfo->checksums; *p; ++p) {
556         if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
557            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
558           f->checksum =
559             new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
560                                                   (*p)->hash);
561           break;
562         }
563       }
564       if(f->checksum) {
565         break;
566       }
567     }
568   }
569   if(fileinfo->resources) {
570     metalink_resource_t **p;
571     metalink_resource root, *tail;
572     root.next = NULL;
573     tail = &root;
574     for(p = fileinfo->resources; *p; ++p) {
575       metalink_resource *res;
576       /* Filter by type if it is non-NULL. In Metalink v3, type
577          includes the type of the resource. In curl, we are only
578          interested in HTTP, HTTPS and FTP. In addition to them,
579          Metalink v3 file may contain bittorrent type URL, which
580          points to the BitTorrent metainfo file. We ignore it here.
581          In Metalink v4, type was deprecated and all
582          fileinfo->resources point to the target file. BitTorrent
583          metainfo file URL may be appeared in fileinfo->metaurls.
584       */
585       if((*p)->type == NULL ||
586          Curl_raw_equal((*p)->type, "http") ||
587          Curl_raw_equal((*p)->type, "https") ||
588          Curl_raw_equal((*p)->type, "ftp") ||
589          Curl_raw_equal((*p)->type, "ftps")) {
590         res = new_metalink_resource((*p)->url);
591         tail->next = res;
592         tail = res;
593       }
594     }
595     f->resource = root.next;
596   }
597   return f;
598 }
599
600 int parse_metalink(struct Configurable *config, struct OutStruct *outs,
601                    const char *metalink_url)
602 {
603   metalink_error_t r;
604   metalink_t* metalink;
605   metalink_file_t **files;
606   bool warnings = FALSE;
607
608   /* metlaink_parse_final deletes outs->metalink_parser */
609   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
610   outs->metalink_parser = NULL;
611   if(r != 0) {
612     return -1;
613   }
614   if(metalink->files == NULL) {
615     fprintf(config->errors, "Metalink: parsing (%s) WARNING "
616             "(missing or invalid file name)\n",
617             metalink_url);
618     metalink_delete(metalink);
619     return -1;
620   }
621   for(files = metalink->files; *files; ++files) {
622     struct getout *url;
623     /* Skip an entry which has no resource. */
624     if(!(*files)->resources) {
625       fprintf(config->errors, "Metalink: parsing (%s) WARNING "
626               "(missing or invalid resource)\n",
627               metalink_url, (*files)->name);
628       continue;
629     }
630     if(config->url_get ||
631        ((config->url_get = config->url_list) != NULL)) {
632       /* there's a node here, if it already is filled-in continue to
633          find an "empty" node */
634       while(config->url_get && (config->url_get->flags & GETOUT_URL))
635         config->url_get = config->url_get->next;
636     }
637
638     /* now there might or might not be an available node to fill in! */
639
640     if(config->url_get)
641       /* existing node */
642       url = config->url_get;
643     else
644       /* there was no free node, create one! */
645       url = new_getout(config);
646
647     if(url) {
648       metalinkfile *mlfile;
649       mlfile = new_metalinkfile(*files);
650       if(!mlfile->checksum) {
651         warnings = TRUE;
652         fprintf(config->errors, "Metalink: parsing (%s) WARNING "
653                 "(digest missing)\n",
654                 metalink_url);
655       }
656       /* Set name as url */
657       GetStr(&url->url, mlfile->filename);
658
659       /* set flag metalink here */
660       url->flags |= GETOUT_URL | GETOUT_METALINK;
661
662       if(config->metalinkfile_list) {
663         config->metalinkfile_last->next = mlfile;
664         config->metalinkfile_last = mlfile;
665       }
666       else {
667         config->metalinkfile_list = config->metalinkfile_last = mlfile;
668       }
669     }
670   }
671   metalink_delete(metalink);
672   return (warnings) ? -2 : 0;
673 }
674
675 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
676                          void *userdata)
677 {
678   struct OutStruct *outs = userdata;
679   struct Configurable *config = outs->config;
680   int rv;
681
682   /*
683    * Once that libcurl has called back tool_write_cb() the returned value
684    * is checked against the amount that was intended to be written, if
685    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
686    * point returning a value different from sz*nmemb indicates failure.
687    */
688   const size_t failure = (sz * nmemb) ? 0 : 1;
689
690   if(!config)
691     return failure;
692
693   rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
694   if(rv == 0)
695     return sz * nmemb;
696   else {
697     fprintf(config->errors, "Metalink: parsing FAILED\n");
698     return failure;
699   }
700 }
701
702 /*
703  * Returns nonzero if content_type includes mediatype.
704  */
705 static int check_content_type(const char *content_type, const char *media_type)
706 {
707   const char *ptr = content_type;
708   size_t media_type_len = strlen(media_type);
709   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
710   if(!*ptr) {
711     return 0;
712   }
713   return Curl_raw_nequal(ptr, media_type, media_type_len) &&
714     (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
715      *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
716 }
717
718 int check_metalink_content_type(const char *content_type)
719 {
720   return check_content_type(content_type, "application/metalink+xml");
721 }
722
723 int count_next_metalink_resource(metalinkfile *mlfile)
724 {
725   int count = 0;
726   metalink_resource *res;
727   for(res = mlfile->resource; res; res = res->next, ++count);
728   return count;
729 }
730
731 static void delete_metalink_checksum(metalink_checksum *chksum)
732 {
733   if(chksum == NULL) {
734     return;
735   }
736   Curl_safefree(chksum->digest);
737   Curl_safefree(chksum);
738 }
739
740 static void delete_metalink_resource(metalink_resource *res)
741 {
742   if(res == NULL) {
743     return;
744   }
745   Curl_safefree(res->url);
746   Curl_safefree(res);
747 }
748
749 static void delete_metalinkfile(metalinkfile *mlfile)
750 {
751   metalink_resource *res;
752   if(mlfile == NULL) {
753     return;
754   }
755   Curl_safefree(mlfile->filename);
756   delete_metalink_checksum(mlfile->checksum);
757   for(res = mlfile->resource; res;) {
758     metalink_resource *next;
759     next = res->next;
760     delete_metalink_resource(res);
761     res = next;
762   }
763   Curl_safefree(mlfile);
764 }
765
766 void clean_metalink(struct Configurable *config)
767 {
768   while(config->metalinkfile_list) {
769     metalinkfile *mlfile = config->metalinkfile_list;
770     config->metalinkfile_list = config->metalinkfile_list->next;
771     delete_metalinkfile(mlfile);
772   }
773   config->metalinkfile_last = 0;
774 }
775
776 #endif /* USE_METALINK */