mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-17 16:43:53 +00:00
fuchsia: Implement TLS support in HTTPTransportSocket
With use_boringssl_for_http_transport_socket set, this also works on Linux, however the bots fail during run lacking libcrypto.so.1.1. So, not enabled on Linux until that's figured out. (Includes https://github.com/yhirose/cpp-httplib/pull/70, until it lands and I'll do a full roll of cpp-httplib then.) Bug: crashpad:30, crashpad:196 Change-Id: I987f6a87f8e47160c15e53fe1ce28611339069ff Reviewed-on: https://chromium-review.googlesource.com/1075726 Reviewed-by: Robert Sesek <rsesek@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org>
This commit is contained in:
parent
5191992ae5
commit
5c49c59847
@ -230,6 +230,10 @@ base::FilePath TestPaths::BuildArtifact(
|
|||||||
directory = base::FilePath();
|
directory = base::FilePath();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FileType::kCertificate:
|
||||||
|
extension = FILE_PATH_LITERAL(".pem");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return directory.Append(test_name + FILE_PATH_LITERAL("_") + artifact +
|
return directory.Append(test_name + FILE_PATH_LITERAL("_") + artifact +
|
||||||
|
@ -39,6 +39,9 @@ class TestPaths {
|
|||||||
//! \brief `.dll` will be used on Windows, and `.so` will be used on other
|
//! \brief `.dll` will be used on Windows, and `.so` will be used on other
|
||||||
//! platforms.
|
//! platforms.
|
||||||
kLoadableModule,
|
kLoadableModule,
|
||||||
|
|
||||||
|
//! \brief `.pem` used for all platforms.
|
||||||
|
kCertificate,
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \brief The architecture of the file requested of BuildArtifact().
|
//! \brief The architecture of the file requested of BuildArtifact().
|
||||||
|
14
third_party/cpp-httplib/cpp-httplib/httplib.h
vendored
14
third_party/cpp-httplib/cpp-httplib/httplib.h
vendored
@ -1630,12 +1630,18 @@ inline int Server::bind_internal(const char* host, int port, int socket_flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0) {
|
if (port == 0) {
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_storage address;
|
||||||
socklen_t len = sizeof(sin);
|
socklen_t len = sizeof(address);
|
||||||
if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&sin), &len) == -1) {
|
if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&address), &len) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ntohs(sin.sin_port);
|
if (address.ss_family == AF_INET) {
|
||||||
|
return ntohs(reinterpret_cast<struct sockaddr_in*>(&address)->sin_port);
|
||||||
|
} else if (address.ss_family == AF_INET6) {
|
||||||
|
return ntohs(reinterpret_cast<struct sockaddr_in6*>(&address)->sin6_port);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
|
|
||||||
import("../build/crashpad_buildconfig.gni")
|
import("../build/crashpad_buildconfig.gni")
|
||||||
|
|
||||||
|
declare_args() {
|
||||||
|
use_boringssl_for_http_transport_socket = crashpad_is_fuchsia
|
||||||
|
}
|
||||||
|
|
||||||
if (crashpad_is_mac) {
|
if (crashpad_is_mac) {
|
||||||
if (crashpad_is_in_chromium) {
|
if (crashpad_is_in_chromium) {
|
||||||
import("//build/config/sysroot.gni")
|
import("//build/config/sysroot.gni")
|
||||||
@ -246,6 +250,13 @@ static_library("util") {
|
|||||||
|
|
||||||
if (crashpad_is_linux || crashpad_is_fuchsia) {
|
if (crashpad_is_linux || crashpad_is_fuchsia) {
|
||||||
sources += [ "net/http_transport_socket.cc" ]
|
sources += [ "net/http_transport_socket.cc" ]
|
||||||
|
if (use_boringssl_for_http_transport_socket) {
|
||||||
|
defines = [ "CRASHPAD_USE_BORINGSSL" ]
|
||||||
|
libs = [
|
||||||
|
"crypto",
|
||||||
|
"ssl",
|
||||||
|
]
|
||||||
|
}
|
||||||
} else if (crashpad_is_android) {
|
} else if (crashpad_is_android) {
|
||||||
sources += [ "net/http_transport_none.cc" ]
|
sources += [ "net/http_transport_none.cc" ]
|
||||||
}
|
}
|
||||||
@ -379,11 +390,11 @@ static_library("util") {
|
|||||||
|
|
||||||
if (crashpad_is_fuchsia) {
|
if (crashpad_is_fuchsia) {
|
||||||
sources += [
|
sources += [
|
||||||
"fuchsia/system_exception_port_key.h",
|
|
||||||
"fuchsia/koid_utilities.cc",
|
"fuchsia/koid_utilities.cc",
|
||||||
"fuchsia/koid_utilities.h",
|
"fuchsia/koid_utilities.h",
|
||||||
"fuchsia/scoped_task_suspend.cc",
|
"fuchsia/scoped_task_suspend.cc",
|
||||||
"fuchsia/scoped_task_suspend.h",
|
"fuchsia/scoped_task_suspend.h",
|
||||||
|
"fuchsia/system_exception_port_key.h",
|
||||||
"misc/capture_context_fuchsia.S",
|
"misc/capture_context_fuchsia.S",
|
||||||
"misc/paths_fuchsia.cc",
|
"misc/paths_fuchsia.cc",
|
||||||
"process/process_memory_fuchsia.cc",
|
"process/process_memory_fuchsia.cc",
|
||||||
@ -435,6 +446,17 @@ static_library("util") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_boringssl_for_http_transport_socket) {
|
||||||
|
action("generate_test_server_key") {
|
||||||
|
script = "net/generate_test_server_key.py"
|
||||||
|
outputs = [
|
||||||
|
"$root_out_dir/crashpad_util_test_cert.pem",
|
||||||
|
"$root_out_dir/crashpad_util_test_key.pem",
|
||||||
|
]
|
||||||
|
data = outputs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!crashpad_is_android) {
|
if (!crashpad_is_android) {
|
||||||
crashpad_executable("http_transport_test_server") {
|
crashpad_executable("http_transport_test_server") {
|
||||||
testonly = true
|
testonly = true
|
||||||
@ -451,14 +473,21 @@ if (!crashpad_is_android) {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if (crashpad_is_standalone) {
|
if (crashpad_is_standalone) {
|
||||||
remove_configs = [
|
remove_configs = [ "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors" ]
|
||||||
"//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors",
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crashpad_is_win) {
|
if (crashpad_is_win) {
|
||||||
libs = [ "ws2_32.lib" ]
|
libs = [ "ws2_32.lib" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_boringssl_for_http_transport_socket) {
|
||||||
|
data_deps = [ ":generate_test_server_key" ]
|
||||||
|
defines = [ "CRASHPAD_USE_BORINGSSL" ]
|
||||||
|
libs = [
|
||||||
|
"crypto",
|
||||||
|
"ssl",
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,6 +639,10 @@ source_set("util_test") {
|
|||||||
data_deps = [
|
data_deps = [
|
||||||
":http_transport_test_server",
|
":http_transport_test_server",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (use_boringssl_for_http_transport_socket) {
|
||||||
|
defines = [ "CRASHPAD_USE_BORINGSSL" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crashpad_is_mac) {
|
if (crashpad_is_mac) {
|
||||||
|
26
util/net/generate_test_server_key.py
Executable file
26
util/net/generate_test_server_key.py
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright 2018 The Crashpad Authors. All rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# GN requires a Python script for actions, so this just wraps the openssl
|
||||||
|
# command needed to generate a test private key and a certificate. These names
|
||||||
|
# must correspond to what TestPaths::BuildArtifact() constructs.
|
||||||
|
key = 'crashpad_util_test_key.pem'
|
||||||
|
cert = 'crashpad_util_test_cert.pem'
|
||||||
|
subprocess.check_call(
|
||||||
|
['openssl', 'req', '-x509', '-nodes', '-subj', '/CN=localhost',
|
||||||
|
'-days', '365', '-newkey', 'rsa:2048', '-keyout', key, '-out', cert])
|
@ -52,4 +52,8 @@ void HTTPTransport::SetTimeout(double timeout) {
|
|||||||
timeout_ = timeout;
|
timeout_ = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPTransport::SetRootCACertificatePath(const base::FilePath& cert) {
|
||||||
|
root_ca_certificate_path_ = cert;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/files/file_path.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "util/net/http_headers.h"
|
#include "util/net/http_headers.h"
|
||||||
|
|
||||||
@ -71,6 +72,16 @@ class HTTPTransport {
|
|||||||
//! \param[in] timeout The request timeout, in seconds.
|
//! \param[in] timeout The request timeout, in seconds.
|
||||||
void SetTimeout(double timeout);
|
void SetTimeout(double timeout);
|
||||||
|
|
||||||
|
//! \brief Sets a certificate file to be used in lieu of the system CA cert
|
||||||
|
//! bundle.
|
||||||
|
//!
|
||||||
|
//! This is exposed primarily for testing with a self-signed certificate, and
|
||||||
|
//! it isn't necessary to set it in normal use.
|
||||||
|
//!
|
||||||
|
//! \param[in] cert The filename of a file in PEM format containing the CA
|
||||||
|
//! cert to be used for TLS connections.
|
||||||
|
void SetRootCACertificatePath(const base::FilePath& cert);
|
||||||
|
|
||||||
//! \brief Performs the HTTP request with the configured parameters and waits
|
//! \brief Performs the HTTP request with the configured parameters and waits
|
||||||
//! for the execution to complete.
|
//! for the execution to complete.
|
||||||
//!
|
//!
|
||||||
@ -90,10 +101,14 @@ class HTTPTransport {
|
|||||||
const HTTPHeaders& headers() const { return headers_; }
|
const HTTPHeaders& headers() const { return headers_; }
|
||||||
HTTPBodyStream* body_stream() const { return body_stream_.get(); }
|
HTTPBodyStream* body_stream() const { return body_stream_.get(); }
|
||||||
double timeout() const { return timeout_; }
|
double timeout() const { return timeout_; }
|
||||||
|
const base::FilePath& root_ca_certificate_path() const {
|
||||||
|
return root_ca_certificate_path_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string url_;
|
std::string url_;
|
||||||
std::string method_;
|
std::string method_;
|
||||||
|
base::FilePath root_ca_certificate_path_;
|
||||||
HTTPHeaders headers_;
|
HTTPHeaders headers_;
|
||||||
std::unique_ptr<HTTPBodyStream> body_stream_;
|
std::unique_ptr<HTTPBodyStream> body_stream_;
|
||||||
double timeout_;
|
double timeout_;
|
||||||
|
@ -32,6 +32,10 @@
|
|||||||
#include "util/stdlib/string_number_conversion.h"
|
#include "util/stdlib/string_number_conversion.h"
|
||||||
#include "util/string/split_string.h"
|
#include "util/string/split_string.h"
|
||||||
|
|
||||||
|
#if defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -56,6 +60,160 @@ struct ScopedAddrinfoTraits {
|
|||||||
using ScopedAddrinfo =
|
using ScopedAddrinfo =
|
||||||
base::ScopedGeneric<addrinfo*, ScopedAddrinfoTraits>;
|
base::ScopedGeneric<addrinfo*, ScopedAddrinfoTraits>;
|
||||||
|
|
||||||
|
class Stream {
|
||||||
|
public:
|
||||||
|
virtual ~Stream() = default;
|
||||||
|
|
||||||
|
virtual bool LoggingWrite(const void* data, size_t size) = 0;
|
||||||
|
virtual bool LoggingRead(void* data, size_t size) = 0;
|
||||||
|
virtual bool LoggingReadToEOF(std::string* contents) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FdStream : public Stream {
|
||||||
|
public:
|
||||||
|
explicit FdStream(int fd) : fd_(fd) { CHECK(fd_ >= 0); }
|
||||||
|
|
||||||
|
bool LoggingWrite(const void* data, size_t size) override {
|
||||||
|
return LoggingWriteFile(fd_, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingRead(void* data, size_t size) override {
|
||||||
|
return LoggingReadFileExactly(fd_, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingReadToEOF(std::string* result) override{
|
||||||
|
return crashpad::LoggingReadToEOF(fd_, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fd_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FdStream);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
class SSLStream : public Stream {
|
||||||
|
public:
|
||||||
|
SSLStream() = default;
|
||||||
|
|
||||||
|
bool Initialize(const base::FilePath& root_cert_path,
|
||||||
|
int sock,
|
||||||
|
const std::string& hostname) {
|
||||||
|
SSL_library_init();
|
||||||
|
|
||||||
|
ctx_.reset(SSL_CTX_new(TLS_method()));
|
||||||
|
if (!ctx_.is_valid()) {
|
||||||
|
LOG(ERROR) << "SSL_CTX_new";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_CTX_set_min_proto_version(ctx_.get(), TLS1_2_VERSION) <= 0) {
|
||||||
|
LOG(ERROR) << "SSL_CTX_set_min_proto_version";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_CTX_set_verify(ctx_.get(), SSL_VERIFY_PEER, nullptr);
|
||||||
|
SSL_CTX_set_verify_depth(ctx_.get(), 5);
|
||||||
|
|
||||||
|
if (!root_cert_path.empty()) {
|
||||||
|
if (SSL_CTX_load_verify_locations(
|
||||||
|
ctx_.get(), root_cert_path.value().c_str(), nullptr) <= 0) {
|
||||||
|
LOG(ERROR) << "SSL_CTX_load_verify_locations";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if defined(OS_LINUX)
|
||||||
|
if (SSL_CTX_load_verify_locations(
|
||||||
|
ctx_.get(), nullptr, "/etc/ssl/certs") <= 0) {
|
||||||
|
LOG(ERROR) << "SSL_CTX_load_verify_locations";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#elif defined(OS_FUCHSIA)
|
||||||
|
if (SSL_CTX_load_verify_locations(
|
||||||
|
ctx_.get(), "/config/ssl/cert.pem", nullptr) <= 0) {
|
||||||
|
LOG(ERROR) << "SSL_CTX_load_verify_locations";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error cert store location
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_.reset(SSL_new(ctx_.get()));
|
||||||
|
if (!ssl_.is_valid()) {
|
||||||
|
LOG(ERROR) << "SSL_new";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIO* bio = BIO_new_socket(sock, BIO_NOCLOSE);
|
||||||
|
if (!bio) {
|
||||||
|
LOG(ERROR) << "BIO_new_socket";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSL_set_bio() takes ownership of |bio|.
|
||||||
|
SSL_set_bio(ssl_.get(), bio, bio);
|
||||||
|
|
||||||
|
if (SSL_set_tlsext_host_name(ssl_.get(), hostname.c_str()) == 0) {
|
||||||
|
LOG(ERROR) << "SSL_set_tlsext_host_name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_connect(ssl_.get()) <= 0) {
|
||||||
|
LOG(ERROR) << "SSL_connect";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingWrite(const void* data, size_t size) override {
|
||||||
|
return SSL_write(ssl_.get(), data, size) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingRead(void* data, size_t size) override {
|
||||||
|
return SSL_read(ssl_.get(), data, size) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingReadToEOF(std::string* contents) override {
|
||||||
|
contents->clear();
|
||||||
|
char buffer[4096];
|
||||||
|
FileOperationResult rv;
|
||||||
|
while ((rv = SSL_read(ssl_.get(), buffer, sizeof(buffer))) > 0) {
|
||||||
|
DCHECK_LE(static_cast<size_t>(rv), sizeof(buffer));
|
||||||
|
contents->append(buffer, rv);
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
LOG(ERROR) << "SSL_read";
|
||||||
|
contents->clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ScopedSSLCTXTraits {
|
||||||
|
static SSL_CTX* InvalidValue() { return nullptr; }
|
||||||
|
static void Free(SSL_CTX* ctx) { SSL_CTX_free(ctx); }
|
||||||
|
};
|
||||||
|
using ScopedSSLCTX = base::ScopedGeneric<SSL_CTX*, ScopedSSLCTXTraits>;
|
||||||
|
|
||||||
|
struct ScopedSSLTraits {
|
||||||
|
static SSL* InvalidValue() { return nullptr; }
|
||||||
|
static void Free(SSL* ssl) {
|
||||||
|
SSL_shutdown(ssl);
|
||||||
|
SSL_free(ssl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using ScopedSSL = base::ScopedGeneric<SSL*, ScopedSSLTraits>;
|
||||||
|
|
||||||
|
ScopedSSLCTX ctx_;
|
||||||
|
ScopedSSL ssl_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(SSLStream);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
bool WaitUntilSocketIsReady(int sock) {
|
bool WaitUntilSocketIsReady(int sock) {
|
||||||
pollfd pollfds;
|
pollfd pollfds;
|
||||||
pollfds.fd = sock;
|
pollfds.fd = sock;
|
||||||
@ -167,14 +325,14 @@ base::ScopedFD CreateSocket(const std::string& hostname,
|
|||||||
return base::ScopedFD();
|
return base::ScopedFD();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteRequest(int sock,
|
bool WriteRequest(Stream* stream,
|
||||||
const std::string& method,
|
const std::string& method,
|
||||||
const std::string& resource,
|
const std::string& resource,
|
||||||
const HTTPHeaders& headers,
|
const HTTPHeaders& headers,
|
||||||
HTTPBodyStream* body_stream) {
|
HTTPBodyStream* body_stream) {
|
||||||
std::string request_line = base::StringPrintf(
|
std::string request_line = base::StringPrintf(
|
||||||
"%s %s HTTP/1.0\r\n", method.c_str(), resource.c_str());
|
"%s %s HTTP/1.0\r\n", method.c_str(), resource.c_str());
|
||||||
if (!LoggingWriteFile(sock, request_line.data(), request_line.size()))
|
if (!stream->LoggingWrite(request_line.data(), request_line.size()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Write headers, and determine if Content-Length has been specified.
|
// Write headers, and determine if Content-Length has been specified.
|
||||||
@ -188,7 +346,7 @@ bool WriteRequest(int sock,
|
|||||||
DCHECK(!chunked);
|
DCHECK(!chunked);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoggingWriteFile(sock, header_str.data(), header_str.size()))
|
if (!stream->LoggingWrite(header_str.data(), header_str.size()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,13 +354,13 @@ bool WriteRequest(int sock,
|
|||||||
if (chunked) {
|
if (chunked) {
|
||||||
static constexpr const char kTransferEncodingChunked[] =
|
static constexpr const char kTransferEncodingChunked[] =
|
||||||
"Transfer-Encoding: chunked\r\n";
|
"Transfer-Encoding: chunked\r\n";
|
||||||
if (!LoggingWriteFile(
|
if (!stream->LoggingWrite(kTransferEncodingChunked,
|
||||||
sock, kTransferEncodingChunked, strlen(kTransferEncodingChunked))) {
|
strlen(kTransferEncodingChunked))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoggingWriteFile(sock, kCRLFTerminator, strlen(kCRLFTerminator))) {
|
if (!stream->LoggingWrite(kCRLFTerminator, strlen(kCRLFTerminator))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +425,7 @@ bool WriteRequest(int sock,
|
|||||||
// sent to signal EOF. This will happen when processing the EOF indicated by
|
// sent to signal EOF. This will happen when processing the EOF indicated by
|
||||||
// a 0 return from body_stream()->GetBytesBuffer() above.
|
// a 0 return from body_stream()->GetBytesBuffer() above.
|
||||||
if (write_size != 0) {
|
if (write_size != 0) {
|
||||||
if (!LoggingWriteFile(sock, write_start, write_size))
|
if (!stream->LoggingWrite(write_start, write_size))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} while (data_bytes > 0);
|
} while (data_bytes > 0);
|
||||||
@ -275,11 +433,11 @@ bool WriteRequest(int sock,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadLine(int sock, std::string* line) {
|
bool ReadLine(Stream* stream, std::string* line) {
|
||||||
line->clear();
|
line->clear();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char byte;
|
char byte;
|
||||||
if (!LoggingReadFileExactly(sock, &byte, 1)) {
|
if (!stream->LoggingRead(&byte, 1)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,9 +451,9 @@ bool StartsWith(const std::string& str, const char* with, size_t len) {
|
|||||||
return str.compare(0, len, with) == 0;
|
return str.compare(0, len, with) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadResponseLine(int sock) {
|
bool ReadResponseLine(Stream* stream) {
|
||||||
std::string response_line;
|
std::string response_line;
|
||||||
if (!ReadLine(sock, &response_line)) {
|
if (!ReadLine(stream, &response_line)) {
|
||||||
LOG(ERROR) << "ReadLine";
|
LOG(ERROR) << "ReadLine";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -305,10 +463,10 @@ bool ReadResponseLine(int sock) {
|
|||||||
StartsWith(response_line, kHttp11, strlen(kHttp11));
|
StartsWith(response_line, kHttp11, strlen(kHttp11));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadResponseHeaders(int sock, HTTPHeaders* headers) {
|
bool ReadResponseHeaders(Stream* stream, HTTPHeaders* headers) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::string line;
|
std::string line;
|
||||||
if (!ReadLine(sock, &line)) {
|
if (!ReadLine(stream, &line)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,21 +488,21 @@ bool ReadResponseHeaders(int sock, HTTPHeaders* headers) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadContentChunked(int sock, std::string* body) {
|
bool ReadContentChunked(Stream* stream, std::string* body) {
|
||||||
// TODO(scottmg): https://crashpad.chromium.org/bug/196.
|
// TODO(scottmg): https://crashpad.chromium.org/bug/196.
|
||||||
LOG(ERROR) << "TODO(scottmg): chunked response read";
|
LOG(ERROR) << "TODO(scottmg): chunked response read";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadResponse(int sock, std::string* response_body) {
|
bool ReadResponse(Stream* stream, std::string* response_body) {
|
||||||
response_body->clear();
|
response_body->clear();
|
||||||
|
|
||||||
if (!ReadResponseLine(sock)) {
|
if (!ReadResponseLine(stream)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPHeaders response_headers;
|
HTTPHeaders response_headers;
|
||||||
if (!ReadResponseHeaders(sock, &response_headers)) {
|
if (!ReadResponseHeaders(stream, &response_headers)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +517,7 @@ bool ReadResponse(int sock, std::string* response_body) {
|
|||||||
|
|
||||||
if (len) {
|
if (len) {
|
||||||
response_body->resize(len, 0);
|
response_body->resize(len, 0);
|
||||||
return ReadFileExactly(sock, &(*response_body)[0], len);
|
return stream->LoggingRead(&(*response_body)[0], len);
|
||||||
}
|
}
|
||||||
|
|
||||||
it = response_headers.find("Transfer-Encoding");
|
it = response_headers.find("Transfer-Encoding");
|
||||||
@ -368,8 +526,8 @@ bool ReadResponse(int sock, std::string* response_body) {
|
|||||||
chunked = true;
|
chunked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunked ? ReadContentChunked(sock, response_body)
|
return chunked ? ReadContentChunked(stream, response_body)
|
||||||
: LoggingReadToEOF(sock, response_body);
|
: stream->LoggingReadToEOF(response_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPTransportSocket::ExecuteSynchronously(std::string* response_body) {
|
bool HTTPTransportSocket::ExecuteSynchronously(std::string* response_body) {
|
||||||
@ -378,16 +536,38 @@ bool HTTPTransportSocket::ExecuteSynchronously(std::string* response_body) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
CHECK(scheme == "http");
|
||||||
|
#endif
|
||||||
|
|
||||||
base::ScopedFD sock(CreateSocket(hostname, port));
|
base::ScopedFD sock(CreateSocket(hostname, port));
|
||||||
if (!sock.is_valid()) {
|
if (!sock.is_valid()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteRequest(sock.get(), method(), resource, headers(), body_stream())) {
|
#if defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
std::unique_ptr<Stream> stream;
|
||||||
|
if (scheme == "https") {
|
||||||
|
auto ssl_stream = std::make_unique<SSLStream>();
|
||||||
|
if (!ssl_stream->Initialize(
|
||||||
|
root_ca_certificate_path(), sock.get(), hostname)) {
|
||||||
|
LOG(ERROR) << "SSLStream Initialize";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stream = std::move(ssl_stream);
|
||||||
|
} else {
|
||||||
|
stream = std::make_unique<FdStream>(sock.get());
|
||||||
|
}
|
||||||
|
#else // CRASHPAD_USE_BORINGSSL
|
||||||
|
std::unique_ptr<Stream> stream(std::make_unique<FdStream>(sock.get()));
|
||||||
|
#endif // CRASHPAD_USE_BORINGSSL
|
||||||
|
|
||||||
|
if (!WriteRequest(
|
||||||
|
stream.get(), method(), resource, headers(), body_stream())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReadResponse(sock.get(), response_body)) {
|
if (!ReadResponse(stream.get(), response_body)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +42,23 @@ namespace crashpad {
|
|||||||
namespace test {
|
namespace test {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
std::string ToUTF8IfWin(const base::string16& x) {
|
||||||
|
return base::UTF16ToUTF8(x);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::string ToUTF8IfWin(const std::string& x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class HTTPTransportTestFixture : public MultiprocessExec {
|
class HTTPTransportTestFixture : public MultiprocessExec {
|
||||||
public:
|
public:
|
||||||
using RequestValidator =
|
using RequestValidator =
|
||||||
void(*)(HTTPTransportTestFixture*, const std::string&);
|
void(*)(HTTPTransportTestFixture*, const std::string&);
|
||||||
|
|
||||||
HTTPTransportTestFixture(const HTTPHeaders& headers,
|
HTTPTransportTestFixture(const base::FilePath::StringType& scheme,
|
||||||
|
const HTTPHeaders& headers,
|
||||||
std::unique_ptr<HTTPBodyStream> body_stream,
|
std::unique_ptr<HTTPBodyStream> body_stream,
|
||||||
uint16_t http_response_code,
|
uint16_t http_response_code,
|
||||||
RequestValidator request_validator)
|
RequestValidator request_validator)
|
||||||
@ -55,14 +66,33 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
|||||||
headers_(headers),
|
headers_(headers),
|
||||||
body_stream_(std::move(body_stream)),
|
body_stream_(std::move(body_stream)),
|
||||||
response_code_(http_response_code),
|
response_code_(http_response_code),
|
||||||
request_validator_(request_validator) {
|
request_validator_(request_validator),
|
||||||
|
cert_(),
|
||||||
|
scheme_and_host_() {
|
||||||
base::FilePath server_path = TestPaths::Executable().DirName().Append(
|
base::FilePath server_path = TestPaths::Executable().DirName().Append(
|
||||||
FILE_PATH_LITERAL("http_transport_test_server")
|
FILE_PATH_LITERAL("http_transport_test_server")
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
FILE_PATH_LITERAL(".exe")
|
FILE_PATH_LITERAL(".exe")
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
SetChildCommand(server_path, nullptr);
|
|
||||||
|
if (ToUTF8IfWin(scheme) == "http") {
|
||||||
|
scheme_and_host_ = "http://localhost";
|
||||||
|
SetChildCommand(server_path, nullptr);
|
||||||
|
} else {
|
||||||
|
std::vector<std::string> args;
|
||||||
|
cert_ = TestPaths::BuildArtifact(FILE_PATH_LITERAL("util"),
|
||||||
|
FILE_PATH_LITERAL("cert"),
|
||||||
|
TestPaths::FileType::kCertificate);
|
||||||
|
args.push_back(ToUTF8IfWin(cert_.value()));
|
||||||
|
args.emplace_back(ToUTF8IfWin(
|
||||||
|
TestPaths::BuildArtifact(FILE_PATH_LITERAL("util"),
|
||||||
|
FILE_PATH_LITERAL("key"),
|
||||||
|
TestPaths::FileType::kCertificate)
|
||||||
|
.value()));
|
||||||
|
SetChildCommand(server_path, &args);
|
||||||
|
scheme_and_host_ = "https://localhost";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const HTTPHeaders& headers() { return headers_; }
|
const HTTPHeaders& headers() { return headers_; }
|
||||||
@ -94,7 +124,12 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
|||||||
// Now execute the HTTP request.
|
// Now execute the HTTP request.
|
||||||
std::unique_ptr<HTTPTransport> transport(HTTPTransport::Create());
|
std::unique_ptr<HTTPTransport> transport(HTTPTransport::Create());
|
||||||
transport->SetMethod("POST");
|
transport->SetMethod("POST");
|
||||||
transport->SetURL(base::StringPrintf("http://127.0.0.1:%d/upload", port));
|
|
||||||
|
if (!cert_.empty()) {
|
||||||
|
transport->SetRootCACertificatePath(cert_);
|
||||||
|
}
|
||||||
|
transport->SetURL(
|
||||||
|
base::StringPrintf("%s:%d/upload", scheme_and_host_.c_str(), port));
|
||||||
for (const auto& pair : headers_) {
|
for (const auto& pair : headers_) {
|
||||||
transport->SetHeader(pair.first, pair.second);
|
transport->SetHeader(pair.first, pair.second);
|
||||||
}
|
}
|
||||||
@ -128,6 +163,8 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
|||||||
std::unique_ptr<HTTPBodyStream> body_stream_;
|
std::unique_ptr<HTTPBodyStream> body_stream_;
|
||||||
uint16_t response_code_;
|
uint16_t response_code_;
|
||||||
RequestValidator request_validator_;
|
RequestValidator request_validator_;
|
||||||
|
base::FilePath cert_;
|
||||||
|
std::string scheme_and_host_;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr char kMultipartFormData[] = "multipart/form-data";
|
constexpr char kMultipartFormData[] = "multipart/form-data";
|
||||||
@ -209,7 +246,10 @@ void ValidFormData(HTTPTransportTestFixture* fixture,
|
|||||||
EXPECT_EQ(request.substr(body_start), expected);
|
EXPECT_EQ(request.substr(body_start), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HTTPTransport, ValidFormData) {
|
class HTTPTransport
|
||||||
|
: public testing::TestWithParam<base::FilePath::StringType> {};
|
||||||
|
|
||||||
|
TEST_P(HTTPTransport, ValidFormData) {
|
||||||
HTTPMultipartBuilder builder;
|
HTTPMultipartBuilder builder;
|
||||||
builder.SetFormData("key1", "test");
|
builder.SetFormData("key1", "test");
|
||||||
builder.SetFormData("key2", "--abcdefg123");
|
builder.SetFormData("key2", "--abcdefg123");
|
||||||
@ -217,12 +257,12 @@ TEST(HTTPTransport, ValidFormData) {
|
|||||||
HTTPHeaders headers;
|
HTTPHeaders headers;
|
||||||
builder.PopulateContentHeaders(&headers);
|
builder.PopulateContentHeaders(&headers);
|
||||||
|
|
||||||
HTTPTransportTestFixture test(
|
HTTPTransportTestFixture test(GetParam(),
|
||||||
headers, builder.GetBodyStream(), 200, &ValidFormData);
|
headers, builder.GetBodyStream(), 200, &ValidFormData);
|
||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HTTPTransport, ValidFormData_Gzip) {
|
TEST_P(HTTPTransport, ValidFormData_Gzip) {
|
||||||
HTTPMultipartBuilder builder;
|
HTTPMultipartBuilder builder;
|
||||||
builder.SetGzipEnabled(true);
|
builder.SetGzipEnabled(true);
|
||||||
builder.SetFormData("key1", "test");
|
builder.SetFormData("key1", "test");
|
||||||
@ -231,8 +271,8 @@ TEST(HTTPTransport, ValidFormData_Gzip) {
|
|||||||
HTTPHeaders headers;
|
HTTPHeaders headers;
|
||||||
builder.PopulateContentHeaders(&headers);
|
builder.PopulateContentHeaders(&headers);
|
||||||
|
|
||||||
HTTPTransportTestFixture test(headers, builder.GetBodyStream(), 200,
|
HTTPTransportTestFixture test(
|
||||||
&ValidFormData);
|
GetParam(), headers, builder.GetBodyStream(), 200, &ValidFormData);
|
||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,11 +285,11 @@ void ErrorResponse(HTTPTransportTestFixture* fixture,
|
|||||||
EXPECT_EQ(content_type, kTextPlain);
|
EXPECT_EQ(content_type, kTextPlain);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HTTPTransport, ErrorResponse) {
|
TEST_P(HTTPTransport, ErrorResponse) {
|
||||||
HTTPMultipartBuilder builder;
|
HTTPMultipartBuilder builder;
|
||||||
HTTPHeaders headers;
|
HTTPHeaders headers;
|
||||||
headers[kContentType] = kTextPlain;
|
headers[kContentType] = kTextPlain;
|
||||||
HTTPTransportTestFixture test(headers, builder.GetBodyStream(),
|
HTTPTransportTestFixture test(GetParam(), headers, builder.GetBodyStream(),
|
||||||
404, &ErrorResponse);
|
404, &ErrorResponse);
|
||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
@ -273,7 +313,7 @@ void UnchunkedPlainText(HTTPTransportTestFixture* fixture,
|
|||||||
EXPECT_EQ(request.substr(body_start + 2), kTextBody);
|
EXPECT_EQ(request.substr(body_start + 2), kTextBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HTTPTransport, UnchunkedPlainText) {
|
TEST_P(HTTPTransport, UnchunkedPlainText) {
|
||||||
std::unique_ptr<HTTPBodyStream> body_stream(
|
std::unique_ptr<HTTPBodyStream> body_stream(
|
||||||
new StringHTTPBodyStream(kTextBody));
|
new StringHTTPBodyStream(kTextBody));
|
||||||
|
|
||||||
@ -281,12 +321,13 @@ TEST(HTTPTransport, UnchunkedPlainText) {
|
|||||||
headers[kContentType] = kTextPlain;
|
headers[kContentType] = kTextPlain;
|
||||||
headers[kContentLength] = base::StringPrintf("%" PRIuS, strlen(kTextBody));
|
headers[kContentLength] = base::StringPrintf("%" PRIuS, strlen(kTextBody));
|
||||||
|
|
||||||
HTTPTransportTestFixture test(
|
HTTPTransportTestFixture test(GetParam(),
|
||||||
headers, std::move(body_stream), 200, &UnchunkedPlainText);
|
headers, std::move(body_stream), 200, &UnchunkedPlainText);
|
||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunUpload33k(bool has_content_length) {
|
void RunUpload33k(const base::FilePath::StringType& scheme,
|
||||||
|
bool has_content_length) {
|
||||||
// On macOS, NSMutableURLRequest winds up calling into a CFReadStream’s Read()
|
// On macOS, NSMutableURLRequest winds up calling into a CFReadStream’s Read()
|
||||||
// callback with a 32kB buffer. Make sure that it’s able to get everything
|
// callback with a 32kB buffer. Make sure that it’s able to get everything
|
||||||
// when enough is available to fill this buffer, requiring more than one
|
// when enough is available to fill this buffer, requiring more than one
|
||||||
@ -303,6 +344,7 @@ void RunUpload33k(bool has_content_length) {
|
|||||||
base::StringPrintf("%" PRIuS, request_string.size());
|
base::StringPrintf("%" PRIuS, request_string.size());
|
||||||
}
|
}
|
||||||
HTTPTransportTestFixture test(
|
HTTPTransportTestFixture test(
|
||||||
|
scheme,
|
||||||
headers,
|
headers,
|
||||||
std::move(body_stream),
|
std::move(body_stream),
|
||||||
200,
|
200,
|
||||||
@ -313,15 +355,31 @@ void RunUpload33k(bool has_content_length) {
|
|||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HTTPTransport, Upload33k) {
|
TEST_P(HTTPTransport, Upload33k) {
|
||||||
RunUpload33k(true);
|
RunUpload33k(GetParam(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(HTTPTransport, Upload33k_LengthUnknown) {
|
TEST_P(HTTPTransport, Upload33k_LengthUnknown) {
|
||||||
// The same as Upload33k, but without declaring Content-Length ahead of time.
|
// The same as Upload33k, but without declaring Content-Length ahead of time.
|
||||||
RunUpload33k(false);
|
RunUpload33k(GetParam(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
// The test server requires BoringSSL or OpenSSL, so https in tests can only be
|
||||||
|
// enabled where that's readily available. Additionally on Linux, the bots fail
|
||||||
|
// lacking libcrypto.so.1.1, so disabled there for now. On Mac, they could also
|
||||||
|
// likely be enabled relatively easily, if HTTPTransportMac learned to respect
|
||||||
|
// the user-supplied cert.
|
||||||
|
INSTANTIATE_TEST_CASE_P(HTTPTransport,
|
||||||
|
HTTPTransport,
|
||||||
|
testing::Values(FILE_PATH_LITERAL("http"),
|
||||||
|
FILE_PATH_LITERAL("https")));
|
||||||
|
#else
|
||||||
|
INSTANTIATE_TEST_CASE_P(HTTPTransport,
|
||||||
|
HTTPTransport,
|
||||||
|
testing::Values(FILE_PATH_LITERAL("http")));
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -34,6 +34,10 @@
|
|||||||
#pragma warning(disable: 4244 4245 4267 4702)
|
#pragma warning(disable: 4244 4245 4267 4702)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CPPHTTPLIB_ZLIB_SUPPORT
|
#define CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
#include "third_party/cpp-httplib/cpp-httplib/httplib.h"
|
#include "third_party/cpp-httplib/cpp-httplib/httplib.h"
|
||||||
|
|
||||||
@ -45,9 +49,20 @@ namespace crashpad {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
int HttpTransportTestServerMain(int argc, char* argv[]) {
|
int HttpTransportTestServerMain(int argc, char* argv[]) {
|
||||||
httplib::Server svr(httplib::HttpVersion::v1_0);
|
std::unique_ptr<httplib::Server> server;
|
||||||
|
if (argc == 1) {
|
||||||
|
server.reset(new httplib::Server);
|
||||||
|
#if defined(CRASHPAD_USE_BORINGSSL)
|
||||||
|
} else if (argc == 3) {
|
||||||
|
server.reset(new httplib::SSLServer(argv[1], argv[2]));
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "usage: http_transport_test_server [cert.pem key.pem]";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!svr.is_valid()) {
|
|
||||||
|
if (!server->is_valid()) {
|
||||||
LOG(ERROR) << "server creation failed";
|
LOG(ERROR) << "server creation failed";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -57,30 +72,30 @@ int HttpTransportTestServerMain(int argc, char* argv[]) {
|
|||||||
|
|
||||||
std::string to_stdout;
|
std::string to_stdout;
|
||||||
|
|
||||||
svr.Post("/upload",
|
server->Post("/upload",
|
||||||
[&response, &response_code, &svr, &to_stdout](
|
[&response, &response_code, &server, &to_stdout](
|
||||||
const httplib::Request& req, httplib::Response& res) {
|
const httplib::Request& req, httplib::Response& res) {
|
||||||
res.status = response_code;
|
res.status = response_code;
|
||||||
if (response_code == 200) {
|
if (response_code == 200) {
|
||||||
res.set_content(std::string(response, 16) + "\r\n",
|
res.set_content(std::string(response, 16) + "\r\n",
|
||||||
"text/plain");
|
"text/plain");
|
||||||
} else {
|
} else {
|
||||||
res.set_content("error", "text/plain");
|
res.set_content("error", "text/plain");
|
||||||
}
|
}
|
||||||
|
|
||||||
to_stdout += "POST /upload HTTP/1.0\r\n";
|
to_stdout += "POST /upload HTTP/1.0\r\n";
|
||||||
for (const auto& h : req.headers) {
|
for (const auto& h : req.headers) {
|
||||||
to_stdout += base::StringPrintf(
|
to_stdout += base::StringPrintf(
|
||||||
"%s: %s\r\n", h.first.c_str(), h.second.c_str());
|
"%s: %s\r\n", h.first.c_str(), h.second.c_str());
|
||||||
}
|
}
|
||||||
to_stdout += "\r\n";
|
to_stdout += "\r\n";
|
||||||
to_stdout += req.body;
|
to_stdout += req.body;
|
||||||
|
|
||||||
svr.stop();
|
server->stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
uint16_t port =
|
uint16_t port =
|
||||||
base::checked_cast<uint16_t>(svr.bind_to_any_port("127.0.0.1"));
|
base::checked_cast<uint16_t>(server->bind_to_any_port("localhost"));
|
||||||
|
|
||||||
CheckedWriteFile(
|
CheckedWriteFile(
|
||||||
StdioFileHandle(StdioStream::kStandardOutput), &port, sizeof(port));
|
StdioFileHandle(StdioStream::kStandardOutput), &port, sizeof(port));
|
||||||
@ -93,7 +108,7 @@ int HttpTransportTestServerMain(int argc, char* argv[]) {
|
|||||||
&response,
|
&response,
|
||||||
sizeof(response));
|
sizeof(response));
|
||||||
|
|
||||||
svr.listen_after_bind();
|
server->listen_after_bind();
|
||||||
|
|
||||||
LoggingWriteFile(StdioFileHandle(StdioStream::kStandardOutput),
|
LoggingWriteFile(StdioFileHandle(StdioStream::kStandardOutput),
|
||||||
to_stdout.data(),
|
to_stdout.data(),
|
||||||
@ -102,8 +117,8 @@ int HttpTransportTestServerMain(int argc, char* argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
|
||||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user