Fixed segmentation fault when Metalink has no valid file or no resource.
[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 #include "rawstr.h"
25
26 #include "tool_metalink.h"
27 #include "tool_getparam.h"
28 #include "tool_paramhlp.h"
29
30 #include "memdebug.h" /* keep this as LAST include */
31
32 /* Copied from tool_getparam.c */
33 #define GetStr(str,val) do { \
34   if(*(str)) { \
35     free(*(str)); \
36     *(str) = NULL; \
37   } \
38   if((val)) \
39     *(str) = strdup((val)); \
40   if(!(val)) \
41     return PARAM_NO_MEM; \
42 } WHILE_FALSE
43
44 struct metalinkfile *new_metalinkfile(metalink_file_t *metalinkfile) {
45   struct metalinkfile *f;
46   f = (struct metalinkfile*)malloc(sizeof(struct metalinkfile));
47   f->file = metalinkfile;
48   f->next = NULL;
49   return f;
50 }
51
52 struct metalink *new_metalink(metalink_t *metalink) {
53   struct metalink *ml;
54   ml = (struct metalink*)malloc(sizeof(struct metalink));
55   ml->metalink = metalink;
56   ml->next = NULL;
57   return ml;
58 }
59
60 int count_next_metalink_resource(struct metalinkfile *mlfile)
61 {
62   int count = 0;
63   metalink_resource_t **mlres;
64   for(mlres = mlfile->file->resources; *mlres; ++mlres, ++count);
65   return count;
66 }
67
68 void clean_metalink(struct Configurable *config)
69 {
70   while(config->metalinkfile_list) {
71     struct metalinkfile *mlfile = config->metalinkfile_list;
72     config->metalinkfile_list = config->metalinkfile_list->next;
73     Curl_safefree(mlfile);
74   }
75   config->metalinkfile_last = 0;
76   while(config->metalink_list) {
77     struct metalink *ml = config->metalink_list;
78     config->metalink_list = config->metalink_list->next;
79     metalink_delete(ml->metalink);
80     Curl_safefree(ml);
81   }
82   config->metalink_last = 0;
83 }
84
85 int parse_metalink(struct Configurable *config, const char *infile)
86 {
87   metalink_error_t r;
88   metalink_t* metalink;
89   metalink_file_t **files;
90   struct metalink *ml;
91
92   r = metalink_parse_file(infile, &metalink);
93
94   if(r != 0) {
95     return -1;
96   }
97   if(metalink->files == NULL) {
98     fprintf(config->errors, "\nMetalink does not contain any file.\n");
99     return 0;
100   }
101   ml = new_metalink(metalink);
102
103   if(config->metalink_list) {
104     config->metalink_last->next = ml;
105     config->metalink_last = ml;
106   }
107   else {
108     config->metalink_list = config->metalink_last = ml;
109   }
110
111   for(files = metalink->files; *files; ++files) {
112     struct getout *url;
113     /* Skip an entry which has no resource. */
114     if(!(*files)->resources) {
115       fprintf(config->errors, "\nFile %s does not have any resource.\n",
116               (*files)->name);
117       continue;
118     }
119     if(config->url_get ||
120        ((config->url_get = config->url_list) != NULL)) {
121       /* there's a node here, if it already is filled-in continue to
122          find an "empty" node */
123       while(config->url_get && (config->url_get->flags & GETOUT_URL))
124         config->url_get = config->url_get->next;
125     }
126
127     /* now there might or might not be an available node to fill in! */
128
129     if(config->url_get)
130       /* existing node */
131       url = config->url_get;
132     else
133       /* there was no free node, create one! */
134       url=new_getout(config);
135
136     if(url) {
137       struct metalinkfile *mlfile;
138       /* Set name as url */
139       GetStr(&url->url, (*files)->name);
140
141       /* set flag metalink here */
142       url->flags |= GETOUT_URL | GETOUT_METALINK;
143       mlfile = new_metalinkfile(*files);
144
145       if(config->metalinkfile_list) {
146         config->metalinkfile_last->next = mlfile;
147         config->metalinkfile_last = mlfile;
148       }
149       else {
150         config->metalinkfile_list = config->metalinkfile_last = mlfile;
151       }
152     }
153   }
154   return 0;
155 }
156
157 /*
158  * Returns nonzero if content_type includes mediatype.
159  */
160 static int check_content_type(const char *content_type, const char *media_type)
161 {
162   const char *ptr = content_type;
163   size_t media_type_len = strlen(media_type);
164   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
165   if(!*ptr) {
166     return 0;
167   }
168   return Curl_raw_nequal(ptr, media_type, media_type_len) &&
169     (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
170      *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
171 }
172
173 int check_metalink_content_type(const char *content_type)
174 {
175   return check_content_type(content_type, "application/metalink+xml");
176 }