Don't print whole json data buffer to errorstream on error
[oweals/minetest.git] / src / convert_json.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <vector>
21 #include <iostream>
22 #include <sstream>
23
24 #include "convert_json.h"
25 #include "mods.h"
26 #include "config.h"
27 #include "log.h"
28 #include "settings.h"
29 #include "httpfetch.h"
30 #include "porting.h"
31
32 Json::Value fetchJsonValue(const std::string &url,
33                 std::vector<std::string> *extra_headers)
34 {
35         HTTPFetchRequest fetch_request;
36         HTTPFetchResult fetch_result;
37         fetch_request.url = url;
38         fetch_request.caller = HTTPFETCH_SYNC;
39
40         if (extra_headers != NULL)
41                 fetch_request.extra_headers = *extra_headers;
42
43         httpfetch_sync(fetch_request, fetch_result);
44
45         if (!fetch_result.succeeded) {
46                 return Json::Value();
47         }
48         Json::Value root;
49         Json::Reader reader;
50         std::istringstream stream(fetch_result.data);
51
52         if (!reader.parse(stream, root)) {
53                 errorstream << "URL: " << url << std::endl;
54                 errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
55                 if (fetch_result.data.size() > 100) {
56                         errorstream << "Data (" << fetch_result.data.size()
57                                 << " bytes) printed to warningstream." << std::endl;
58                         warningstream << "data: \"" << fetch_result.data << "\"" << std::endl;
59                 } else {
60                         errorstream << "data: \"" << fetch_result.data << "\"" << std::endl;
61                 }
62                 return Json::Value();
63         }
64
65         return root;
66 }
67
68 std::vector<ModStoreMod>    readModStoreList(Json::Value& modlist) {
69                 std::vector<ModStoreMod> retval;
70
71         if (modlist.isArray()) {
72                 for (unsigned int i = 0; i < modlist.size(); i++)
73                 {
74                         ModStoreMod toadd;
75                         toadd.valid = true;
76
77                         //id
78                         if (modlist[i]["id"].asString().size()) {
79                                 std::string id_raw = modlist[i]["id"].asString();
80                                 char* endptr = 0;
81                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
82
83                                 if ((id_raw != "") && (*endptr == 0)) {
84                                         toadd.id = numbervalue;
85                                 }
86                                 else {
87                                         errorstream << "readModStoreList: missing id" << std::endl;
88                                         toadd.valid = false;
89                                 }
90                         }
91                         else {
92                                 errorstream << "readModStoreList: missing id" << std::endl;
93                                 toadd.valid = false;
94                         }
95
96                         //title
97                         if (modlist[i]["title"].asString().size()) {
98                                 toadd.title = modlist[i]["title"].asString();
99                         }
100                         else {
101                                 errorstream << "readModStoreList: missing title" << std::endl;
102                                 toadd.valid = false;
103                         }
104
105                         //basename
106                         if (modlist[i]["basename"].asString().size()) {
107                                 toadd.basename = modlist[i]["basename"].asString();
108                         }
109                         else {
110                                 errorstream << "readModStoreList: missing basename" << std::endl;
111                                 toadd.valid = false;
112                         }
113
114                         //author
115
116                         //rating
117
118                         //version
119
120                         if (toadd.valid) {
121                                 retval.push_back(toadd);
122                         }
123                 }
124         }
125         return retval;
126 }
127
128 ModStoreModDetails          readModStoreModDetails(Json::Value& details) {
129
130         ModStoreModDetails retval;
131
132         retval.valid = true;
133
134         //version set
135         if (details["version_set"].isArray()) {
136                 for (unsigned int i = 0; i < details["version_set"].size(); i++)
137                 {
138                         ModStoreVersionEntry toadd;
139
140                         if (details["version_set"][i]["id"].asString().size()) {
141                                 std::string id_raw = details["version_set"][i]["id"].asString();
142                                 char* endptr = 0;
143                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
144
145                                 if ((id_raw != "") && (*endptr == 0)) {
146                                         toadd.id = numbervalue;
147                                 }
148                         }
149                         else {
150                                 errorstream << "readModStoreModDetails: missing version_set id" << std::endl;
151                                 retval.valid = false;
152                         }
153
154                         //date
155                         if (details["version_set"][i]["date"].asString().size()) {
156                                 toadd.date = details["version_set"][i]["date"].asString();
157                         }
158
159                         //file
160                         if (details["version_set"][i]["file"].asString().size()) {
161                                 toadd.file = details["version_set"][i]["file"].asString();
162                         }
163                         else {
164                                 errorstream << "readModStoreModDetails: missing version_set file" << std::endl;
165                                 retval.valid = false;
166                         }
167
168                         //approved
169
170                         //mtversion
171
172                         if( retval.valid ) {
173                                 retval.versions.push_back(toadd);
174                         }
175                         else {
176                                 break;
177                         }
178                 }
179         }
180
181         if (retval.versions.size() < 1) {
182                 infostream << "readModStoreModDetails: not a single version specified!" << std::endl;
183                 retval.valid = false;
184         }
185
186         //categories
187         if (details["categories"].isObject()) {
188                 for (unsigned int i = 0; i < details["categories"].size(); i++) {
189                         ModStoreCategoryInfo toadd;
190
191                         if (details["categories"][i]["id"].asString().size()) {
192
193                                 std::string id_raw = details["categories"][i]["id"].asString();
194                                 char* endptr = 0;
195                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
196
197                                 if ((id_raw != "") && (*endptr == 0)) {
198                                         toadd.id = numbervalue;
199                                 }
200                         }
201                         else {
202                                 errorstream << "readModStoreModDetails: missing categories id" << std::endl;
203                                 retval.valid = false;
204                         }
205                         if (details["categories"][i]["title"].asString().size()) {
206                                 toadd.name = details["categories"][i]["title"].asString();
207                         }
208                         else {
209                                 errorstream << "readModStoreModDetails: missing categories title" << std::endl;
210                                 retval.valid = false;
211                         }
212
213                         if( retval.valid ) {
214                                 retval.categories.push_back(toadd);
215                         }
216                         else {
217                                 break;
218                         }
219                 }
220         }
221
222         //author
223         if (details["author"].isObject()) {
224                 if (details["author"]["id"].asString().size()) {
225
226                         std::string id_raw = details["author"]["id"].asString();
227                         char* endptr = 0;
228                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
229
230                         if ((id_raw != "") && (*endptr == 0)) {
231                                 retval.author.id = numbervalue;
232                         }
233                         else {
234                                 errorstream << "readModStoreModDetails: missing author id (convert)" << std::endl;
235                                 retval.valid = false;
236                         }
237                 }
238                 else {
239                         errorstream << "readModStoreModDetails: missing author id" << std::endl;
240                         retval.valid = false;
241                 }
242
243                 if (details["author"]["username"].asString().size()) {
244                         retval.author.username = details["author"]["username"].asString();
245                 }
246                 else {
247                         errorstream << "readModStoreModDetails: missing author username" << std::endl;
248                         retval.valid = false;
249                 }
250         }
251         else {
252                 errorstream << "readModStoreModDetails: missing author" << std::endl;
253                 retval.valid = false;
254         }
255
256         //license
257         if (details["license"].isObject()) {
258                 if (details["license"]["id"].asString().size()) {
259
260                         std::string id_raw = details["license"]["id"].asString();
261                         char* endptr = 0;
262                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
263
264                         if ((id_raw != "") && (*endptr == 0)) {
265                                 retval.license.id = numbervalue;
266                         }
267                 }
268                 else {
269                         errorstream << "readModStoreModDetails: missing license id" << std::endl;
270                         retval.valid = false;
271                 }
272
273                 if (details["license"]["short"].asString().size()) {
274                         retval.license.shortinfo = details["license"]["short"].asString();
275                 }
276                 else {
277                         errorstream << "readModStoreModDetails: missing license short" << std::endl;
278                         retval.valid = false;
279                 }
280
281                 if (details["license"]["link"].asString().size()) {
282                         retval.license.url = details["license"]["link"].asString();
283                 }
284
285         }
286
287         //titlepic
288         if (details["titlepic"].isObject()) {
289                 if (details["titlepic"]["id"].asString().size()) {
290
291                         std::string id_raw = details["titlepic"]["id"].asString();
292                         char* endptr = 0;
293                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
294
295                         if ((id_raw != "") && (*endptr == 0)) {
296                                 retval.titlepic.id = numbervalue;
297                         }
298                 }
299
300                 if (details["titlepic"]["file"].asString().size()) {
301                         retval.titlepic.file = details["titlepic"]["file"].asString();
302                 }
303
304                 if (details["titlepic"]["desc"].asString().size()) {
305                         retval.titlepic.description = details["titlepic"]["desc"].asString();
306                 }
307
308                 if (details["titlepic"]["mod"].asString().size()) {
309
310                         std::string mod_raw = details["titlepic"]["mod"].asString();
311                         char* endptr = 0;
312                         int numbervalue = strtol(mod_raw.c_str(),&endptr,10);
313
314                         if ((mod_raw != "") && (*endptr == 0)) {
315                                 retval.titlepic.mod = numbervalue;
316                         }
317                 }
318         }
319
320         //id
321         if (details["id"].asString().size()) {
322
323                 std::string id_raw = details["id"].asString();
324                 char* endptr = 0;
325                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
326
327                 if ((id_raw != "") && (*endptr == 0)) {
328                         retval.id = numbervalue;
329                 }
330         }
331         else {
332                 errorstream << "readModStoreModDetails: missing id" << std::endl;
333                 retval.valid = false;
334         }
335
336         //title
337         if (details["title"].asString().size()) {
338                 retval.title = details["title"].asString();
339         }
340         else {
341                 errorstream << "readModStoreModDetails: missing title" << std::endl;
342                 retval.valid = false;
343         }
344
345         //basename
346         if (details["basename"].asString().size()) {
347                 retval.basename = details["basename"].asString();
348         }
349         else {
350                 errorstream << "readModStoreModDetails: missing basename" << std::endl;
351                 retval.valid = false;
352         }
353
354         //description
355         if (details["desc"].asString().size()) {
356                 retval.description = details["desc"].asString();
357         }
358
359         //repository
360         if (details["replink"].asString().size()) {
361                 retval.repository = details["replink"].asString();
362         }
363
364         //value
365         if (details["value"].isInt()) {
366                 retval.rating = details["value"].asInt();
367         } else {
368                 retval.rating = 0;
369         }
370
371         //depends
372         if (details["depends"].isArray()) {
373                 //TODO
374         }
375
376         //softdepends
377         if (details["softdep"].isArray()) {
378                 //TODO
379         }
380
381         //screenshot url
382         if (details["screenshot_url"].asString().size()) {
383                 retval.screenshot_url = details["screenshot_url"].asString();
384         }
385
386         return retval;
387 }