From 208d43c7988c527691b663e4e00b56b42cc19277 Mon Sep 17 00:00:00 2001 From: "Angelo Mantellini (manangel)" Date: Tue, 25 Apr 2017 21:17:37 +0200 Subject: correction link libraries libcurl Change-Id: I8be291ac6b9ec15f0f7bbaa8b434da9d319ae389 Signed-off-by: Angelo Mantellini (manangel) --- .../jni/libcurl/src/tool_metalink.c | 963 +++++++++++++++++++++ 1 file changed, 963 insertions(+) create mode 100755 external/libcurl_android/jni/libcurl/src/tool_metalink.c (limited to 'external/libcurl_android/jni/libcurl/src/tool_metalink.c') diff --git a/external/libcurl_android/jni/libcurl/src/tool_metalink.c b/external/libcurl_android/jni/libcurl/src/tool_metalink.c new file mode 100755 index 00000000..3573b058 --- /dev/null +++ b/external/libcurl_android/jni/libcurl/src/tool_metalink.c @@ -0,0 +1,963 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef USE_METALINK + +#include + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef USE_SSLEAY +# ifdef USE_OPENSSL +# include +# include +# else +# include +# include +# endif +#elif defined(USE_GNUTLS_NETTLE) +# include +# include +# define MD5_CTX struct md5_ctx +# define SHA_CTX struct sha1_ctx +# define SHA256_CTX struct sha256_ctx +#elif defined(USE_GNUTLS) +# include +# define MD5_CTX gcry_md_hd_t +# define SHA_CTX gcry_md_hd_t +# define SHA256_CTX gcry_md_hd_t +#elif defined(USE_NSS) +# include +# include +# define MD5_CTX void * +# define SHA_CTX void * +# define SHA256_CTX void * + static NSSInitContext *nss_context; +#elif defined(USE_POLARSSL) +# include +# include +# include +# define MD5_CTX md5_context +# define SHA_CTX sha1_context +# define SHA256_CTX sha256_context +#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ + (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ + (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) +/* For Apple operating systems: CommonCrypto has the functions we need. + The library's headers are even backward-compatible with OpenSSL's + headers as long as we define COMMON_DIGEST_FOR_OPENSSL first. + + These functions are available on Tiger and later, as well as iOS 2.0 + and later. If you're building for an older cat, well, sorry. */ +# define COMMON_DIGEST_FOR_OPENSSL +# include +#elif defined(_WIN32) +/* For Windows: If no other crypto library is provided, we fallback + to the hash functions provided within the Microsoft Windows CryptoAPI */ +# include +/* Custom structure in order to store the required provider and hash handle */ +struct win32_crypto_hash { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; +}; +/* Custom Microsoft AES Cryptographic Provider defines required for MinGW */ +# ifndef ALG_SID_SHA_256 +# define ALG_SID_SHA_256 12 +# endif +# ifndef CALG_SHA_256 +# define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) +# endif +# define MD5_CTX struct win32_crypto_hash +# define SHA_CTX struct win32_crypto_hash +# define SHA256_CTX struct win32_crypto_hash +#else +# error "Can't compile METALINK support without a crypto library." +#endif + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_getparam.h" +#include "tool_paramhlp.h" +#include "tool_cfgable.h" +#include "tool_metalink.h" +#include "tool_msgs.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 + +#ifdef USE_GNUTLS_NETTLE + +static int MD5_Init(MD5_CTX *ctx) +{ + md5_init(ctx); + return 1; +} + +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + md5_update(ctx, inputLen, input); +} + +static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +{ + md5_digest(ctx, 16, digest); +} + +static int SHA1_Init(SHA_CTX *ctx) +{ + sha1_init(ctx); + return 1; +} + +static void SHA1_Update(SHA_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + sha1_update(ctx, inputLen, input); +} + +static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) +{ + sha1_digest(ctx, 20, digest); +} + +static int SHA256_Init(SHA256_CTX *ctx) +{ + sha256_init(ctx); + return 1; +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + sha256_update(ctx, inputLen, input); +} + +static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) +{ + sha256_digest(ctx, 32, digest); +} + +#elif defined(USE_GNUTLS) + +static int MD5_Init(MD5_CTX *ctx) +{ + gcry_md_open(ctx, GCRY_MD_MD5, 0); + return 1; +} + +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + gcry_md_write(*ctx, input, inputLen); +} + +static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +{ + memcpy(digest, gcry_md_read(*ctx, 0), 16); + gcry_md_close(*ctx); +} + +static int SHA1_Init(SHA_CTX *ctx) +{ + gcry_md_open(ctx, GCRY_MD_SHA1, 0); + return 1; +} + +static void SHA1_Update(SHA_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + gcry_md_write(*ctx, input, inputLen); +} + +static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) +{ + memcpy(digest, gcry_md_read(*ctx, 0), 20); + gcry_md_close(*ctx); +} + +static int SHA256_Init(SHA256_CTX *ctx) +{ + gcry_md_open(ctx, GCRY_MD_SHA256, 0); + return 1; +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + gcry_md_write(*ctx, input, inputLen); +} + +static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) +{ + memcpy(digest, gcry_md_read(*ctx, 0), 32); + gcry_md_close(*ctx); +} + +#elif defined(USE_NSS) + +static int nss_hash_init(void **pctx, SECOidTag hash_alg) +{ + PK11Context *ctx; + + /* we have to initialize NSS if not initialized alraedy */ + if(!NSS_IsInitialized() && !nss_context) { + static NSSInitParameters params; + params.length = sizeof params; + nss_context = NSS_InitContext("", "", "", "", ¶ms, NSS_INIT_READONLY + | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN + | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); + } + + ctx = PK11_CreateDigestContext(hash_alg); + if(!ctx) + return /* failure */ 0; + + if(PK11_DigestBegin(ctx) != SECSuccess) { + PK11_DestroyContext(ctx, PR_TRUE); + return /* failure */ 0; + } + + *pctx = ctx; + return /* success */ 1; +} + +static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len) +{ + PK11Context *ctx = *pctx; + unsigned int outlen; + PK11_DigestFinal(ctx, out, &outlen, len); + PK11_DestroyContext(ctx, PR_TRUE); +} + +static int MD5_Init(MD5_CTX *pctx) +{ + return nss_hash_init(pctx, SEC_OID_MD5); +} + +static void MD5_Update(MD5_CTX *pctx, + const unsigned char *input, + unsigned int input_len) +{ + PK11_DigestOp(*pctx, input, input_len); +} + +static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx) +{ + nss_hash_final(pctx, digest, 16); +} + +static int SHA1_Init(SHA_CTX *pctx) +{ + return nss_hash_init(pctx, SEC_OID_SHA1); +} + +static void SHA1_Update(SHA_CTX *pctx, + const unsigned char *input, + unsigned int input_len) +{ + PK11_DigestOp(*pctx, input, input_len); +} + +static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx) +{ + nss_hash_final(pctx, digest, 20); +} + +static int SHA256_Init(SHA256_CTX *pctx) +{ + return nss_hash_init(pctx, SEC_OID_SHA256); +} + +static void SHA256_Update(SHA256_CTX *pctx, + const unsigned char *input, + unsigned int input_len) +{ + PK11_DigestOp(*pctx, input, input_len); +} + +static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx) +{ + nss_hash_final(pctx, digest, 32); +} + +#elif defined(USE_POLARSSL) + +static int MD5_Init(MD5_CTX *ctx) +{ + md5_starts(ctx); + return 1; +} + +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + md5_update(ctx, input, inputLen); +} + +static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +{ + md5_finish(ctx, digest); +} + +static int SHA1_Init(SHA_CTX *ctx) +{ + sha1_starts(ctx); + return 1; +} + +static void SHA1_Update(SHA_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + sha1_update(ctx, input, inputLen); +} + +static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) +{ + sha1_finish(ctx, digest); +} + +static int SHA256_Init(SHA256_CTX *ctx) +{ + sha256_starts(ctx, 0); /* 0 = sha256 */ + return 1; +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + sha256_update(ctx, input, inputLen); +} + +static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) +{ + sha256_finish(ctx, digest); +} + +#elif defined(_WIN32) && !defined(USE_SSLEAY) + +static void win32_crypto_final(struct win32_crypto_hash *ctx, + unsigned char *digest, + unsigned int digestLen) +{ + unsigned long length; + CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); + if(length == digestLen) + CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); + if(ctx->hHash) + CryptDestroyHash(ctx->hHash); + if(ctx->hCryptProv) + CryptReleaseContext(ctx->hCryptProv, 0); +} + +static int MD5_Init(MD5_CTX *ctx) +{ + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); + } + return 1; +} + +static void MD5_Update(MD5_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); +} + +static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) +{ + win32_crypto_final(ctx, digest, 16); +} + +static int SHA1_Init(SHA_CTX *ctx) +{ + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash); + } + return 1; +} + +static void SHA1_Update(SHA_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); +} + +static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) +{ + win32_crypto_final(ctx, digest, 20); +} + +static int SHA256_Init(SHA256_CTX *ctx) +{ + if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, + PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); + } + return 1; +} + +static void SHA256_Update(SHA256_CTX *ctx, + const unsigned char *input, + unsigned int inputLen) +{ + CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); +} + +static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) +{ + win32_crypto_final(ctx, digest, 32); +} + +#endif /* CRYPTO LIBS */ + +const digest_params MD5_DIGEST_PARAMS[] = { + { + (Curl_digest_init_func) MD5_Init, + (Curl_digest_update_func) MD5_Update, + (Curl_digest_final_func) MD5_Final, + sizeof(MD5_CTX), + 16 + } +}; + +const digest_params SHA1_DIGEST_PARAMS[] = { + { + (Curl_digest_init_func) SHA1_Init, + (Curl_digest_update_func) SHA1_Update, + (Curl_digest_final_func) SHA1_Final, + sizeof(SHA_CTX), + 20 + } +}; + +const digest_params SHA256_DIGEST_PARAMS[] = { + { + (Curl_digest_init_func) SHA256_Init, + (Curl_digest_update_func) SHA256_Update, + (Curl_digest_final_func) SHA256_Final, + sizeof(SHA256_CTX), + 32 + } +}; + +static const metalink_digest_def SHA256_DIGEST_DEF[] = { + {"sha-256", SHA256_DIGEST_PARAMS} +}; + +static const metalink_digest_def SHA1_DIGEST_DEF[] = { + {"sha-1", SHA1_DIGEST_PARAMS} +}; + +static const metalink_digest_def MD5_DIGEST_DEF[] = { + {"md5", MD5_DIGEST_PARAMS} +}; + +/* + * The alias of supported hash functions in the order by preference + * (basically stronger hash comes first). We included "sha-256" and + * "sha256". The former is the name defined in the IANA registry named + * "Hash Function Textual Names". The latter is widely (and + * historically) used in Metalink version 3. + */ +static const metalink_digest_alias digest_aliases[] = { + {"sha-256", SHA256_DIGEST_DEF}, + {"sha256", SHA256_DIGEST_DEF}, + {"sha-1", SHA1_DIGEST_DEF}, + {"sha1", SHA1_DIGEST_DEF}, + {"md5", MD5_DIGEST_DEF}, + {NULL, NULL} +}; + +digest_context *Curl_digest_init(const digest_params *dparams) +{ + digest_context *ctxt; + + /* Create digest context */ + ctxt = malloc(sizeof *ctxt); + + if(!ctxt) + return ctxt; + + ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize); + + if(!ctxt->digest_hashctx) { + free(ctxt); + return NULL; + } + + ctxt->digest_hash = dparams; + + if(dparams->digest_init(ctxt->digest_hashctx) != 1) { + free(ctxt); + return NULL; + } + + return ctxt; +} + +int Curl_digest_update(digest_context *context, + const unsigned char *data, + unsigned int len) +{ + (*context->digest_hash->digest_update)(context->digest_hashctx, data, len); + + return 0; +} + +int Curl_digest_final(digest_context *context, unsigned char *result) +{ + (*context->digest_hash->digest_final)(result, context->digest_hashctx); + + free(context->digest_hashctx); + free(context); + + return 0; +} + +static unsigned char hex_to_uint(const char *s) +{ + int v[2]; + int i; + for(i = 0; i < 2; ++i) { + v[i] = Curl_raw_toupper(s[i]); + if('0' <= v[i] && v[i] <= '9') { + v[i] -= '0'; + } + else if('A' <= v[i] && v[i] <= 'Z') { + v[i] -= 'A'-10; + } + } + return (unsigned char)((v[0] << 4) | v[1]); +} + +/* + * Check checksum of file denoted by filename. The expected hash value + * is given in hex_hash which is hex-encoded string. + * + * This function returns 1 if it succeeds or one of the following + * integers: + * + * 0: + * Checksum didn't match. + * -1: + * Could not open file; or could not read data from file. + * -2: + * Hash algorithm not available. + */ +static int check_hash(const char *filename, + const metalink_digest_def *digest_def, + const unsigned char *digest, FILE *error) +{ + unsigned char *result; + digest_context *dctx; + int check_ok, flags, fd; + + flags = O_RDONLY; +#ifdef O_BINARY + /* O_BINARY is required in order to avoid binary EOF in text mode */ + flags |= O_BINARY; +#endif + + fd = open(filename, flags); + if(fd == -1) { + fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, + digest_def->hash_name, strerror(errno)); + return -1; + } + + dctx = Curl_digest_init(digest_def->dparams); + if(!dctx) { + fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, + digest_def->hash_name, "failed to initialize hash algorithm"); + close(fd); + return -2; + } + + result = malloc(digest_def->dparams->digest_resultlen); + while(1) { + unsigned char buf[4096]; + ssize_t len = read(fd, buf, sizeof(buf)); + if(len == 0) { + break; + } + else if(len == -1) { + fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename, + digest_def->hash_name, strerror(errno)); + Curl_digest_final(dctx, result); + close(fd); + return -1; + } + Curl_digest_update(dctx, buf, (unsigned int)len); + } + 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, "Metalink: validating (%s) [%s] OK\n", filename, + digest_def->hash_name); + else + fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n", + filename, digest_def->hash_name); + + free(result); + close(fd); + return check_ok; +} + +int metalink_check_hash(struct GlobalConfig *config, + metalinkfile *mlfile, + const char *filename) +{ + int rv; + fprintf(config->errors, "Metalink: validating (%s)...\n", filename); + if(mlfile->checksum == NULL) { + fprintf(config->errors, + "Metalink: validating (%s) FAILED (digest missing)\n", filename); + return -2; + } + rv = check_hash(filename, mlfile->checksum->digest_def, + mlfile->checksum->digest, config->errors); + return rv; +} + +static metalink_checksum *new_metalink_checksum_from_hex_digest +(const metalink_digest_def *digest_def, const char *hex_digest) +{ + metalink_checksum *chksum; + unsigned char *digest; + size_t i; + size_t len = strlen(hex_digest); + digest = malloc(len/2); + for(i = 0; i < len; i += 2) { + digest[i/2] = hex_to_uint(hex_digest+i); + } + chksum = malloc(sizeof(metalink_checksum)); + chksum->digest_def = digest_def; + chksum->digest = digest; + return chksum; +} + +static metalink_resource *new_metalink_resource(const char *url) +{ + metalink_resource *res; + res = malloc(sizeof(metalink_resource)); + res->next = NULL; + res->url = strdup(url); + return res; +} + +/* Returns nonzero if hex_digest is properly formatted; that is each + letter is in [0-9A-Za-z] and the length of the string equals to the + result length of digest * 2. */ +static int check_hex_digest(const char *hex_digest, + const metalink_digest_def *digest_def) +{ + size_t i; + for(i = 0; hex_digest[i]; ++i) { + char c = hex_digest[i]; + if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z'))) { + return 0; + } + } + return digest_def->dparams->digest_resultlen * 2 == i; +} + +static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo) +{ + metalinkfile *f; + f = (metalinkfile*)malloc(sizeof(metalinkfile)); + f->next = NULL; + f->filename = strdup(fileinfo->name); + f->checksum = NULL; + f->resource = NULL; + if(fileinfo->checksums) { + const metalink_digest_alias *digest_alias; + for(digest_alias = digest_aliases; digest_alias->alias_name; + ++digest_alias) { + metalink_checksum_t **p; + for(p = fileinfo->checksums; *p; ++p) { + if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) && + check_hex_digest((*p)->hash, digest_alias->digest_def)) { + f->checksum = + new_metalink_checksum_from_hex_digest(digest_alias->digest_def, + (*p)->hash); + break; + } + } + if(f->checksum) { + break; + } + } + } + if(fileinfo->resources) { + metalink_resource_t **p; + metalink_resource root, *tail; + root.next = NULL; + tail = &root; + for(p = fileinfo->resources; *p; ++p) { + metalink_resource *res; + /* Filter by type if it is non-NULL. In Metalink v3, type + includes the type of the resource. In curl, we are only + interested in HTTP, HTTPS and FTP. In addition to them, + Metalink v3 file may contain bittorrent type URL, which + points to the BitTorrent metainfo file. We ignore it here. + In Metalink v4, type was deprecated and all + fileinfo->resources point to the target file. BitTorrent + metainfo file URL may be appeared in fileinfo->metaurls. + */ + if((*p)->type == NULL || + Curl_raw_equal((*p)->type, "http") || + Curl_raw_equal((*p)->type, "https") || + Curl_raw_equal((*p)->type, "ftp") || + Curl_raw_equal((*p)->type, "ftps")) { + res = new_metalink_resource((*p)->url); + tail->next = res; + tail = res; + } + } + f->resource = root.next; + } + return f; +} + +int parse_metalink(struct OperationConfig *config, struct OutStruct *outs, + const char *metalink_url) +{ + metalink_error_t r; + metalink_t* metalink; + metalink_file_t **files; + bool warnings = FALSE; + + /* 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; + } + if(metalink->files == NULL) { + fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " + "(missing or invalid file name)\n", + metalink_url); + metalink_delete(metalink); + return -1; + } + for(files = metalink->files; *files; ++files) { + struct getout *url; + /* Skip an entry which has no resource. */ + if(!(*files)->resources) { + fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " + "(missing or invalid resource)\n", + metalink_url, (*files)->name); + 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) { + metalinkfile *mlfile; + mlfile = new_metalinkfile(*files); + if(!mlfile->checksum) { + warnings = TRUE; + fprintf(config->global->errors, + "Metalink: parsing (%s) WARNING (digest missing)\n", + metalink_url); + } + /* Set name as url */ + GetStr(&url->url, mlfile->filename); + + /* set flag metalink here */ + url->flags |= GETOUT_URL | GETOUT_METALINK; + + if(config->metalinkfile_list) { + config->metalinkfile_last->next = mlfile; + config->metalinkfile_last = mlfile; + } + else { + config->metalinkfile_list = config->metalinkfile_last = mlfile; + } + } + } + metalink_delete(metalink); + return (warnings) ? -2 : 0; +} + +size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, + void *userdata) +{ + struct OutStruct *outs = userdata; + struct OperationConfig *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 { + fprintf(config->global->errors, "Metalink: parsing FAILED\n"); + return failure; + } +} + +/* + * Returns nonzero if content_type includes mediatype. + */ +static int check_content_type(const char *content_type, const char *media_type) +{ + const char *ptr = content_type; + size_t media_type_len = strlen(media_type); + for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr); + if(!*ptr) { + return 0; + } + return Curl_raw_nequal(ptr, media_type, media_type_len) && + (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' || + *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';'); +} + +int check_metalink_content_type(const char *content_type) +{ + return check_content_type(content_type, "application/metalink+xml"); +} + +int count_next_metalink_resource(metalinkfile *mlfile) +{ + int count = 0; + metalink_resource *res; + for(res = mlfile->resource; res; res = res->next, ++count); + return count; +} + +static void delete_metalink_checksum(metalink_checksum *chksum) +{ + if(chksum == NULL) { + return; + } + Curl_safefree(chksum->digest); + Curl_safefree(chksum); +} + +static void delete_metalink_resource(metalink_resource *res) +{ + if(res == NULL) { + return; + } + Curl_safefree(res->url); + Curl_safefree(res); +} + +static void delete_metalinkfile(metalinkfile *mlfile) +{ + metalink_resource *res; + if(mlfile == NULL) { + return; + } + Curl_safefree(mlfile->filename); + delete_metalink_checksum(mlfile->checksum); + for(res = mlfile->resource; res;) { + metalink_resource *next; + next = res->next; + delete_metalink_resource(res); + res = next; + } + Curl_safefree(mlfile); +} + +void clean_metalink(struct OperationConfig *config) +{ + while(config->metalinkfile_list) { + metalinkfile *mlfile = config->metalinkfile_list; + config->metalinkfile_list = config->metalinkfile_list->next; + delete_metalinkfile(mlfile); + } + config->metalinkfile_last = 0; +} + +void metalink_cleanup(void) +{ +#ifdef USE_NSS + if(nss_context) { + NSS_ShutdownContext(nss_context); + nss_context = NULL; + } +#endif +} + +#endif /* USE_METALINK */ -- cgit 1.2.3-korg