Move Windows Symbol Converter to breakpad

- First step, this is just enough to get it generating a msbuild
  project with GYP, which in turn can build the executable.
- Tests need to be redesigned because there isn't an available server.

Change-Id: I45440fd32b3ede29666c127703bcd441f0e4288e
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1661134
Reviewed-by: Ivan Penkov <ivanpe@chromium.org>
This commit is contained in:
Nelson Billing 2019-06-14 15:51:23 -07:00
parent a7d686086c
commit 92032389a6
21 changed files with 3056 additions and 0 deletions

View file

@ -0,0 +1,33 @@
@if "%ECHOON%"=="" @echo off
SETLOCAL
REM ******************************************************************
REM Please, make sure to run this in an Elevated Command Prompt.
REM Usage:
REM configure.cmd
REM ******************************************************************
REM ******************************************************************
REM Initialize
REM ******************************************************************
SET SCRIPT_LOCATION=%~dp0
REM ******************************************************************
REM Go to script location
REM ******************************************************************
pushd %SCRIPT_LOCATION%
REM ******************************************************************
REM Register msdia120.dll.
REM ******************************************************************
SET MSG=Failed to register msdia120.dll. Make sure to run this in elevated command prompt.
%systemroot%\SysWoW64\regsvr32.exe /s msdia120.dll & if errorlevel 1 echo %MSG% & goto :fail
:success
echo Configuration was successful.
ENDLOCAL
exit /b 0
:fail
ENDLOCAL
exit /b 1

View file

@ -0,0 +1,2 @@
msctf.pdb|6A5BABB8E88644C696530BFE3C90F32F2|6.1.7600.16385|msctf.dll|4A5BDFAA109000
imm32.pdb|98F27BA5AEE541ECBEE00CD03AD50FEE2|6.1.7600.16385|imm32.dll|4A5BDF402e000

Binary file not shown.

View file

@ -0,0 +1,2 @@
See breakpad/tools/windows/converter/ms_symbol_server_converter.h for a
description of this file's function.

View file

@ -0,0 +1,33 @@
@if "%ECHOON%"=="" @echo off
SETLOCAL
REM ******************************************************************
REM Please, make sure to run this in an Elevated Command Prompt.
REM Usage:
REM configure.cmd
REM ******************************************************************
REM ******************************************************************
REM Initialize
REM ******************************************************************
SET SCRIPT_LOCATION=%~dp0
REM ******************************************************************
REM Go to script location
REM ******************************************************************
pushd %SCRIPT_LOCATION%
REM ******************************************************************
REM Register msdia120.dll.
REM ******************************************************************
SET MSG=Failed to register msdia120.dll. Make sure to run this in elevated command prompt.
%systemroot%\SysWoW64\regsvr32.exe /s msdia120.dll & if errorlevel 1 echo %MSG% & goto :fail
:success
echo Configuration was successful.
ENDLOCAL
exit /b 0
:fail
ENDLOCAL
exit /b 1

View file

@ -0,0 +1,807 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma comment(lib, "winhttp.lib")
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "diaguids.lib")
#pragma comment(lib, "imagehlp.lib")
#include <cassert>
#include <cstdio>
#include <ctime>
#include <map>
#include <regex>
#include <string>
#include <vector>
#include "tools/windows/converter_exe/escaping.h"
#include "tools/windows/converter_exe/http_download.h"
#include "tools/windows/converter_exe/tokenizer.h"
#include "common/windows/http_upload.h"
#include "common/windows/string_utils-inl.h"
#include "tools/windows/converter/ms_symbol_server_converter.h"
using strings::WebSafeBase64Unescape;
using strings::WebSafeBase64Escape;
namespace {
using std::map;
using std::string;
using std::vector;
using std::wstring;
using crash::HTTPDownload;
using crash::Tokenizer;
using google_breakpad::HTTPUpload;
using google_breakpad::MissingSymbolInfo;
using google_breakpad::MSSymbolServerConverter;
using google_breakpad::WindowsStringUtils;
const char *kMissingStringDelimiters = "|";
const char *kLocalCachePath = "c:\\symbols";
const char *kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/";
const int kMatchArrSize = 64;
// Windows stdio doesn't do line buffering. Use this function to flush after
// writing to stdout and stderr so that a log will be available if the
// converter crashes.
static int FprintfFlush(FILE *file, const char *format, ...) {
va_list arguments;
va_start(arguments, format);
int retval = vfprintf(file, format, arguments);
va_end(arguments);
fflush(file);
return retval;
}
static string CurrentDateAndTime() {
const string kUnknownDateAndTime = "????-??-?? ??:??:??";
time_t current_time;
time(&current_time);
// localtime_s is safer but is only available in MSVC8. Use localtime
// in earlier environments.
struct tm *time_pointer;
#if _MSC_VER >= 1400 // MSVC 2005/8
struct tm time_struct;
time_pointer = &time_struct;
if (localtime_s(time_pointer, &current_time) != 0) {
return kUnknownDateAndTime;
}
#else // _MSC_VER >= 1400
time_pointer = localtime(&current_time);
if (!time_pointer) {
return kUnknownDateAndTime;
}
#endif // _MSC_VER >= 1400
char buffer[256];
if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) {
return kUnknownDateAndTime;
}
return string(buffer);
}
// ParseMissingString turns |missing_string| into a MissingSymbolInfo
// structure. It returns true on success, and false if no such conversion
// is possible.
static bool ParseMissingString(const string &missing_string,
MissingSymbolInfo *missing_info) {
assert(missing_info);
vector<string> tokens;
Tokenizer::Tokenize(kMissingStringDelimiters, missing_string, &tokens);
if (tokens.size() != 5) {
return false;
}
missing_info->debug_file = tokens[0];
missing_info->debug_identifier = tokens[1];
missing_info->version = tokens[2];
missing_info->code_file = tokens[3];
missing_info->code_identifier = tokens[4];
return true;
}
// StringMapToWStringMap takes each element in a map that associates
// (narrow) strings to strings and converts the keys and values to wstrings.
// Returns true on success and false on failure, printing an error message.
static bool StringMapToWStringMap(const map<string, string> &smap,
map<wstring, wstring> *wsmap) {
assert(wsmap);
wsmap->clear();
for (map<string, string>::const_iterator iterator = smap.begin();
iterator != smap.end();
++iterator) {
wstring key;
if (!WindowsStringUtils::safe_mbstowcs(iterator->first, &key)) {
FprintfFlush(stderr,
"StringMapToWStringMap: safe_mbstowcs failed for key %s\n",
iterator->first.c_str());
return false;
}
wstring value;
if (!WindowsStringUtils::safe_mbstowcs(iterator->second, &value)) {
FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed "
"for value %s\n",
iterator->second.c_str());
return false;
}
wsmap->insert(make_pair(key, value));
}
return true;
}
// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a
// map of parameters suitable for passing to HTTPDownload or HTTPUpload.
// Returns true on success and false on failure, printing an error message.
static bool MissingSymbolInfoToParameters(const MissingSymbolInfo &missing_info,
map<wstring, wstring> *wparameters) {
assert(wparameters);
map<string, string> parameters;
string encoded_param;
// Indicate the params are encoded.
parameters["encoded"] = "true"; // The string value here does not matter.
WebSafeBase64Escape(missing_info.code_file, &encoded_param);
parameters["code_file"] = encoded_param;
WebSafeBase64Escape(missing_info.code_identifier, &encoded_param);
parameters["code_identifier"] = encoded_param;
WebSafeBase64Escape(missing_info.debug_file, &encoded_param);
parameters["debug_file"] = encoded_param;
WebSafeBase64Escape(missing_info.debug_identifier, &encoded_param);
parameters["debug_identifier"] = encoded_param;
if (!missing_info.version.empty()) {
// The version is optional.
WebSafeBase64Escape(missing_info.version, &encoded_param);
parameters["version"] = encoded_param;
}
WebSafeBase64Escape("WinSymConv", &encoded_param);
parameters["product"] = encoded_param;
if (!StringMapToWStringMap(parameters, wparameters)) {
// StringMapToWStringMap will have printed an error.
return false;
}
return true;
}
// UploadSymbolFile sends |converted_file| as identified by |missing_info|
// to the symbol server rooted at |upload_symbol_url|. Returns true on
// success and false on failure, printing an error message.
static bool UploadSymbolFile(const wstring &upload_symbol_url,
const MissingSymbolInfo &missing_info,
const string &converted_file) {
map<wstring, wstring> parameters;
if (!MissingSymbolInfoToParameters(missing_info, &parameters)) {
// MissingSymbolInfoToParameters or a callee will have printed an error.
return false;
}
wstring converted_file_w;
if (!WindowsStringUtils::safe_mbstowcs(converted_file, &converted_file_w)) {
FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
converted_file.c_str());
return false;
}
map<wstring, wstring> files;
files[L"symbol_file"] = converted_file_w;
FprintfFlush(stderr, "Uploading %s\n", converted_file.c_str());
if (!HTTPUpload::SendRequest(
upload_symbol_url, parameters,
files, NULL, NULL, NULL)) {
FprintfFlush(stderr, "UploadSymbolFile: HTTPUpload::SendRequest failed "
"for %s %s %s\n",
missing_info.debug_file.c_str(),
missing_info.debug_identifier.c_str(),
missing_info.version.c_str());
return false;
}
return true;
}
// SendFetchFailedPing informs the symbol server based at
// |fetch_symbol_failure_url| that the symbol file identified by
// |missing_info| could authoritatively not be located. Returns
// true on success and false on failure.
static bool SendFetchFailedPing(const wstring &fetch_symbol_failure_url,
const MissingSymbolInfo &missing_info) {
map<wstring, wstring> parameters;
if (!MissingSymbolInfoToParameters(missing_info, &parameters)) {
// MissingSymbolInfoToParameters or a callee will have printed an error.
return false;
}
string content;
if (!HTTPDownload::Download(fetch_symbol_failure_url,
&parameters,
&content,
NULL)) {
FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed "
"for %s %s %s\n",
missing_info.debug_file.c_str(),
missing_info.debug_identifier.c_str(),
missing_info.version.c_str());
return false;
}
return true;
}
// Returns true if it's safe to make an external request for the symbol
// file described in missing_info. It's considered safe to make an
// external request unless the symbol file's debug_file string matches
// the given blacklist regular expression.
// The debug_file name is used from the MissingSymbolInfo struct,
// matched against the PCRE blacklist_regex.
static bool SafeToMakeExternalRequest(const MissingSymbolInfo &missing_info,
std::regex blacklist_regex) {
string file_name = missing_info.debug_file;
if (std::regex_match(file_name, blacklist_regex)) {
FprintfFlush(stderr, "Not safe to make external request for file %s\n",
file_name.c_str());
return false;
}
return true;
}
// Converter options derived from command line parameters.
struct ConverterOptions {
ConverterOptions()
: report_fetch_failures(true),
blacklist_regex(nullptr) {
}
~ConverterOptions() {
}
// Names of MS Symbol Supplier Servers that are internal to Google, and may
// have symbols for any request.
vector<string> full_internal_msss_servers;
// Names of MS Symbol Supplier Servers that are internal to Google, and
// shouldn't be checked for symbols for any .exe files.
vector<string> full_external_msss_servers;
// Names of MS Symbol Supplier Servers that are external to Google, and may
// have symbols for any request.
vector<string> no_exe_internal_msss_servers;
// Names of MS Symbol Supplier Servers that are external to Google, and
// shouldn't be checked for symbols for any .exe files.
vector<string> no_exe_external_msss_servers;
// Temporary local storage for symbols.
string local_cache_path;
// URL for uploading symbols.
wstring upload_symbols_url;
// URL to fetch list of missing symbols.
wstring missing_symbols_url;
// URL to report symbol fetch failure.
wstring fetch_symbol_failure_url;
// Are symbol fetch failures reported.
bool report_fetch_failures;
// File containing the list of missing symbols. Fetch failures are not
// reported if such file is provided.
string missing_symbols_file;
// Regex used to blacklist files to prevent external symbol requests.
// Owned and cleaned up by this struct.
std::regex blacklist_regex;
private:
// DISABLE_COPY_AND_ASSIGN
ConverterOptions(const ConverterOptions&);
ConverterOptions& operator=(const ConverterOptions&);
};
// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and
// attempts to locate it from the symbol servers provided in the
// |options.*_msss_servers| arguments. "Full" servers are those that will be
// queried for all symbol files; "No-EXE" servers will only be queried for
// modules whose missing symbol data indicates are not main program executables.
// Results will be sent to the |options.upload_symbols_url| on success or
// |options.fetch_symbol_failure_url| on failure, and the local cache will be
// stored at |options.local_cache_path|. Because nothing can be done even in
// the event of a failure, this function returns no value, although it
// may result in error messages being printed.
static void ConvertMissingSymbolFile(const MissingSymbolInfo &missing_info,
const ConverterOptions &options) {
string time_string = CurrentDateAndTime();
FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n",
time_string.c_str(),
missing_info.debug_file.c_str(),
missing_info.debug_identifier.c_str(),
missing_info.version.c_str());
// The first lookup is always to internal symbol servers.
// Always ask the symbol servers identified as "full."
vector<string> msss_servers = options.full_internal_msss_servers;
// If the file is not an .exe file, also ask an additional set of symbol
// servers, such as Microsoft's public symbol server.
bool is_exe = false;
if (missing_info.code_file.length() >= 4) {
string code_extension =
missing_info.code_file.substr(missing_info.code_file.size() - 4);
// Firefox is a special case: .dll-only servers should be consulted for
// its symbols. This enables us to get its symbols from Mozilla's
// symbol server when crashes occur in Google extension code hosted by a
// Firefox process.
if (_stricmp(code_extension.c_str(), ".exe") == 0 &&
_stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) {
is_exe = true;
}
}
if (!is_exe) {
msss_servers.insert(msss_servers.end(),
options.no_exe_internal_msss_servers.begin(),
options.no_exe_internal_msss_servers.end());
}
// If there are any suitable internal symbol servers, make a request.
MSSymbolServerConverter::LocateResult located =
MSSymbolServerConverter::LOCATE_FAILURE;
string converted_file;
if (msss_servers.size() > 0) {
// Attempt to fetch the symbol file and convert it.
FprintfFlush(stderr, "Making internal request for %s (%s)\n",
missing_info.debug_file.c_str(),
missing_info.debug_identifier.c_str());
MSSymbolServerConverter converter(options.local_cache_path, msss_servers);
located = converter.LocateAndConvertSymbolFile(missing_info,
false, // keep_symbol_file
false, // keep_pe_file
&converted_file,
NULL, // symbol_file
NULL); // pe_file
switch (located) {
case MSSymbolServerConverter::LOCATE_SUCCESS:
FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
// Upload it. Don't bother checking the return value. If this
// succeeds, it should disappear from the missing symbol list.
// If it fails, something will print an error message indicating
// the cause of the failure, and the item will remain on the
// missing symbol list.
UploadSymbolFile(options.upload_symbols_url, missing_info,
converted_file);
remove(converted_file.c_str());
// Note: this does leave some directories behind that could be
// cleaned up. The directories inside options.local_cache_path for
// debug_file/debug_identifier can be removed at this point.
break;
case MSSymbolServerConverter::LOCATE_NOT_FOUND:
FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n");
// The symbol file definitively did not exist. Fall through,
// so we can attempt an external query if it's safe to do so.
break;
case MSSymbolServerConverter::LOCATE_RETRY:
FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
// Fall through in case we should make an external request.
// If not, or if an external request fails in the same way,
// we'll leave the entry in the symbol file list and
// try again on a future pass. Print a message so that there's
// a record.
break;
case MSSymbolServerConverter::LOCATE_FAILURE:
FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
// LocateAndConvertSymbolFile printed an error message.
break;
default:
FprintfFlush(
stderr,
"FATAL: Unexpected return value '%d' from "
"LocateAndConvertSymbolFile()\n",
located);
assert(0);
break;
}
} else {
// No suitable internal symbol servers. This is fine because the converter
// is mainly used for downloading and converting of external symbols.
}
// Make a request to an external server if the internal request didn't
// succeed, and it's safe to do so.
if (located != MSSymbolServerConverter::LOCATE_SUCCESS &&
SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) {
msss_servers = options.full_external_msss_servers;
if (!is_exe) {
msss_servers.insert(msss_servers.end(),
options.no_exe_external_msss_servers.begin(),
options.no_exe_external_msss_servers.end());
}
if (msss_servers.size() > 0) {
FprintfFlush(stderr, "Making external request for %s (%s)\n",
missing_info.debug_file.c_str(),
missing_info.debug_identifier.c_str());
MSSymbolServerConverter external_converter(options.local_cache_path,
msss_servers);
located = external_converter.LocateAndConvertSymbolFile(
missing_info,
false, // keep_symbol_file
false, // keep_pe_file
&converted_file,
NULL, // symbol_file
NULL); // pe_file
} else {
FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n");
}
}
// Final handling for this symbol file is based on the result from the
// external request (if performed above), or on the result from the
// previous internal lookup.
switch (located) {
case MSSymbolServerConverter::LOCATE_SUCCESS:
FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
// Upload it. Don't bother checking the return value. If this
// succeeds, it should disappear from the missing symbol list.
// If it fails, something will print an error message indicating
// the cause of the failure, and the item will remain on the
// missing symbol list.
UploadSymbolFile(options.upload_symbols_url, missing_info,
converted_file);
remove(converted_file.c_str());
// Note: this does leave some directories behind that could be
// cleaned up. The directories inside options.local_cache_path for
// debug_file/debug_identifier can be removed at this point.
break;
case MSSymbolServerConverter::LOCATE_NOT_FOUND:
// The symbol file definitively didn't exist. Inform the server.
// If this fails, something will print an error message indicating
// the cause of the failure, but there's really nothing more to
// do. If this succeeds, the entry should be removed from the
// missing symbols list.
if (!options.report_fetch_failures) {
FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
} else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
missing_info)) {
FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
} else {
FprintfFlush(stderr, "SendFetchFailedPing failed\n");
}
break;
case MSSymbolServerConverter::LOCATE_RETRY:
FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
// Nothing to do but leave the entry in the symbol file list and
// try again on a future pass. Print a message so that there's
// a record.
FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry "
"for %s %s %s\n",
missing_info.debug_file.c_str(),
missing_info.debug_identifier.c_str(),
missing_info.version.c_str());
break;
case MSSymbolServerConverter::LOCATE_FAILURE:
FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
// LocateAndConvertSymbolFile printed an error message.
// This is due to a bad debug file name, so fetch failed.
if (!options.report_fetch_failures) {
FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
} else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
missing_info)) {
FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
} else {
FprintfFlush(stderr, "SendFetchFailedPing failed\n");
}
break;
default:
FprintfFlush(
stderr,
"FATAL: Unexpected return value '%d' from "
"LocateAndConvertSymbolFile()\n",
located);
assert(0);
break;
}
}
// Reads the contents of file |file_name| and populates |contents|.
// Returns true on success.
static bool ReadFile(string file_name, string *contents) {
char buffer[1024 * 8];
FILE *fp = fopen(file_name.c_str(), "rt");
if (!fp) {
return false;
}
contents->clear();
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
contents->append(buffer);
}
fclose(fp);
return true;
}
// ConvertMissingSymbolsList obtains a missing symbol list from
// |options.missing_symbols_url| or |options.missing_symbols_file| and calls
// ConvertMissingSymbolFile for each missing symbol file in the list.
static bool ConvertMissingSymbolsList(const ConverterOptions &options) {
// Set param to indicate requesting for encoded response.
map<wstring, wstring> parameters;
parameters[L"product"] = L"WinSymConv";
parameters[L"encoded"] = L"true";
// Get the missing symbol list.
string missing_symbol_list;
if (!options.missing_symbols_file.empty()) {
if (!ReadFile(options.missing_symbols_file, &missing_symbol_list)) {
return false;
}
} else if (!HTTPDownload::Download(options.missing_symbols_url, &parameters,
&missing_symbol_list, NULL)) {
return false;
}
// Tokenize the content into a vector.
vector<string> missing_symbol_lines;
Tokenizer::Tokenize("\n", missing_symbol_list, &missing_symbol_lines);
FprintfFlush(stderr, "Found %d missing symbol files in list.\n",
missing_symbol_lines.size() - 1); // last line is empty.
int convert_attempts = 0;
for (vector<string>::const_iterator iterator = missing_symbol_lines.begin();
iterator != missing_symbol_lines.end();
++iterator) {
// Decode symbol line.
const string &encoded_line = *iterator;
// Skip lines that are blank.
if (encoded_line.empty()) {
continue;
}
string line;
if (!WebSafeBase64Unescape(encoded_line, &line)) {
// If decoding fails, assume the line is not encoded.
// This is helpful when the program connects to a debug server without
// encoding.
line = encoded_line;
}
FprintfFlush(stderr, "\nLine: %s\n", line.c_str());
// Turn each element into a MissingSymbolInfo structure.
MissingSymbolInfo missing_info;
if (!ParseMissingString(line, &missing_info)) {
FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed "
"for %s from %ws\n",
line.c_str(), options.missing_symbols_url.c_str());
continue;
}
++convert_attempts;
ConvertMissingSymbolFile(missing_info, options);
}
// Say something reassuring, since ConvertMissingSymbolFile was never called
// and therefore never reported any progress.
if (convert_attempts == 0) {
string current_time = CurrentDateAndTime();
FprintfFlush(stdout, "converter: %s: nothing to convert\n",
current_time.c_str());
}
return true;
}
// usage prints the usage message. It returns 1 as a convenience, to be used
// as a return value from main.
static int usage(const char *program_name) {
FprintfFlush(stderr,
"usage: %s [options]\n"
" -f <full_msss_server> MS servers to ask for all symbols\n"
" -n <no_exe_msss_server> same, but prevent asking for EXEs\n"
" -l <local_cache_path> Temporary local storage for symbols\n"
" -s <upload_url> URL for uploading symbols\n"
" -m <missing_symbols_url> URL to fetch list of missing symbols\n"
" -mf <missing_symbols_file> File containing the list of missing\n"
" symbols. Fetch failures are not\n"
" reported if such file is provided.\n"
" -t <fetch_failure_url> URL to report symbol fetch failure\n"
" -b <regex> Regex used to blacklist files to\n"
" prevent external symbol requests\n"
" Note that any server specified by -f or -n that starts with \\filer\n"
" will be treated as internal, and all others as external.\n",
program_name);
return 1;
}
// "Internal" servers consist only of those whose names start with
// the literal string "\\filer\".
static bool IsInternalServer(const string &server_name) {
if (server_name.find("\\\\filer\\") == 0) {
return true;
}
return false;
}
// Adds a server with the given name to the list of internal or external
// servers, as appropriate.
static void AddServer(const string &server_name,
vector<string> *internal_servers,
vector<string> *external_servers) {
if (IsInternalServer(server_name)) {
internal_servers->push_back(server_name);
} else {
external_servers->push_back(server_name);
}
}
} // namespace
int main(int argc, char **argv) {
string time_string = CurrentDateAndTime();
FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str());
ConverterOptions options;
options.report_fetch_failures = true;
// All arguments are paired.
if (argc % 2 != 1) {
return usage(argv[0]);
}
string blacklist_regex_str;
bool have_any_msss_servers = false;
for (int argi = 1; argi < argc; argi += 2) {
string option = argv[argi];
string value = argv[argi + 1];
if (option == "-f") {
AddServer(value, &options.full_internal_msss_servers,
&options.full_external_msss_servers);
have_any_msss_servers = true;
} else if (option == "-n") {
AddServer(value, &options.no_exe_internal_msss_servers,
&options.no_exe_external_msss_servers);
have_any_msss_servers = true;
} else if (option == "-l") {
if (!options.local_cache_path.empty()) {
return usage(argv[0]);
}
options.local_cache_path = value;
} else if (option == "-s") {
if (!WindowsStringUtils::safe_mbstowcs(value,
&options.upload_symbols_url)) {
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
value.c_str());
return 1;
}
} else if (option == "-m") {
if (!WindowsStringUtils::safe_mbstowcs(value,
&options.missing_symbols_url)) {
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
value.c_str());
return 1;
}
} else if (option == "-mf") {
options.missing_symbols_file = value;
printf("Getting the list of missing symbols from a file. Fetch failures"
" will not be reported.\n");
options.report_fetch_failures = false;
} else if (option == "-t") {
if (!WindowsStringUtils::safe_mbstowcs(
value,
&options.fetch_symbol_failure_url)) {
FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
value.c_str());
return 1;
}
} else if (option == "-b") {
blacklist_regex_str = value;
} else {
return usage(argv[0]);
}
}
if (blacklist_regex_str.empty()) {
FprintfFlush(stderr, "No blacklist specified.\n");
return usage(argv[0]);
}
// Compile the blacklist regular expression for later use.
options.blacklist_regex = std::regex(blacklist_regex_str.c_str(),
std::regex_constants::icase);
// Set the defaults. If the user specified any MSSS servers, don't use
// any default.
if (!have_any_msss_servers) {
AddServer(kNoExeMSSSServer, &options.no_exe_internal_msss_servers,
&options.no_exe_external_msss_servers);
}
if (options.local_cache_path.empty()) {
options.local_cache_path = kLocalCachePath;
}
if (options.upload_symbols_url.empty()) {
FprintfFlush(stderr, "No upload symbols URL specified.\n");
return usage(argv[0]);
}
if (options.missing_symbols_url.empty()) {
FprintfFlush(stderr, "No missing symbols URL specified.\n");
return usage(argv[0]);
}
if (options.fetch_symbol_failure_url.empty()) {
FprintfFlush(stderr, "No fetch symbol failure URL specified.\n");
return usage(argv[0]);
}
FprintfFlush(stdout,
"# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n",
options.full_internal_msss_servers.size(),
options.full_external_msss_servers.size(),
options.no_exe_internal_msss_servers.size(),
options.no_exe_external_msss_servers.size());
if (!ConvertMissingSymbolsList(options)) {
return 1;
}
time_string = CurrentDateAndTime();
FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str());
return 0;
}

View file

@ -0,0 +1,57 @@
# Copyright 2013 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'includes': [
'../../../build/common.gypi',
],
'targets': [
{
'target_name': 'converter_exe',
'type': 'executable',
'sources': [
'converter.cc',
'escaping.cc',
'escaping.h',
'http_client.h',
'http_download.cc',
'http_download.h',
'tokenizer.cc',
'tokenizer.h',
'winhttp_client.cc',
'winhttp_client.h',
'wininet_client.cc',
'wininet_client.h',
],
'dependencies': [
'../../../common/windows/common_windows.gyp:common_windows_lib',
'../converter/ms_symbol_server_converter.gyp:ms_symbol_server_converter',
],
},
],
}

View file

@ -0,0 +1,757 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "tools/windows/converter_exe/escaping.h"
#include <assert.h>
#define kApb kAsciiPropertyBits
const unsigned char kAsciiPropertyBits[256] = {
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
};
// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'.
static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); }
///////////////////////////////////
// scoped_array
///////////////////////////////////
// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
// with new [] and the destructor deletes objects with delete [].
//
// As with scoped_ptr<C>, a scoped_array<C> either points to an object
// or is NULL. A scoped_array<C> owns the object that it points to.
// scoped_array<T> is thread-compatible, and once you index into it,
// the returned objects have only the threadsafety guarantees of T.
//
// Size: sizeof(scoped_array<C>) == sizeof(C*)
template <class C>
class scoped_array {
public:
// The element type
typedef C element_type;
// Constructor. Defaults to intializing with NULL.
// There is no way to create an uninitialized scoped_array.
// The input parameter must be allocated with new [].
explicit scoped_array(C* p = NULL) : array_(p) { }
// Destructor. If there is a C object, delete it.
// We don't need to test ptr_ == NULL because C++ does that for us.
~scoped_array() {
enum { type_must_be_complete = sizeof(C) };
delete[] array_;
}
// Reset. Deletes the current owned object, if any.
// Then takes ownership of a new object, if given.
// this->reset(this->get()) works.
void reset(C* p = NULL) {
if (p != array_) {
enum { type_must_be_complete = sizeof(C) };
delete[] array_;
array_ = p;
}
}
// Get one element of the current object.
// Will assert() if there is no current object, or index i is negative.
C& operator[](std::ptrdiff_t i) const {
assert(i >= 0);
assert(array_ != NULL);
return array_[i];
}
// Get a pointer to the zeroth element of the current object.
// If there is no current object, return NULL.
C* get() const {
return array_;
}
// Comparison operators.
// These return whether a scoped_array and a raw pointer refer to
// the same array, not just to two different but equal arrays.
bool operator==(const C* p) const { return array_ == p; }
bool operator!=(const C* p) const { return array_ != p; }
// Swap two scoped arrays.
void swap(scoped_array& p2) {
C* tmp = array_;
array_ = p2.array_;
p2.array_ = tmp;
}
// Release an array.
// The return value is the current pointer held by this object.
// If this object holds a NULL pointer, the return value is NULL.
// After this operation, this object will hold a NULL pointer,
// and will not own the object any more.
C* release() {
C* retVal = array_;
array_ = NULL;
return retVal;
}
private:
C* array_;
// Forbid comparison of different scoped_array types.
template <class C2> bool operator==(scoped_array<C2> const& p2) const;
template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
// Disallow evil constructors
scoped_array(const scoped_array&);
void operator=(const scoped_array&);
};
///////////////////////////////////
// Escape methods
///////////////////////////////////
namespace strings {
// Return a mutable char* pointing to a string's internal buffer,
// which may not be null-terminated. Writing through this pointer will
// modify the string.
//
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
// next call to a string method that invalidates iterators.
//
// As of 2006-04, there is no standard-blessed way of getting a
// mutable reference to a string's internal buffer. However, issue 530
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
// proposes this as the method. According to Matt Austern, this should
// already work on all current implementations.
inline char* string_as_array(string* str) {
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
return str->empty() ? NULL : &*str->begin();
}
int CalculateBase64EscapedLen(int input_len, bool do_padding) {
// these formulae were copied from comments that used to go with the base64
// encoding functions
int intermediate_result = 8 * input_len + 5;
assert(intermediate_result > 0); // make sure we didn't overflow
int len = intermediate_result / 6;
if (do_padding) len = ((len + 3) / 4) * 4;
return len;
}
// Base64Escape does padding, so this calculation includes padding.
int CalculateBase64EscapedLen(int input_len) {
return CalculateBase64EscapedLen(input_len, true);
}
// ----------------------------------------------------------------------
// int Base64Unescape() - base64 decoder
// int Base64Escape() - base64 encoder
// int WebSafeBase64Unescape() - Google's variation of base64 decoder
// int WebSafeBase64Escape() - Google's variation of base64 encoder
//
// Check out
// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
// description, but what we care about is that...
// Take the encoded stuff in groups of 4 characters and turn each
// character into a code 0 to 63 thus:
// A-Z map to 0 to 25
// a-z map to 26 to 51
// 0-9 map to 52 to 61
// +(- for WebSafe) maps to 62
// /(_ for WebSafe) maps to 63
// There will be four numbers, all less than 64 which can be represented
// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
// Arrange the 6 digit binary numbers into three bytes as such:
// aaaaaabb bbbbcccc ccdddddd
// Equals signs (one or two) are used at the end of the encoded block to
// indicate that the text was not an integer multiple of three bytes long.
// ----------------------------------------------------------------------
int Base64UnescapeInternal(const char *src, int szsrc,
char *dest, int szdest,
const signed char* unbase64) {
static const char kPad64 = '=';
int decode = 0;
int destidx = 0;
int state = 0;
unsigned int ch = 0;
unsigned int temp = 0;
// The GET_INPUT macro gets the next input character, skipping
// over any whitespace, and stopping when we reach the end of the
// string or when we read any non-data character. The arguments are
// an arbitrary identifier (used as a label for goto) and the number
// of data bytes that must remain in the input to avoid aborting the
// loop.
#define GET_INPUT(label, remain) \
label: \
--szsrc; \
ch = *src++; \
decode = unbase64[ch]; \
if (decode < 0) { \
if (ascii_isspace((char)ch) && szsrc >= remain) \
goto label; \
state = 4 - remain; \
break; \
}
// if dest is null, we're just checking to see if it's legal input
// rather than producing output. (I suspect this could just be done
// with a regexp...). We duplicate the loop so this test can be
// outside it instead of in every iteration.
if (dest) {
// This loop consumes 4 input bytes and produces 3 output bytes
// per iteration. We can't know at the start that there is enough
// data left in the string for a full iteration, so the loop may
// break out in the middle; if so 'state' will be set to the
// number of input bytes read.
while (szsrc >= 4) {
// We'll start by optimistically assuming that the next four
// bytes of the string (src[0..3]) are four good data bytes
// (that is, no nulls, whitespace, padding chars, or illegal
// chars). We need to test src[0..2] for nulls individually
// before constructing temp to preserve the property that we
// never read past a null in the string (no matter how long
// szsrc claims the string is).
if (!src[0] || !src[1] || !src[2] ||
(temp = ((unbase64[src[0]] << 18) |
(unbase64[src[1]] << 12) |
(unbase64[src[2]] << 6) |
(unbase64[src[3]]))) & 0x80000000) {
// Iff any of those four characters was bad (null, illegal,
// whitespace, padding), then temp's high bit will be set
// (because unbase64[] is -1 for all bad characters).
//
// We'll back up and resort to the slower decoder, which knows
// how to handle those cases.
GET_INPUT(first, 4);
temp = decode;
GET_INPUT(second, 3);
temp = (temp << 6) | decode;
GET_INPUT(third, 2);
temp = (temp << 6) | decode;
GET_INPUT(fourth, 1);
temp = (temp << 6) | decode;
} else {
// We really did have four good data bytes, so advance four
// characters in the string.
szsrc -= 4;
src += 4;
decode = -1;
ch = '\0';
}
// temp has 24 bits of input, so write that out as three bytes.
if (destidx+3 > szdest) return -1;
dest[destidx+2] = (char)temp;
temp >>= 8;
dest[destidx+1] = (char)temp;
temp >>= 8;
dest[destidx] = (char)temp;
destidx += 3;
}
} else {
while (szsrc >= 4) {
if (!src[0] || !src[1] || !src[2] ||
(temp = ((unbase64[src[0]] << 18) |
(unbase64[src[1]] << 12) |
(unbase64[src[2]] << 6) |
(unbase64[src[3]]))) & 0x80000000) {
GET_INPUT(first_no_dest, 4);
GET_INPUT(second_no_dest, 3);
GET_INPUT(third_no_dest, 2);
GET_INPUT(fourth_no_dest, 1);
} else {
szsrc -= 4;
src += 4;
decode = -1;
ch = '\0';
}
destidx += 3;
}
}
#undef GET_INPUT
// if the loop terminated because we read a bad character, return
// now.
if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch))
return -1;
if (ch == kPad64) {
// if we stopped by hitting an '=', un-read that character -- we'll
// look at it again when we count to check for the proper number of
// equals signs at the end.
++szsrc;
--src;
} else {
// This loop consumes 1 input byte per iteration. It's used to
// clean up the 0-3 input bytes remaining when the first, faster
// loop finishes. 'temp' contains the data from 'state' input
// characters read by the first loop.
while (szsrc > 0) {
--szsrc;
ch = *src++;
decode = unbase64[ch];
if (decode < 0) {
if (ascii_isspace((char)ch)) {
continue;
} else if (ch == '\0') {
break;
} else if (ch == kPad64) {
// back up one character; we'll read it again when we check
// for the correct number of equals signs at the end.
++szsrc;
--src;
break;
} else {
return -1;
}
}
// Each input character gives us six bits of output.
temp = (temp << 6) | decode;
++state;
if (state == 4) {
// If we've accumulated 24 bits of output, write that out as
// three bytes.
if (dest) {
if (destidx+3 > szdest) return -1;
dest[destidx+2] = (char)temp;
temp >>= 8;
dest[destidx+1] = (char)temp;
temp >>= 8;
dest[destidx] = (char)temp;
}
destidx += 3;
state = 0;
temp = 0;
}
}
}
// Process the leftover data contained in 'temp' at the end of the input.
int expected_equals = 0;
switch (state) {
case 0:
// Nothing left over; output is a multiple of 3 bytes.
break;
case 1:
// Bad input; we have 6 bits left over.
return -1;
case 2:
// Produce one more output byte from the 12 input bits we have left.
if (dest) {
if (destidx+1 > szdest) return -1;
temp >>= 4;
dest[destidx] = (char)temp;
}
++destidx;
expected_equals = 2;
break;
case 3:
// Produce two more output bytes from the 18 input bits we have left.
if (dest) {
if (destidx+2 > szdest) return -1;
temp >>= 2;
dest[destidx+1] = (char)temp;
temp >>= 8;
dest[destidx] = (char)temp;
}
destidx += 2;
expected_equals = 1;
break;
default:
// state should have no other values at this point.
fprintf(stdout, "This can't happen; base64 decoder state = %d", state);
}
// The remainder of the string should be all whitespace, mixed with
// exactly 0 equals signs, or exactly 'expected_equals' equals
// signs. (Always accepting 0 equals signs is a google extension
// not covered in the RFC.)
int equals = 0;
while (szsrc > 0 && *src) {
if (*src == kPad64)
++equals;
else if (!ascii_isspace(*src))
return -1;
--szsrc;
++src;
}
return (equals == 0 || equals == expected_equals) ? destidx : -1;
}
int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) {
static const signed char UnBase64[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
-1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
-1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1
};
// The above array was generated by the following code
// #include <sys/time.h>
// #include <stdlib.h>
// #include <string.h>
// main()
// {
// static const char Base64[] =
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// char *pos;
// int idx, i, j;
// printf(" ");
// for (i = 0; i < 255; i += 8) {
// for (j = i; j < i + 8; j++) {
// pos = strchr(Base64, j);
// if ((pos == NULL) || (j == 0))
// idx = -1;
// else
// idx = pos - Base64;
// if (idx == -1)
// printf(" %2d, ", idx);
// else
// printf(" %2d/*%c*/,", idx, j);
// }
// printf("\n ");
// }
// }
return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
}
bool Base64Unescape(const char *src, int slen, string* dest) {
// Determine the size of the output string. Base64 encodes every 3 bytes into
// 4 characters. any leftover chars are added directly for good measure.
// This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt
const int dest_len = 3 * (slen / 4) + (slen % 4);
dest->resize(dest_len);
// We are getting the destination buffer by getting the beginning of the
// string and converting it into a char *.
const int len = Base64Unescape(src, slen,
string_as_array(dest), dest->size());
if (len < 0) {
return false;
}
// could be shorter if there was padding
assert(len <= dest_len);
dest->resize(len);
return true;
}
// Base64Escape
//
// NOTE: We have to use an unsigned type for src because code built
// in the the /google tree treats characters as signed unless
// otherwised specified.
//
// TODO(who?): Move this function to use the char* type for "src"
int Base64EscapeInternal(const unsigned char *src, int szsrc,
char *dest, int szdest, const char *base64,
bool do_padding) {
static const char kPad64 = '=';
if (szsrc <= 0) return 0;
char *cur_dest = dest;
const unsigned char *cur_src = src;
// Three bytes of data encodes to four characters of cyphertext.
// So we can pump through three-byte chunks atomically.
while (szsrc > 2) { /* keep going until we have less than 24 bits */
if ((szdest -= 4) < 0) return 0;
cur_dest[0] = base64[cur_src[0] >> 2];
cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
cur_dest[3] = base64[cur_src[2] & 0x3f];
cur_dest += 4;
cur_src += 3;
szsrc -= 3;
}
/* now deal with the tail (<=2 bytes) */
switch (szsrc) {
case 0:
// Nothing left; nothing more to do.
break;
case 1:
// One byte left: this encodes to two characters, and (optionally)
// two pad characters to round out the four-character cypherblock.
if ((szdest -= 2) < 0) return 0;
cur_dest[0] = base64[cur_src[0] >> 2];
cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
cur_dest += 2;
if (do_padding) {
if ((szdest -= 2) < 0) return 0;
cur_dest[0] = kPad64;
cur_dest[1] = kPad64;
cur_dest += 2;
}
break;
case 2:
// Two bytes left: this encodes to three characters, and (optionally)
// one pad character to round out the four-character cypherblock.
if ((szdest -= 3) < 0) return 0;
cur_dest[0] = base64[cur_src[0] >> 2];
cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
cur_dest += 3;
if (do_padding) {
if ((szdest -= 1) < 0) return 0;
cur_dest[0] = kPad64;
cur_dest += 1;
}
break;
default:
// Should not be reached: blocks of 3 bytes are handled
// in the while loop before this switch statement.
fprintf(stderr, "Logic problem? szsrc = %d", szsrc);
assert(false);
break;
}
return (cur_dest - dest);
}
static const char kBase64Chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char kWebSafeBase64Chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
}
void Base64Escape(const unsigned char *src, int szsrc,
string* dest, bool do_padding) {
const int max_escaped_size =
CalculateBase64EscapedLen(szsrc, do_padding);
dest->clear();
dest->resize(max_escaped_size + 1, '\0');
const int escaped_len = Base64EscapeInternal(src, szsrc,
&*dest->begin(), dest->size(),
kBase64Chars,
do_padding);
assert(max_escaped_size <= escaped_len);
dest->resize(escaped_len);
}
void Base64Escape(const string& src, string* dest) {
Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
src.size(), dest, true);
}
////////////////////////////////////////////////////
// WebSafe methods
////////////////////////////////////////////////////
int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
static const signed char UnBase64[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 62/*-*/, -1, -1,
52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
-1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
-1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1
};
// The above array was generated by the following code
// #include <sys/time.h>
// #include <stdlib.h>
// #include <string.h>
// main()
// {
// static const char Base64[] =
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
// char *pos;
// int idx, i, j;
// printf(" ");
// for (i = 0; i < 255; i += 8) {
// for (j = i; j < i + 8; j++) {
// pos = strchr(Base64, j);
// if ((pos == NULL) || (j == 0))
// idx = -1;
// else
// idx = pos - Base64;
// if (idx == -1)
// printf(" %2d, ", idx);
// else
// printf(" %2d/*%c*/,", idx, j);
// }
// printf("\n ");
// }
// }
return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
}
bool WebSafeBase64Unescape(const char *src, int slen, string* dest) {
int dest_len = 3 * (slen / 4) + (slen % 4);
dest->clear();
dest->resize(dest_len);
int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size());
if (len < 0) {
dest->clear();
return false;
}
// could be shorter if there was padding
assert(len <= dest_len);
dest->resize(len);
return true;
}
bool WebSafeBase64Unescape(const string& src, string* dest) {
return WebSafeBase64Unescape(src.data(), src.size(), dest);
}
int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
int szdest, bool do_padding) {
return Base64EscapeInternal(src, szsrc, dest, szdest,
kWebSafeBase64Chars, do_padding);
}
void WebSafeBase64Escape(const unsigned char *src, int szsrc,
string *dest, bool do_padding) {
const int max_escaped_size =
CalculateBase64EscapedLen(szsrc, do_padding);
dest->clear();
dest->resize(max_escaped_size + 1, '\0');
const int escaped_len = Base64EscapeInternal(src, szsrc,
&*dest->begin(), dest->size(),
kWebSafeBase64Chars,
do_padding);
assert(max_escaped_size <= escaped_len);
dest->resize(escaped_len);
}
void WebSafeBase64EscapeInternal(const string& src,
string* dest,
bool do_padding) {
int encoded_len = CalculateBase64EscapedLen(src.size());
scoped_array<char> buf(new char[encoded_len]);
int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
src.size(), buf.get(),
encoded_len, do_padding);
dest->assign(buf.get(), len);
}
void WebSafeBase64Escape(const string& src, string* dest) {
WebSafeBase64EscapeInternal(src, dest, false);
}
void WebSafeBase64EscapeWithPadding(const string& src, string* dest) {
WebSafeBase64EscapeInternal(src, dest, true);
}
} // namespace strings

View file

@ -0,0 +1,99 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Base64 escaping methods to encode/decode strings.
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
#include <string>
namespace strings {
using std::string;
// ----------------------------------------------------------------------
// Base64Escape()
// WebSafeBase64Escape()
// Encode "src" to "dest" using base64 encoding.
// src is not null terminated, instead specify len.
// 'dest' should have at least CalculateBase64EscapedLen() length.
// RETURNS the length of dest.
// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
// so that we can place the out in the URL or cookies without having
// to escape them. It also has an extra parameter "do_padding",
// which when set to false will prevent padding with "=".
// ----------------------------------------------------------------------
void Base64Escape(const string& src, string* dest);
int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest);
// Encode src into dest with padding.
void Base64Escape(const unsigned char* src, int szsrc,
string* dest, bool do_padding);
int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest,
int szdest, bool do_padding);
// Encode src into dest web-safely without padding.
void WebSafeBase64Escape(const string& src, string* dest);
// Encode src into dest web-safely with padding.
void WebSafeBase64EscapeWithPadding(const string& src, string* dest);
void WebSafeBase64Escape(const unsigned char* src, int szsrc,
string* dest, bool do_padding);
// ----------------------------------------------------------------------
// Base64Unescape()
// WebSafeBase64Unescape()
// Copies "src" to "dest", where src is in base64 and is written to its
// ASCII equivalents. src is not null terminated, instead specify len.
// I recommend that slen<szdest, but we honor szdest anyway.
// RETURNS the length of dest, or -1 if src contains invalid chars.
// The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
// The variations that store into a string clear the string first, and
// return false (with dest empty) if src contains invalid chars; for
// these versions src and dest must be different strings.
// ----------------------------------------------------------------------
int Base64Unescape(const char* src, int slen, char* dest, int szdest);
bool Base64Unescape(const char* src, int slen, string* dest);
inline bool Base64Unescape(const string& src, string* dest) {
return Base64Unescape(src.data(), src.size(), dest);
}
int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest);
bool WebSafeBase64Unescape(const char* src, int slen, string* dest);
bool WebSafeBase64Unescape(const string& src, string* dest);
// Return the length to use for the output buffer given to the base64 escape
// routines. Make sure to use the same value for do_padding in both.
// This function may return incorrect results if given input_len values that
// are extremely high, which should happen rarely.
int CalculateBase64EscapedLen(int input_len, bool do_padding);
// Use this version when calling Base64Escape without a do_padding arg.
int CalculateBase64EscapedLen(int input_len);
} // namespace strings
#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_

View file

@ -0,0 +1,96 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
#include <tchar.h>
#include <windows.h>
#include <vector>
typedef void* HttpHandle;
namespace crash {
// HttpClient provides an abstract layer for HTTP APIs. The actual
// implementation can be based on either WinHttp or WinInet.
class HttpClient {
public:
enum AccessType {
ACCESS_TYPE_PRECONFIG,
ACCESS_TYPE_DIRECT,
ACCESS_TYPE_PROXY,
};
virtual ~HttpClient() {}
virtual bool CrackUrl(const TCHAR* url,
DWORD flags,
TCHAR* scheme,
size_t scheme_buffer_length,
TCHAR* host,
size_t host_buffer_length,
TCHAR* uri,
size_t uri_buffer_length,
int* port) const = 0;
virtual bool Open(const TCHAR* user_agent,
DWORD access_type,
const TCHAR* proxy_name,
const TCHAR* proxy_bypass,
HttpHandle* session_handle) const = 0;
virtual bool Connect(HttpHandle session_handle,
const TCHAR* server,
int port,
HttpHandle* connection_handle) const = 0;
virtual bool OpenRequest(HttpHandle connection_handle,
const TCHAR* verb,
const TCHAR* uri,
const TCHAR* version,
const TCHAR* referrer,
bool is_secure,
HttpHandle* request_handle) const = 0;
virtual bool SendRequest(HttpHandle request_handle,
const TCHAR* headers,
DWORD headers_length) const = 0;
virtual bool ReceiveResponse(HttpHandle request_handle) const = 0;
virtual bool GetHttpStatusCode(HttpHandle request_handle,
int* status_code) const = 0;
virtual bool GetContentLength(HttpHandle request_handle,
DWORD* content_length) const = 0;
virtual bool ReadData(HttpHandle request_handle,
void* buffer,
DWORD buffer_length,
DWORD* bytes_read) const = 0;
virtual bool Close(HttpHandle handle) const = 0;
static const DWORD kUnknownContentLength = (DWORD)-1;
};
} // namespace crash
#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_

View file

@ -0,0 +1,326 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <stdio.h>
#include <Windows.h>
#include <WinInet.h>
#include <vector>
#include "tools/windows/converter_exe/http_download.h"
#include "tools/windows/converter_exe/winhttp_client.h"
#include "tools/windows/converter_exe/wininet_client.h"
namespace crash {
static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB
using std::vector;
// Class that atuo closes the contained HttpHandle when the object
// goes out of scope.
class AutoHttpHandle {
public:
AutoHttpHandle() : handle_(NULL) {}
explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {}
~AutoHttpHandle() {
if (handle_) {
InternetCloseHandle(handle_);
}
}
HttpHandle get() { return handle_; }
HttpHandle* get_handle_addr () { return &handle_; }
private:
HttpHandle handle_;
};
// Template class for auto releasing the contained pointer when
// the object goes out of scope.
template<typename T>
class AutoPtr {
public:
explicit AutoPtr(T* ptr) : ptr_(ptr) {}
~AutoPtr() {
if (ptr_) {
delete ptr_;
}
}
T* get() { return ptr_; }
T* operator -> () { return ptr_; }
private:
T* ptr_;
};
// CheckParameters ensures that the parameters in |parameters| are safe for
// use in an HTTP URL. Returns true if they are, false if unsafe characters
// are present.
static bool CheckParameters(const map<wstring, wstring> *parameters) {
for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
iterator != parameters->end();
++iterator) {
const wstring &key = iterator->first;
if (key.empty()) {
// Disallow empty parameter names.
return false;
}
for (unsigned int i = 0; i < key.size(); ++i) {
wchar_t c = key[i];
if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
return false;
}
}
const wstring &value = iterator->second;
for (unsigned int i = 0; i < value.size(); ++i) {
wchar_t c = value[i];
if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
return false;
}
}
}
return true;
}
HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) {
const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP");
TCHAR buffer[2] = {0};
HttpClient* http_client = NULL;
if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable,
buffer,
sizeof(buffer)/sizeof(buffer[0])) > 0) {
fprintf(stdout,
"Environment variable [%ws] is set, use WinHttp\n",
kHttpApiPolicyEnvironmentVariable);
http_client = CreateWinHttpClient(url);
if (http_client == NULL) {
fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? "
"Fall back to WinInet API.\n");
}
} else {
fprintf(stderr,
"Environment variable [%ws] is NOT set, use WinInet API\n",
kHttpApiPolicyEnvironmentVariable);
}
if (http_client == NULL) {
return CreateWinInetClient(url);
}
return http_client;
}
// static
bool HTTPDownload::Download(const wstring &url,
const map<wstring, wstring> *parameters,
string *content, int *status_code) {
assert(content);
AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str()));
if (!http_client.get()) {
fprintf(stderr, "Failed to create any http client.\n");
return false;
}
if (status_code) {
*status_code = 0;
}
wchar_t scheme[16] = {0};
wchar_t host[256] = {0};
wchar_t path[256] = {0};
int port = 0;
if (!http_client->CrackUrl(url.c_str(),
0,
scheme,
sizeof(scheme)/sizeof(scheme[0]),
host,
sizeof(host)/sizeof(host[0]),
path,
sizeof(path)/sizeof(path[0]),
&port)) {
fprintf(stderr,
"HTTPDownload::Download: InternetCrackUrl: error %d for %ws\n",
GetLastError(), url.c_str());
return false;
}
bool secure = false;
if (_wcsicmp(scheme, L"https") == 0) {
secure = true;
} else if (wcscmp(scheme, L"http") != 0) {
fprintf(stderr,
"HTTPDownload::Download: scheme must be http or https for %ws\n",
url.c_str());
return false;
}
AutoHttpHandle internet;
if (!http_client->Open(NULL, // user agent
HttpClient::ACCESS_TYPE_PRECONFIG,
NULL, // proxy name
NULL, // proxy bypass
internet.get_handle_addr())) {
fprintf(stderr,
"HTTPDownload::Download: Open: error %d for %ws\n",
GetLastError(), url.c_str());
return false;
}
AutoHttpHandle connection;
if (!http_client->Connect(internet.get(),
host,
port,
connection.get_handle_addr())) {
fprintf(stderr,
"HTTPDownload::Download: InternetConnect: error %d for %ws\n",
GetLastError(), url.c_str());
return false;
}
wstring request_string = path;
if (parameters) {
// TODO(mmentovai): escape bad characters in parameters instead of
// forbidding them.
if (!CheckParameters(parameters)) {
fprintf(stderr,
"HTTPDownload::Download: invalid characters in parameters\n");
return false;
}
bool added_parameter = false;
for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
iterator != parameters->end();
++iterator) {
request_string.append(added_parameter ? L"&" : L"?");
request_string.append(iterator->first);
request_string.append(L"=");
request_string.append(iterator->second);
added_parameter = true;
}
}
AutoHttpHandle request;
if (!http_client->OpenRequest(connection.get(),
L"GET",
request_string.c_str(),
NULL, // version
NULL, // referer
secure,
request.get_handle_addr())) {
fprintf(stderr,
"HttpClient::OpenRequest: error %d for %ws, request: %ws\n",
GetLastError(), url.c_str(), request_string.c_str());
return false;
}
if (!http_client->SendRequest(request.get(), NULL, 0)) {
fprintf(stderr,
"HttpClient::SendRequest: error %d for %ws\n",
GetLastError(), url.c_str());
return false;
}
if (!http_client->ReceiveResponse(request.get())) {
fprintf(stderr,
"HttpClient::ReceiveResponse: error %d for %ws\n",
GetLastError(), url.c_str());
return false;
}
int http_status = 0;
if (!http_client->GetHttpStatusCode(request.get(), &http_status)) {
fprintf(stderr,
"HttpClient::GetHttpStatusCode: error %d for %ws\n",
GetLastError(), url.c_str());
return false;
}
if (http_status != 200) {
fprintf(stderr,
"HTTPDownload::Download: HTTP status code %d for %ws\n",
http_status, url.c_str());
return false;
}
DWORD content_length = 0;
vector<char>::size_type buffer_size = 0;
http_client->GetContentLength(request.get(), &content_length);
if (content_length == HttpClient::kUnknownContentLength) {
buffer_size = kVectorChunkSize;
} else {
buffer_size = content_length;
}
if (content_length != 0) {
vector<char> response_buffer = vector<char>(buffer_size+1);
DWORD size_read;
DWORD total_read = 0;
bool read_result;
do {
if (content_length == HttpClient::kUnknownContentLength
&& buffer_size == total_read) {
// The content length wasn't specified in the response header, so we
// have to keep growing the buffer until we're done reading.
buffer_size += kVectorChunkSize;
response_buffer.resize(buffer_size);
}
read_result = !!http_client->ReadData(
request.get(),
&response_buffer[total_read],
static_cast<DWORD>(buffer_size) - total_read,
&size_read);
total_read += size_read;
} while (read_result && (size_read != 0));
if (!read_result) {
fprintf(stderr,
"HttpClient::ReadData: error %d for %ws\n",
GetLastError(),
url.c_str());
return false;
} else if (size_read != 0) {
fprintf(stderr,
"HttpClient::ReadData: error %d/%d for %ws\n",
total_read,
content_length,
url.c_str());
return false;
}
content->assign(&response_buffer[0], total_read);
} else {
content->clear();
}
return true;
}
} // namespace crash

View file

@ -0,0 +1,62 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
#include <map>
#include <string>
#include "tools/windows/converter_exe/winhttp_client.h"
namespace crash {
using std::map;
using std::string;
using std::wstring;
class HTTPDownload {
public:
// Retrieves the resource located at |url|, a http or https URL, via WinInet.
// The request is fetched with GET request; the optional |parameters| are
// appended to the URL. Returns true on success, placing the content of the
// retrieved resource in |content|. Returns false on failure. HTTP status
// codes other than 200 cause Download to return false. If |status_code| is
// supplied, it will be set to the value of the HTTP status code, if an HTTP
// transaction occurs. If Download fails before a transaction can occur,
// |status_code| will be set to 0. Any failures will result in messages
// being printed to stderr.
static bool Download(const wstring &url,
const map<wstring, wstring> *parameters,
string *content, int *status_code);
private:
static HttpClient* CreateHttpClient(const wchar_t*);
};
} // namespace crash
#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_

View file

@ -0,0 +1,2 @@
msctf.pdb|6A5BABB8E88644C696530BFE3C90F32F2|6.1.7600.16385|msctf.dll|4A5BDFAA109000
imm32.pdb|98F27BA5AEE541ECBEE00CD03AD50FEE2|6.1.7600.16385|imm32.dll|4A5BDF402e000

View file

@ -0,0 +1,2 @@
See breakpad/tools/windows/converter/ms_symbol_server_converter.h for a
description of this file's function.

View file

@ -0,0 +1,61 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include "tools/windows/converter_exe/tokenizer.h"
namespace crash {
// static
void Tokenizer::Tokenize(const string &delimiters, const string &input,
vector<string> *output) {
assert(output);
output->clear();
string::size_type position = 0; // Where to begin looking for a delimiter
string::size_type new_position; // Position of found delimiter
string token;
while ((new_position = input.find_first_of(delimiters, position)) !=
string::npos) {
token = input.substr(position, new_position - position);
output->push_back(token);
// Next time, begin looking right after this delimiter.
position = new_position + 1;
}
// There are no more delimiters in the string. Take everything from the
// final delimiter up to the end of the string as a token. This may be
// an empty string.
token = input.substr(position);
output->push_back(token);
}
} // namespace crash

View file

@ -0,0 +1,51 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
#include <string>
#include <vector>
namespace crash {
using std::string;
using std::vector;
class Tokenizer {
public:
// Splits |input| into a series of tokens delimited in the input string by
// any of the characters in |delimiters|. The tokens are passed back in the
// |output| vector.
static void Tokenize(const string &delimiters, const string &input,
vector<string> *output);
};
} // namespace crash
#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_

View file

@ -0,0 +1,307 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "tools/windows/converter_exe/winhttp_client.h"
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
#include <winhttp.h>
#include <vector>
namespace crash {
namespace internal {
// This class implements HttpClient based on WinInet APIs.
class WinHttpClient : public HttpClient {
public:
virtual ~WinHttpClient() {}
virtual bool CrackUrl(const TCHAR* url,
DWORD flags,
TCHAR* scheme,
size_t scheme_buffer_length,
TCHAR* host,
size_t host_buffer_length,
TCHAR* uri,
size_t uri_buffer_length,
int* port) const;
virtual bool Open(const TCHAR* user_agent,
DWORD access_type,
const TCHAR* proxy_name,
const TCHAR* proxy_bypass,
HttpHandle* session_handle) const;
virtual bool Connect(HttpHandle session_handle,
const TCHAR* server,
int port,
HttpHandle* connection_handle) const;
virtual bool OpenRequest(HttpHandle connection_handle,
const TCHAR* verb,
const TCHAR* uri,
const TCHAR* version,
const TCHAR* referrer,
bool is_secure,
HttpHandle* request_handle) const;
virtual bool SendRequest(HttpHandle request_handle,
const TCHAR* headers,
DWORD headers_length) const;
virtual bool ReceiveResponse(HttpHandle request_handle) const;
virtual bool GetHttpStatusCode(HttpHandle request_handle,
int* status_code) const;
virtual bool GetContentLength(HttpHandle request_handle,
DWORD* content_length) const;
virtual bool ReadData(HttpHandle request_handle,
void* buffer,
DWORD buffer_length,
DWORD* bytes_read) const;
virtual bool Close(HttpHandle handle) const;
private:
static DWORD MapAccessType(DWORD access_type);
static HINTERNET ToHINTERNET(HttpHandle handle);
static HttpHandle FromHINTERNET(HINTERNET handle);
};
bool WinHttpClient::CrackUrl(const TCHAR* url,
DWORD flags,
TCHAR* scheme,
size_t scheme_buffer_length,
TCHAR* host,
size_t host_buffer_length,
TCHAR* uri,
size_t uri_buffer_length,
int* port) const {
assert(url);
assert(scheme);
assert(host);
assert(uri);
assert(port);
URL_COMPONENTS url_comp = {0};
url_comp.dwStructSize = sizeof(url_comp);
url_comp.lpszScheme = scheme;
url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
url_comp.lpszHostName = host;
url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
url_comp.lpszUrlPath = uri;
url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
if (result) {
*port = static_cast<int>(url_comp.nPort);
}
return result;
}
bool WinHttpClient::Open(const TCHAR* user_agent,
DWORD access_type,
const TCHAR* proxy_name,
const TCHAR* proxy_bypass,
HttpHandle* session_handle) const {
*session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
MapAccessType(access_type),
proxy_name,
proxy_bypass,
0));
return !!(*session_handle);
}
bool WinHttpClient::Connect(HttpHandle session_handle,
const TCHAR* server,
int port,
HttpHandle* connection_handle) const {
assert(server);
// Uses NULL user name and password to connect.
*connection_handle = FromHINTERNET(::WinHttpConnect(
ToHINTERNET(session_handle),
server,
static_cast<INTERNET_PORT>(port),
NULL));
return !!(*connection_handle);
}
bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
const TCHAR* verb,
const TCHAR* uri,
const TCHAR* version,
const TCHAR* referrer,
bool is_secure,
HttpHandle* request_handle) const {
assert(connection_handle);
assert(verb);
assert(uri);
assert(request_handle);
*request_handle = FromHINTERNET(::WinHttpOpenRequest(
ToHINTERNET(connection_handle),
verb,
uri,
version,
referrer,
WINHTTP_DEFAULT_ACCEPT_TYPES,
is_secure ? WINHTTP_FLAG_SECURE : 0));
return !!(*request_handle);
}
bool WinHttpClient::SendRequest(HttpHandle request_handle,
const TCHAR* headers,
DWORD headers_length) const {
assert(request_handle);
return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
headers,
headers_length,
NULL,
0,
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
NULL);
}
bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
assert(request_handle);
return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
}
bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
int* status_code) const {
TCHAR http_status_string[4] = {0};
DWORD http_status_string_size = sizeof(http_status_string);
if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
WINHTTP_QUERY_STATUS_CODE,
WINHTTP_HEADER_NAME_BY_INDEX,
static_cast<void *>(&http_status_string),
&http_status_string_size, 0)) {
return false;
}
*status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
return true;
}
bool WinHttpClient::GetContentLength(HttpHandle request_handle,
DWORD* content_length) const {
assert(request_handle);
assert(content_length);
TCHAR content_length_string[11] = {0};
DWORD content_length_string_size = sizeof(content_length_string);
if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
WINHTTP_QUERY_CONTENT_LENGTH,
WINHTTP_HEADER_NAME_BY_INDEX,
static_cast<void *>(&content_length_string),
&content_length_string_size, 0)) {
*content_length = kUnknownContentLength;
} else {
*content_length =
static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
}
return true;
}
bool WinHttpClient::ReadData(HttpHandle request_handle,
void* buffer,
DWORD buffer_length,
DWORD* bytes_read) const {
assert(request_handle);
assert(buffer);
assert(bytes_read);
DWORD bytes_read_local = 0;
if (!::WinHttpReadData(ToHINTERNET(request_handle),
buffer,
buffer_length,
&bytes_read_local)) {
return false;
}
*bytes_read = bytes_read_local;
return true;
}
bool WinHttpClient::Close(HttpHandle handle) const {
assert(handle);
return !!::WinHttpCloseHandle(ToHINTERNET(handle));
}
DWORD WinHttpClient::MapAccessType(DWORD access_type) {
switch (static_cast<AccessType>(access_type)) {
case ACCESS_TYPE_PRECONFIG:
default:
return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
case ACCESS_TYPE_DIRECT:
return WINHTTP_ACCESS_TYPE_NO_PROXY;
case ACCESS_TYPE_PROXY:
return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
}
}
HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
return static_cast<HINTERNET>(handle);
}
HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
return static_cast<HttpHandle>(handle);
}
} // namespace internal
HttpClient* CreateWinHttpClient(const TCHAR* url) {
assert(url);
internal::WinHttpClient winhttp;
wchar_t scheme[16] = {0};
wchar_t host[256] = {0};
wchar_t path[256] = {0};
int port = 0;
if (!winhttp.CrackUrl(url,
0,
scheme,
sizeof(scheme)/sizeof(scheme[0]),
host,
sizeof(host)/sizeof(host[0]),
path,
sizeof(path)/sizeof(path[0]),
&port)) {
return NULL;
}
if (_wcsicmp(scheme, L"https") == 0) {
// Winhttp under WINE doesn't support wildcard certificates, so avoid
// to use it if the scheme is https. The caller should fall back to
// use wininet if NULL is returned.
return NULL;
}
return new internal::WinHttpClient();
}
} // namespace crash

View file

@ -0,0 +1,40 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
#include "tools/windows/converter_exe/http_client.h"
namespace crash {
HttpClient* CreateWinHttpClient(const TCHAR* url);
} // namespace crash
#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_

View file

@ -0,0 +1,278 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "tools/windows/converter_exe/wininet_client.h"
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
#include <wininet.h>
namespace crash {
namespace internal {
// This class implements HttpClient based on WinInet APIs.
class WinInetClient : public HttpClient {
public:
virtual ~WinInetClient() {}
virtual bool CrackUrl(const TCHAR* url,
DWORD flags,
TCHAR* scheme,
size_t scheme_buffer_length,
TCHAR* host,
size_t host_buffer_length,
TCHAR* uri,
size_t uri_buffer_length,
int* port) const;
virtual bool Open(const TCHAR* user_agent,
DWORD access_type,
const TCHAR* proxy_name,
const TCHAR* proxy_bypass,
HttpHandle* session_handle) const;
virtual bool Connect(HttpHandle session_handle,
const TCHAR* server,
int port,
HttpHandle* connection_handle) const;
virtual bool OpenRequest(HttpHandle connection_handle,
const TCHAR* verb,
const TCHAR* uri,
const TCHAR* version,
const TCHAR* referrer,
bool is_secure,
HttpHandle* request_handle) const;
virtual bool SendRequest(HttpHandle request_handle,
const TCHAR* headers,
DWORD headers_length) const;
virtual bool ReceiveResponse(HttpHandle request_handle) const;
virtual bool GetHttpStatusCode(HttpHandle request_handle,
int* status_code) const;
virtual bool GetContentLength(HttpHandle request_handle,
DWORD* content_length) const;
virtual bool ReadData(HttpHandle request_handle,
void* buffer,
DWORD buffer_length,
DWORD* bytes_read) const;
virtual bool Close(HttpHandle handle) const;
private:
static DWORD MapAccessType(DWORD access_type);
static HINTERNET ToHINTERNET(HttpHandle handle);
static HttpHandle FromHINTERNET(HINTERNET handle);
};
bool WinInetClient::CrackUrl(const TCHAR* url,
DWORD flags,
TCHAR* scheme,
size_t scheme_buffer_length,
TCHAR* host,
size_t host_buffer_length,
TCHAR* uri,
size_t uri_buffer_length,
int* port) const {
assert(url);
assert(scheme);
assert(host);
assert(uri);
assert(port);
URL_COMPONENTS url_comp = {0};
url_comp.dwStructSize = sizeof(url_comp);
url_comp.lpszScheme = scheme;
url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
url_comp.lpszHostName = host;
url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
url_comp.lpszUrlPath = uri;
url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
if (result) {
*port = static_cast<int>(url_comp.nPort);
}
return result;
}
bool WinInetClient::Open(const TCHAR* user_agent,
DWORD access_type,
const TCHAR* proxy_name,
const TCHAR* proxy_bypass,
HttpHandle* session_handle) const {
*session_handle = FromHINTERNET(::InternetOpen(user_agent,
MapAccessType(access_type),
proxy_name,
proxy_bypass,
0));
return !!(*session_handle);
}
bool WinInetClient::Connect(HttpHandle session_handle,
const TCHAR* server,
int port,
HttpHandle* connection_handle) const {
assert(server);
// Uses NULL user name and password to connect. Always uses http service.
*connection_handle = FromHINTERNET(::InternetConnect(
ToHINTERNET(session_handle),
server,
static_cast<INTERNET_PORT>(port),
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0));
return !!(*connection_handle);
}
bool WinInetClient::OpenRequest(HttpHandle connection_handle,
const TCHAR* verb,
const TCHAR* uri,
const TCHAR* version,
const TCHAR* referrer,
bool is_secure,
HttpHandle* request_handle) const {
assert(connection_handle);
assert(verb);
assert(uri);
*request_handle = FromHINTERNET(::HttpOpenRequest(
ToHINTERNET(connection_handle),
verb,
uri,
version,
referrer,
NULL,
is_secure ? INTERNET_FLAG_SECURE : 0,
NULL));
return !!(*request_handle);
}
bool WinInetClient::SendRequest(HttpHandle request_handle,
const TCHAR* headers,
DWORD headers_length) const {
assert(request_handle);
return !!::HttpSendRequest(ToHINTERNET(request_handle),
headers,
headers_length,
NULL,
0);
}
bool WinInetClient::ReceiveResponse(HttpHandle) const {
return true;
}
bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
int* status_code) const {
assert(request_handle);
TCHAR http_status_string[4] = {0};
DWORD http_status_string_size = sizeof(http_status_string);
if (!::HttpQueryInfo(ToHINTERNET(request_handle),
HTTP_QUERY_STATUS_CODE,
static_cast<void *>(&http_status_string),
&http_status_string_size,
0)) {
return false;
}
*status_code = _tcstol(http_status_string, NULL, 10);
return true;
}
bool WinInetClient::GetContentLength(HttpHandle request_handle,
DWORD* content_length) const {
assert(request_handle);
assert(content_length);
TCHAR content_length_string[11];
DWORD content_length_string_size = sizeof(content_length_string);
if (!::HttpQueryInfo(ToHINTERNET(request_handle),
HTTP_QUERY_CONTENT_LENGTH,
static_cast<void *>(&content_length_string),
&content_length_string_size,
0)) {
*content_length = kUnknownContentLength;
} else {
*content_length = wcstol(content_length_string, NULL, 10);
}
return true;
}
bool WinInetClient::ReadData(HttpHandle request_handle,
void* buffer,
DWORD buffer_length,
DWORD* bytes_read) const {
assert(request_handle);
assert(buffer);
assert(bytes_read);
DWORD bytes_read_local = 0;
if (!::InternetReadFile(ToHINTERNET(request_handle),
buffer,
buffer_length,
&bytes_read_local)) {
return false;
}
*bytes_read = bytes_read_local;
return true;
}
bool WinInetClient::Close(HttpHandle handle) const {
assert(handle);
return !!::InternetCloseHandle(ToHINTERNET(handle));
}
DWORD WinInetClient::MapAccessType(DWORD access_type) {
switch (static_cast<AccessType>(access_type)) {
case ACCESS_TYPE_PRECONFIG:
default:
return INTERNET_OPEN_TYPE_PRECONFIG;
case ACCESS_TYPE_DIRECT:
return INTERNET_OPEN_TYPE_DIRECT;
case ACCESS_TYPE_PROXY:
return INTERNET_OPEN_TYPE_PROXY;
}
}
HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
return static_cast<HINTERNET>(handle);
}
HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
return static_cast<HttpHandle>(handle);
}
} // namespace internal
HttpClient* CreateWinInetClient(const TCHAR*) {
return new internal::WinInetClient();
}
} // namespace crash

View file

@ -0,0 +1,40 @@
// Copyright 2019 Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
#include "tools/windows/converter_exe/http_client.h"
namespace crash {
HttpClient* CreateWinInetClient(const TCHAR* url);
} // namespace crash
#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_

View file

@ -37,6 +37,7 @@
'type': 'none',
'dependencies': [
'./converter/ms_symbol_server_converter.gyp:*',
'./converter_exe/converter.gyp:*',
'./dump_syms/dump_syms.gyp:*',
'./symupload/symupload.gyp:*',
],