mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-17 08:33:54 +00:00
net: Provide better HTTP User-Agent strings
Previously, macOS used “User-Agent: crashpad_util_test (unknown version) CFNetwork/807.2.14 Darwin/16.4.0 (x86_64)” and Windows gave results like “User-Agent: Crashpad/0.8.0”. Now, macOS uses “User-Agent: Crashpad/0.8.0 CFNetwork/807.2.14 Darwin/16.4.0 (x86_64)” and Windows uses “User-Agent: Crashpad/0.8.0 WinHTTP/10.0.14393.351 Windows_NT/10.0.14393.0 (x64)” Change-Id: I578b44734cf59d79e3d9b6136b4b92f05acefe71 Reviewed-on: https://chromium-review.googlesource.com/447796 Reviewed-by: Robert Sesek <rsesek@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
parent
bf2c5155d2
commit
60be5a66a0
@ -106,17 +106,17 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) {
|
|||||||
os_version_major_ = ffi.dwFileVersionMS >> 16;
|
os_version_major_ = ffi.dwFileVersionMS >> 16;
|
||||||
os_version_minor_ = ffi.dwFileVersionMS & 0xffff;
|
os_version_minor_ = ffi.dwFileVersionMS & 0xffff;
|
||||||
os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
|
os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
|
||||||
os_version_build_ =
|
os_version_build_ = base::StringPrintf("%u", ffi.dwFileVersionLS & 0xffff);
|
||||||
base::StringPrintf("%d", ffi.dwFileVersionLS & 0xffff);
|
|
||||||
os_version_full_ = base::StringPrintf(
|
os_version_full_ = base::StringPrintf(
|
||||||
"%s %d.%d.%d.%s%s",
|
"%s %u.%u.%u.%s%s",
|
||||||
os_name.c_str(),
|
os_name.c_str(),
|
||||||
os_version_major_,
|
os_version_major_,
|
||||||
os_version_minor_,
|
os_version_minor_,
|
||||||
os_version_bugfix_,
|
os_version_bugfix_,
|
||||||
os_version_build_.c_str(),
|
os_version_build_.c_str(),
|
||||||
flags_string.empty() ? "" : (std::string(" (") + flags_string + ")")
|
flags_string.empty()
|
||||||
.c_str());
|
? ""
|
||||||
|
: (std::string(" (") + flags_string + ")").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||||
|
@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
#include "base/mac/foundation_util.h"
|
#include "base/mac/foundation_util.h"
|
||||||
#import "base/mac/scoped_nsobject.h"
|
#import "base/mac/scoped_nsobject.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/strings/sys_string_conversions.h"
|
#include "base/strings/sys_string_conversions.h"
|
||||||
|
#include "build/build_config.h"
|
||||||
|
#include "package.h"
|
||||||
#include "third_party/apple_cf/CFStreamAbstract.h"
|
#include "third_party/apple_cf/CFStreamAbstract.h"
|
||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/misc/implicit_cast.h"
|
#include "util/misc/implicit_cast.h"
|
||||||
@ -30,6 +33,80 @@ namespace crashpad {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
NSString* AppendEscapedFormat(NSString* base,
|
||||||
|
NSString* format,
|
||||||
|
NSString* data) {
|
||||||
|
return [base stringByAppendingFormat:
|
||||||
|
format,
|
||||||
|
[data stringByAddingPercentEncodingWithAllowedCharacters:
|
||||||
|
[[NSCharacterSet
|
||||||
|
characterSetWithCharactersInString:
|
||||||
|
@"()<>@,;:\\\"/[]?={} \t"] invertedSet]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This builds the same User-Agent string that CFNetwork would build internally,
|
||||||
|
// but it uses PACKAGE_NAME and PACKAGE_VERSION in place of values obtained from
|
||||||
|
// the main bundle’s Info.plist.
|
||||||
|
NSString* UserAgentString() {
|
||||||
|
NSString* user_agent = [NSString string];
|
||||||
|
|
||||||
|
// CFNetwork would use the main bundle’s CFBundleName, or the main
|
||||||
|
// executable’s filename if none.
|
||||||
|
user_agent = AppendEscapedFormat(
|
||||||
|
user_agent, @"%@", [NSString stringWithUTF8String:PACKAGE_NAME]);
|
||||||
|
|
||||||
|
// CFNetwork would use the main bundle’s CFBundleVersion, or the string
|
||||||
|
// “(unknown version)” if none.
|
||||||
|
user_agent = AppendEscapedFormat(
|
||||||
|
user_agent, @"/%@", [NSString stringWithUTF8String:PACKAGE_VERSION]);
|
||||||
|
|
||||||
|
// Expected to be CFNetwork.
|
||||||
|
NSBundle* nsurl_bundle = [NSBundle bundleForClass:[NSURLRequest class]];
|
||||||
|
NSString* bundle_name = base::mac::ObjCCast<NSString>([nsurl_bundle
|
||||||
|
objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
|
||||||
|
if (bundle_name) {
|
||||||
|
user_agent = AppendEscapedFormat(user_agent, @" %@", bundle_name);
|
||||||
|
|
||||||
|
NSString* bundle_version = base::mac::ObjCCast<NSString>([nsurl_bundle
|
||||||
|
objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleVersionKey)]);
|
||||||
|
if (bundle_version) {
|
||||||
|
user_agent = AppendEscapedFormat(user_agent, @"/%@", bundle_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utsname os;
|
||||||
|
if (uname(&os) != 0) {
|
||||||
|
PLOG(WARNING) << "uname";
|
||||||
|
} else {
|
||||||
|
user_agent = AppendEscapedFormat(
|
||||||
|
user_agent, @" %@", [NSString stringWithUTF8String:os.sysname]);
|
||||||
|
user_agent = AppendEscapedFormat(
|
||||||
|
user_agent, @"/%@", [NSString stringWithUTF8String:os.release]);
|
||||||
|
|
||||||
|
// CFNetwork just uses the equivalent of os.machine to obtain the native
|
||||||
|
// (kernel) architecture. Here, give the process’ architecture as well as
|
||||||
|
// the native architecture. Use the same strings that the kernel would, so
|
||||||
|
// that they can be de-duplicated.
|
||||||
|
#if defined(ARCH_CPU_X86)
|
||||||
|
NSString* arch = @"i386";
|
||||||
|
#elif defined(ARCH_CPU_X86_64)
|
||||||
|
NSString* arch = @"x86_64";
|
||||||
|
#else
|
||||||
|
#error Port
|
||||||
|
#endif
|
||||||
|
user_agent = AppendEscapedFormat(user_agent, @" (%@", arch);
|
||||||
|
|
||||||
|
NSString* machine = [NSString stringWithUTF8String:os.machine];
|
||||||
|
if (![machine isEqualToString:arch]) {
|
||||||
|
user_agent = AppendEscapedFormat(user_agent, @"; %@", machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
user_agent = [user_agent stringByAppendingString:@")"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return user_agent;
|
||||||
|
}
|
||||||
|
|
||||||
// An implementation of CFReadStream. This implements the V0 callback
|
// An implementation of CFReadStream. This implements the V0 callback
|
||||||
// scheme.
|
// scheme.
|
||||||
class HTTPBodyStreamCFReadStream {
|
class HTTPBodyStreamCFReadStream {
|
||||||
@ -171,6 +248,13 @@ bool HTTPTransportMac::ExecuteSynchronously(std::string* response_body) {
|
|||||||
timeoutInterval:timeout()];
|
timeoutInterval:timeout()];
|
||||||
[request setHTTPMethod:base::SysUTF8ToNSString(method())];
|
[request setHTTPMethod:base::SysUTF8ToNSString(method())];
|
||||||
|
|
||||||
|
// If left to its own devices, CFNetwork would build a user-agent string
|
||||||
|
// based on keys in the main bundle’s Info.plist, giving ugly results if
|
||||||
|
// there is no Info.plist. Provide a User-Agent string similar to the one
|
||||||
|
// that CFNetwork would use, but with appropriate values in place of the
|
||||||
|
// Info.plist-derived strings.
|
||||||
|
[request setValue:UserAgentString() forHTTPHeaderField:@"User-Agent"];
|
||||||
|
|
||||||
for (const auto& pair : headers()) {
|
for (const auto& pair : headers()) {
|
||||||
[request setValue:base::SysUTF8ToNSString(pair.second)
|
[request setValue:base::SysUTF8ToNSString(pair.second)
|
||||||
forHTTPHeaderField:base::SysUTF8ToNSString(pair.first)];
|
forHTTPHeaderField:base::SysUTF8ToNSString(pair.first)];
|
||||||
|
@ -28,15 +28,59 @@
|
|||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "build/build_config.h"
|
||||||
#include "package.h"
|
#include "package.h"
|
||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/numeric/safe_assignment.h"
|
#include "util/numeric/safe_assignment.h"
|
||||||
#include "util/net/http_body.h"
|
#include "util/net/http_body.h"
|
||||||
|
#include "util/win/module_version.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const wchar_t kWinHttpDll[] = L"winhttp.dll";
|
||||||
|
|
||||||
|
std::string UserAgent() {
|
||||||
|
std::string user_agent =
|
||||||
|
base::StringPrintf("%s/%s WinHTTP", PACKAGE_NAME, PACKAGE_VERSION);
|
||||||
|
|
||||||
|
VS_FIXEDFILEINFO version;
|
||||||
|
if (GetModuleVersionAndType(base::FilePath(kWinHttpDll), &version)) {
|
||||||
|
user_agent.append(base::StringPrintf("/%u.%u.%u.%u",
|
||||||
|
version.dwFileVersionMS >> 16,
|
||||||
|
version.dwFileVersionMS & 0xffff,
|
||||||
|
version.dwFileVersionLS >> 16,
|
||||||
|
version.dwFileVersionLS & 0xffff));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetModuleVersionAndType(base::FilePath(L"kernel32.dll"), &version) &&
|
||||||
|
(version.dwFileOS & VOS_NT_WINDOWS32) == VOS_NT_WINDOWS32) {
|
||||||
|
user_agent.append(base::StringPrintf(" Windows_NT/%u.%u.%u.%u (",
|
||||||
|
version.dwFileVersionMS >> 16,
|
||||||
|
version.dwFileVersionMS & 0xffff,
|
||||||
|
version.dwFileVersionLS >> 16,
|
||||||
|
version.dwFileVersionLS & 0xffff));
|
||||||
|
#if defined(ARCH_CPU_X86)
|
||||||
|
user_agent.append("x86");
|
||||||
|
#elif defined(ARCH_CPU_X86_64)
|
||||||
|
user_agent.append("x64");
|
||||||
|
#else
|
||||||
|
#error Port
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOOL is_wow64;
|
||||||
|
if (!IsWow64Process(GetCurrentProcess(), &is_wow64)) {
|
||||||
|
PLOG(WARNING) << "IsWow64Process";
|
||||||
|
} else if (is_wow64) {
|
||||||
|
user_agent.append("; WoW64");
|
||||||
|
}
|
||||||
|
user_agent.append(1, ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
return user_agent;
|
||||||
|
}
|
||||||
|
|
||||||
// PLOG doesn't work for messages from WinHTTP, so we need to use
|
// PLOG doesn't work for messages from WinHTTP, so we need to use
|
||||||
// FORMAT_MESSAGE_FROM_HMODULE + the dll name manually here.
|
// FORMAT_MESSAGE_FROM_HMODULE + the dll name manually here.
|
||||||
std::string WinHttpMessage(const char* extra) {
|
std::string WinHttpMessage(const char* extra) {
|
||||||
@ -45,7 +89,7 @@ std::string WinHttpMessage(const char* extra) {
|
|||||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
|
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||||
FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_HMODULE;
|
FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_HMODULE;
|
||||||
DWORD len = FormatMessageA(flags,
|
DWORD len = FormatMessageA(flags,
|
||||||
GetModuleHandle(L"winhttp.dll"),
|
GetModuleHandle(kWinHttpDll),
|
||||||
error_code,
|
error_code,
|
||||||
0,
|
0,
|
||||||
msgbuf,
|
msgbuf,
|
||||||
@ -93,12 +137,11 @@ HTTPTransportWin::~HTTPTransportWin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
|
bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
|
||||||
ScopedHINTERNET session(
|
ScopedHINTERNET session(WinHttpOpen(base::UTF8ToUTF16(UserAgent()).c_str(),
|
||||||
WinHttpOpen(base::UTF8ToUTF16(PACKAGE_NAME "/" PACKAGE_VERSION).c_str(),
|
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
WINHTTP_NO_PROXY_NAME,
|
||||||
WINHTTP_NO_PROXY_NAME,
|
WINHTTP_NO_PROXY_BYPASS,
|
||||||
WINHTTP_NO_PROXY_BYPASS,
|
0));
|
||||||
0));
|
|
||||||
if (!session.get()) {
|
if (!session.get()) {
|
||||||
LOG(ERROR) << WinHttpMessage("WinHttpOpen");
|
LOG(ERROR) << WinHttpMessage("WinHttpOpen");
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user