mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +08: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_minor_ = ffi.dwFileVersionMS & 0xffff;
|
||||
os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
|
||||
os_version_build_ =
|
||||
base::StringPrintf("%d", ffi.dwFileVersionLS & 0xffff);
|
||||
os_version_build_ = base::StringPrintf("%u", ffi.dwFileVersionLS & 0xffff);
|
||||
os_version_full_ = base::StringPrintf(
|
||||
"%s %d.%d.%d.%s%s",
|
||||
"%s %u.%u.%u.%s%s",
|
||||
os_name.c_str(),
|
||||
os_version_major_,
|
||||
os_version_minor_,
|
||||
os_version_bugfix_,
|
||||
os_version_build_.c_str(),
|
||||
flags_string.empty() ? "" : (std::string(" (") + flags_string + ")")
|
||||
.c_str());
|
||||
flags_string.empty()
|
||||
? ""
|
||||
: (std::string(" (") + flags_string + ")").c_str());
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "base/mac/foundation_util.h"
|
||||
#import "base/mac/scoped_nsobject.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "package.h"
|
||||
#include "third_party/apple_cf/CFStreamAbstract.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/misc/implicit_cast.h"
|
||||
@ -30,6 +33,80 @@ namespace crashpad {
|
||||
|
||||
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
|
||||
// scheme.
|
||||
class HTTPBodyStreamCFReadStream {
|
||||
@ -171,6 +248,13 @@ bool HTTPTransportMac::ExecuteSynchronously(std::string* response_body) {
|
||||
timeoutInterval:timeout()];
|
||||
[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()) {
|
||||
[request setValue:base::SysUTF8ToNSString(pair.second)
|
||||
forHTTPHeaderField:base::SysUTF8ToNSString(pair.first)];
|
||||
|
@ -28,15 +28,59 @@
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "package.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/numeric/safe_assignment.h"
|
||||
#include "util/net/http_body.h"
|
||||
#include "util/win/module_version.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
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
|
||||
// FORMAT_MESSAGE_FROM_HMODULE + the dll name manually here.
|
||||
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 |
|
||||
FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_HMODULE;
|
||||
DWORD len = FormatMessageA(flags,
|
||||
GetModuleHandle(L"winhttp.dll"),
|
||||
GetModuleHandle(kWinHttpDll),
|
||||
error_code,
|
||||
0,
|
||||
msgbuf,
|
||||
@ -93,12 +137,11 @@ HTTPTransportWin::~HTTPTransportWin() {
|
||||
}
|
||||
|
||||
bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
|
||||
ScopedHINTERNET session(
|
||||
WinHttpOpen(base::UTF8ToUTF16(PACKAGE_NAME "/" PACKAGE_VERSION).c_str(),
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS,
|
||||
0));
|
||||
ScopedHINTERNET session(WinHttpOpen(base::UTF8ToUTF16(UserAgent()).c_str(),
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS,
|
||||
0));
|
||||
if (!session.get()) {
|
||||
LOG(ERROR) << WinHttpMessage("WinHttpOpen");
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user