diff options
| author | Alexander Karatarakis <alkarata@microsoft.com> | 2018-06-19 16:59:27 -0700 |
|---|---|---|
| committer | Alexander Karatarakis <alkarata@microsoft.com> | 2018-06-19 23:07:31 -0700 |
| commit | 3e76baa163880f59fc344dcff58fd48e526b4a39 (patch) | |
| tree | 682bfa6297b01df0351151509b96386d817976fa | |
| parent | 84d65840ab5a36dc095826496a8213ac2404a216 (diff) | |
| download | vcpkg-3e76baa163880f59fc344dcff58fd48e526b4a39.tar.gz vcpkg-3e76baa163880f59fc344dcff58fd48e526b4a39.zip | |
Introduce downloads.h/cpp
| -rw-r--r-- | toolsrc/include/vcpkg/base/downloads.h | 16 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/base/downloads.cpp | 142 | ||||
| -rw-r--r-- | toolsrc/src/vcpkg/commands.fetch.cpp | 138 | ||||
| -rw-r--r-- | toolsrc/vcpkglib/vcpkglib.vcxproj | 2 | ||||
| -rw-r--r-- | toolsrc/vcpkglib/vcpkglib.vcxproj.filters | 6 |
5 files changed, 169 insertions, 135 deletions
diff --git a/toolsrc/include/vcpkg/base/downloads.h b/toolsrc/include/vcpkg/base/downloads.h new file mode 100644 index 000000000..f30e865a6 --- /dev/null +++ b/toolsrc/include/vcpkg/base/downloads.h @@ -0,0 +1,16 @@ +#pragma once
+
+#include <vcpkg/base/files.h>
+
+namespace vcpkg::Downloads
+{
+ void verify_downloaded_file_hash(const Files::Filesystem& fs,
+ const std::string& url,
+ const fs::path& path,
+ const std::string& sha512);
+
+ void download_file(vcpkg::Files::Filesystem& fs,
+ const std::string& url,
+ const fs::path& download_path,
+ const std::string& sha512);
+}
diff --git a/toolsrc/src/vcpkg/base/downloads.cpp b/toolsrc/src/vcpkg/base/downloads.cpp new file mode 100644 index 000000000..a5ee05391 --- /dev/null +++ b/toolsrc/src/vcpkg/base/downloads.cpp @@ -0,0 +1,142 @@ +#include "pch.h" + +#include <vcpkg/base/downloads.h> +#include <vcpkg/base/util.h> +#include <vcpkg/commands.h> + +namespace vcpkg::Downloads +{ +#if defined(_WIN32) + static void winhttp_download_file(Files::Filesystem& fs, + CStringView target_file_path, + CStringView hostname, + CStringView url_path) + { + // Make sure the directories are present, otherwise fopen_s fails + const auto dir = fs::path(target_file_path.c_str()).parent_path(); + std::error_code ec; + fs.create_directories(dir, ec); + Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not create directories %s", dir.u8string()); + + FILE* f = nullptr; + const errno_t err = fopen_s(&f, target_file_path.c_str(), "wb"); + Checks::check_exit(VCPKG_LINE_INFO, + !err, + "Could not download https://%s%s. Failed to open file %s. Error code was %s", + hostname, + url_path, + target_file_path, + std::to_string(err)); + + auto hSession = WinHttpOpen( + L"vcpkg/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + Checks::check_exit(VCPKG_LINE_INFO, hSession, "WinHttpOpen() failed: %d", GetLastError()); + + // Use Windows 10 defaults on Windows 7 + DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | + WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); + WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); + + // Specify an HTTP server. + auto hConnect = WinHttpConnect(hSession, Strings::to_utf16(hostname).c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0); + Checks::check_exit(VCPKG_LINE_INFO, hConnect, "WinHttpConnect() failed: %d", GetLastError()); + + // Create an HTTP request handle. + auto hRequest = WinHttpOpenRequest(hConnect, + L"GET", + Strings::to_utf16(url_path).c_str(), + nullptr, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + WINHTTP_FLAG_SECURE); + Checks::check_exit(VCPKG_LINE_INFO, hRequest, "WinHttpOpenRequest() failed: %d", GetLastError()); + + // Send a request. + auto bResults = + WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); + Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpSendRequest() failed: %d", GetLastError()); + + // End the request. + bResults = WinHttpReceiveResponse(hRequest, NULL); + Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReceiveResponse() failed: %d", GetLastError()); + + std::vector<char> buf; + + size_t total_downloaded_size = 0; + DWORD dwSize = 0; + do + { + DWORD downloaded_size = 0; + bResults = WinHttpQueryDataAvailable(hRequest, &dwSize); + Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpQueryDataAvailable() failed: %d", GetLastError()); + + if (buf.size() < dwSize) buf.resize(dwSize * 2); + + bResults = WinHttpReadData(hRequest, (LPVOID)buf.data(), dwSize, &downloaded_size); + Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReadData() failed: %d", GetLastError()); + fwrite(buf.data(), 1, downloaded_size, f); + + total_downloaded_size += downloaded_size; + } while (dwSize > 0); + + WinHttpCloseHandle(hSession); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hRequest); + fflush(f); + fclose(f); + } +#endif + + void verify_downloaded_file_hash(const Files::Filesystem& fs, + const std::string& url, + const fs::path& path, + const std::string& sha512) + { + const std::string actual_hash = Commands::Hash::get_file_hash(fs, path, "SHA512"); + Checks::check_exit(VCPKG_LINE_INFO, + sha512 == actual_hash, + "File does not have the expected hash:\n" + " url : [ %s ]\n" + " File path : [ %s ]\n" + " Expected hash : [ %s ]\n" + " Actual hash : [ %s ]\n", + url, + path.u8string(), + sha512, + actual_hash); + } + + void download_file(vcpkg::Files::Filesystem& fs, + const std::string& url, + const fs::path& download_path, + const std::string& sha512) + { + const std::string download_path_part = download_path.u8string() + ".part"; + std::error_code ec; + fs.remove(download_path, ec); + fs.remove(download_path_part, ec); +#if defined(_WIN32) + auto url_no_proto = url.substr(8); // drop https:// + auto path_begin = Util::find(url_no_proto, '/'); + std::string hostname(url_no_proto.begin(), path_begin); + std::string path(path_begin, url_no_proto.end()); + + winhttp_download_file(fs, download_path_part.c_str(), hostname, path); +#else + const auto code = System::cmd_execute( + Strings::format(R"(curl -L '%s' --create-dirs --output '%s')", url, download_path_part)); + Checks::check_exit(VCPKG_LINE_INFO, code == 0, "Could not download %s", url); +#endif + + verify_downloaded_file_hash(fs, url, download_path_part, sha512); + fs.rename(download_path_part, download_path, ec); + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Failed to do post-download rename-in-place.\n" + "fs.rename(%s, %s, %s)", + download_path_part, + download_path.u8string(), + ec.message()); + } + +} diff --git a/toolsrc/src/vcpkg/commands.fetch.cpp b/toolsrc/src/vcpkg/commands.fetch.cpp index 03f7a8a45..0656989c5 100644 --- a/toolsrc/src/vcpkg/commands.fetch.cpp +++ b/toolsrc/src/vcpkg/commands.fetch.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include <vcpkg/base/checks.h> +#include <vcpkg/base/downloads.h> #include <vcpkg/base/sortedvector.h> #include <vcpkg/base/strings.h> #include <vcpkg/base/system.h> @@ -335,139 +336,6 @@ namespace vcpkg::Commands::Fetch ec.message()); } - static void verify_hash(const Files::Filesystem& fs, - const std::string& url, - const fs::path& path, - const std::string& sha512) - { - const std::string actual_hash = Hash::get_file_hash(fs, path, "SHA512"); - Checks::check_exit(VCPKG_LINE_INFO, - sha512 == actual_hash, - "File does not have the expected hash:\n" - " url : [ %s ]\n" - " File path : [ %s ]\n" - " Expected hash : [ %s ]\n" - " Actual hash : [ %s ]\n", - url, - path.u8string(), - sha512, - actual_hash); - } - -#if defined(_WIN32) - static void winhttp_download_file(Files::Filesystem& fs, - CStringView target_file_path, - CStringView hostname, - CStringView url_path) - { - // Make sure the directories are present, otherwise fopen_s fails - const auto dir = fs::path(target_file_path.c_str()).parent_path(); - std::error_code ec; - fs.create_directories(dir, ec); - Checks::check_exit(VCPKG_LINE_INFO, !ec, "Could not create directories %s", dir.u8string()); - - FILE* f = nullptr; - const errno_t err = fopen_s(&f, target_file_path.c_str(), "wb"); - Checks::check_exit(VCPKG_LINE_INFO, - !err, - "Could not download https://%s%s. Failed to open file %s. Error code was %s", - hostname, - url_path, - target_file_path, - std::to_string(err)); - - auto hSession = WinHttpOpen( - L"vcpkg/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); - Checks::check_exit(VCPKG_LINE_INFO, hSession, "WinHttpOpen() failed: %d", GetLastError()); - - // Use Windows 10 defaults on Windows 7 - DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | - WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2); - WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &secure_protocols, sizeof(secure_protocols)); - - // Specify an HTTP server. - auto hConnect = WinHttpConnect(hSession, Strings::to_utf16(hostname).c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0); - Checks::check_exit(VCPKG_LINE_INFO, hConnect, "WinHttpConnect() failed: %d", GetLastError()); - - // Create an HTTP request handle. - auto hRequest = WinHttpOpenRequest(hConnect, - L"GET", - Strings::to_utf16(url_path).c_str(), - nullptr, - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - WINHTTP_FLAG_SECURE); - Checks::check_exit(VCPKG_LINE_INFO, hRequest, "WinHttpOpenRequest() failed: %d", GetLastError()); - - // Send a request. - auto bResults = - WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); - Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpSendRequest() failed: %d", GetLastError()); - - // End the request. - bResults = WinHttpReceiveResponse(hRequest, NULL); - Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReceiveResponse() failed: %d", GetLastError()); - - std::vector<char> buf; - - size_t total_downloaded_size = 0; - DWORD dwSize = 0; - do - { - DWORD downloaded_size = 0; - bResults = WinHttpQueryDataAvailable(hRequest, &dwSize); - Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpQueryDataAvailable() failed: %d", GetLastError()); - - if (buf.size() < dwSize) buf.resize(dwSize * 2); - - bResults = WinHttpReadData(hRequest, (LPVOID)buf.data(), dwSize, &downloaded_size); - Checks::check_exit(VCPKG_LINE_INFO, bResults, "WinHttpReadData() failed: %d", GetLastError()); - fwrite(buf.data(), 1, downloaded_size, f); - - total_downloaded_size += downloaded_size; - } while (dwSize > 0); - - WinHttpCloseHandle(hSession); - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hRequest); - fflush(f); - fclose(f); - } -#endif - - static void download_file(Files::Filesystem& fs, - const std::string& url, - const fs::path& download_path, - const std::string& sha512) - { - const std::string download_path_part = download_path.u8string() + ".part"; - std::error_code ec; - fs.remove(download_path, ec); - fs.remove(download_path_part, ec); -#if defined(_WIN32) - auto url_no_proto = url.substr(8); // drop https:// - auto path_begin = Util::find(url_no_proto, '/'); - std::string hostname(url_no_proto.begin(), path_begin); - std::string path(path_begin, url_no_proto.end()); - - winhttp_download_file(fs, download_path_part.c_str(), hostname, path); -#else - const auto code = System::cmd_execute( - Strings::format(R"(curl -L '%s' --create-dirs --output '%s')", url, download_path_part)); - Checks::check_exit(VCPKG_LINE_INFO, code == 0, "Could not download %s", url); -#endif - - verify_hash(fs, url, download_path_part, sha512); - fs.rename(download_path_part, download_path, ec); - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Failed to do post-download rename-in-place.\n" - "fs.rename(%s, %s, %s)", - download_path_part, - download_path.u8string(), - ec.message()); - } - static fs::path fetch_tool(const VcpkgPaths& paths, const std::string& tool_name, const ToolData& tool_data) { const std::array<int, 3>& version = tool_data.version; @@ -488,12 +356,12 @@ namespace vcpkg::Commands::Fetch if (!fs.exists(tool_data.download_path)) { System::println("Downloading %s...", tool_name); - download_file(fs, tool_data.url, tool_data.download_path, tool_data.sha512); + Downloads::download_file(fs, tool_data.url, tool_data.download_path, tool_data.sha512); System::println("Downloading %s... done.", tool_name); } else { - verify_hash(fs, tool_data.url, tool_data.download_path, tool_data.sha512); + Downloads::verify_downloaded_file_hash(fs, tool_data.url, tool_data.download_path, tool_data.sha512); } if (tool_data.is_archive) diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj b/toolsrc/vcpkglib/vcpkglib.vcxproj index 871d0c58d..720a1043f 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj @@ -141,6 +141,7 @@ <ClInclude Include="..\include\vcpkg\base\chrono.h" />
<ClInclude Include="..\include\vcpkg\base\cofffilereader.h" />
<ClInclude Include="..\include\vcpkg\base\cstringview.h" />
+ <ClInclude Include="..\include\vcpkg\base\downloads.h" />
<ClInclude Include="..\include\vcpkg\base\enums.h" />
<ClInclude Include="..\include\vcpkg\base\expected.h" />
<ClInclude Include="..\include\vcpkg\base\files.h" />
@@ -195,6 +196,7 @@ <ClCompile Include="..\src\vcpkg\base\checks.cpp" />
<ClCompile Include="..\src\vcpkg\base\chrono.cpp" />
<ClCompile Include="..\src\vcpkg\base\cofffilereader.cpp" />
+ <ClCompile Include="..\src\vcpkg\base\downloads.cpp" />
<ClCompile Include="..\src\vcpkg\base\enums.cpp" />
<ClCompile Include="..\src\vcpkg\base\files.cpp" />
<ClCompile Include="..\src\vcpkg\base\lineinfo.cpp" />
diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters index 6a23a09b5..299017929 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters @@ -201,6 +201,9 @@ <ClCompile Include="..\src\vcpkg\commands.fetch.cpp">
<Filter>Source Files\vcpkg</Filter>
</ClCompile>
+ <ClCompile Include="..\src\vcpkg\base\downloads.cpp">
+ <Filter>Source Files\vcpkg\base</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\pch.h">
@@ -347,5 +350,8 @@ <ClInclude Include="..\include\vcpkg\base\stringliteral.h">
<Filter>Header Files\vcpkg\base</Filter>
</ClInclude>
+ <ClInclude Include="..\include\vcpkg\base\downloads.h">
+ <Filter>Header Files\vcpkg\base</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file |
