1 // NeL - MMORPG Framework <https://wiki.ryzom.dev/>
2 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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.
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/>.
18 #include <nel/web/http_package_provider.h>
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>
28 using namespace NLMISC
;
29 using namespace NLWEB
;
34 CHttpPackageProvider::CHttpPackageProvider()
39 CHttpPackageProvider::~CHttpPackageProvider()
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());
62 if (CFile::fileExists(filePath
))
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");
71 nldebug("Unable to create file '%s' for '%s'", downloadPath
.c_str(), name
.c_str());
77 curl
= curl_easy_init();
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
);
91 curl_easy_getinfo(curl
, CURLINFO_RESPONSE_CODE
, &r
);
92 curl_easy_cleanup(curl
);
94 bool diskFull
= ferror(fp
) && errno
== 28 /*ENOSPC*/;
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());
113 nldebug("Curl initialize failed");
115 CFile::deleteFile(downloadPath
);
124 std::string unpackPath
= filePath
+ ".extract." + toString(rand() * rand());
127 if (!unpackLZMA(downloadPath
, unpackPath
, outHash
))
129 CFile::deleteFile(downloadPath
);
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());
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
);
152 } /* namespace NLMISC */