Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / web / http_package_provider.cpp
blobb71f97467787a5a7bc57a03d70f1f7766e26d71c
1 // NeL - MMORPG Framework <https://wiki.ryzom.dev/>
2 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdweb.h"
18 #include <nel/web/http_package_provider.h>
20 // Project includes
21 #include <nel/misc/streamed_package.h>
22 #include <nel/misc/file.h>
23 #include <nel/misc/path.h>
24 #include <nel/misc/seven_zip.h>
25 #include <nel/misc/sha1.h>
27 using namespace std;
28 using namespace NLMISC;
29 using namespace NLWEB;
31 namespace NLWEB
34 CHttpPackageProvider::CHttpPackageProvider()
36 // init
39 CHttpPackageProvider::~CHttpPackageProvider()
41 // release
44 bool CHttpPackageProvider::getFile(std::string &filePath, const CHashKey &hash, const std::string &name)
46 CStreamedPackage::makePath(filePath, hash);
47 std::string downloadUrlFile = filePath + ".lzma";
48 filePath = Path + filePath;
49 std::string downloadPath = filePath + ".download." + toString(rand() * rand());
51 std::string storageDirectory = CFile::getPath(downloadPath);
52 CFile::createDirectoryTree(storageDirectory);
53 /*if (!CFile::isDirectory(storageDirectory) || !CFile::createDirectoryTree(storageDirectory))
55 nldebug("Unable to create directory '%s'", storageDirectory.c_str());
56 return false;
57 }*/
59 // download
60 for (;;)
62 if (CFile::fileExists(filePath))
63 return true;
65 std::string downloadUrl = Hosts[rand() % Hosts.size()] + downloadUrlFile;
66 nldebug("Download streamed package '%s' from '%s'", name.c_str(), downloadUrl.c_str());
68 FILE *fp = fopen(downloadPath.c_str(), "wb");
69 if (fp == NULL)
71 nldebug("Unable to create file '%s' for '%s'", downloadPath.c_str(), name.c_str());
72 return false;
75 CURL *curl;
76 CURLcode res;
77 curl = curl_easy_init();
78 if (curl)
80 curl_easy_setopt(curl, CURLOPT_URL, downloadUrl.c_str());
81 if (downloadUrl.length() > 8 && (downloadUrl[4] == 's' || downloadUrl[4] == 'S')) // 01234 https
83 // Don't need to verify, since we check the hash
84 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
85 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
87 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
88 curl_easy_setopt(curl, CURLOPT_FILE, fp);
89 res = curl_easy_perform(curl);
90 long r;
91 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r);
92 curl_easy_cleanup(curl);
94 bool diskFull = ferror(fp) && errno == 28 /*ENOSPC*/;
95 fclose(fp);
97 if (diskFull)
99 CFile::deleteFile(downloadPath);
100 throw EDiskFullError(downloadPath);
103 if (res != CURLE_OK || r < 200 || r >= 300)
105 CFile::deleteFile(downloadPath);
106 nldebug("Download failed '%s', retry in 1s", downloadUrl.c_str());
107 nlSleep(1000);
108 continue;
111 else
113 nldebug("Curl initialize failed");
114 fclose(fp);
115 CFile::deleteFile(downloadPath);
116 return false;
119 // ok!
120 break;
123 // extract into file
124 std::string unpackPath = filePath + ".extract." + toString(rand() * rand());
126 CHashKey outHash;
127 if (!unpackLZMA(downloadPath, unpackPath, outHash))
129 CFile::deleteFile(downloadPath);
130 return false;
132 CFile::deleteFile(downloadPath);
134 if (!(outHash == hash))
136 std::string wantHashS = hash.toString();
137 std::string outHashS = outHash.toString();
138 nlwarning("Invalid SHA1 hash for file '%s', download has hash '%s'", wantHashS.c_str(), outHashS.c_str());
139 return false;
142 if (!CFile::moveFile(filePath.c_str(), unpackPath.c_str()))
144 nldebug("Failed moving '%s' to '%s'", unpackPath.c_str(), filePath.c_str());
145 // in case downloaded from another thread
146 return CFile::fileExists(filePath);
149 return true;
152 } /* namespace NLMISC */
154 /* end of file */