blob: 110632705dfed2da5e360142c79af9c88733ad65 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/local_two_phase_testserver.h"
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/hash/sha1.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/common/chrome_paths.h"
#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/test/python_utils.h"
namespace safe_browsing {
namespace {
// Computes the SHA-1 of input string, and returns it as an ASCII-encoded string
// of hex characters.
std::string SHA1HexEncode(const std::string& in) {
std::string raw_sha1 = base::SHA1HashString(in);
return base::ToLowerASCII(base::HexEncode(raw_sha1.c_str(), raw_sha1.size()));
}
const char kStartHeader[] = "x-goog-resumable";
std::unique_ptr<net::test_server::HttpResponse> HandleTwoPhaseRequest(
const net::test_server::HttpRequest& request) {
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
GURL url = request.GetURL();
if (request.method == net::test_server::METHOD_POST) {
const auto start_header = request.headers.find(kStartHeader);
if (start_header == request.headers.end()) {
response->set_code(net::HTTP_BAD_REQUEST);
LOG(WARNING) << "Missing header: " << kStartHeader;
return response;
}
if (start_header->second != "start") {
response->set_code(net::HTTP_BAD_REQUEST);
LOG(WARNING) << "Invalid " << kStartHeader
<< " value: " << start_header->second;
return response;
}
std::string medadata_hash = SHA1HexEncode(request.content);
// Default response code.
int p1code = 201;
std::string p2close = "";
std::string p2code = "200";
for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
// Hang up without sending data, in the case of "p1close".
if (it.GetKey() == "p1close")
return std::make_unique<net::test_server::RawHttpResponse>("", "");
if (it.GetKey() == "p1code") {
CHECK(base::StringToInt(it.GetValue(), &p1code));
}
if (it.GetKey() == "p2close")
p2close = "1";
if (it.GetKey() == "p2code")
p2code = it.GetValue();
}
std::string put_url = base::StringPrintf(
"%sput?/%s,%s,%s,%s", request.base_url.spec().c_str(),
url.path().c_str(), medadata_hash.c_str(), p2close.c_str(),
p2code.c_str());
response->set_code(static_cast<net::HttpStatusCode>(p1code));
response->AddCustomHeader("Location", put_url);
return response;
}
if (request.method == net::test_server::METHOD_PUT) {
if (url.path_piece() != "/put") {
response->set_code(net::HTTP_BAD_REQUEST);
LOG(WARNING) << "Invalid path on 2nd phase: " << url.path();
return response;
}
std::vector<std::string> args =
base::SplitString(url.query_piece().substr(1), ",",
base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
if (args.size() != 4) {
response->set_code(net::HTTP_BAD_REQUEST);
LOG(WARNING) << "Invalid query string 2nd phase: " << url.query();
return response;
}
std::string initial_path = args[0];
std::string metadata_hash = args[1];
std::string p2close = args[2];
int p2code = 200;
CHECK(base::StringToInt(args[3], &p2code));
// Hang up without sending data, in the case of "p2close".
if (!p2close.empty())
return std::make_unique<net::test_server::RawHttpResponse>("", "");
response->set_code(static_cast<net::HttpStatusCode>(p2code));
response->set_content(base::StringPrintf(
"%s\n%s\n%s\n", initial_path.c_str(), metadata_hash.c_str(),
SHA1HexEncode(request.content).c_str()));
return response;
}
response->set_code(net::HTTP_BAD_REQUEST);
LOG(WARNING) << "Unexpected method: " << request.method_string;
return response;
}
} // namespace
LocalTwoPhaseTestServer::LocalTwoPhaseTestServer()
: embedded_test_server_(net::EmbeddedTestServer::TYPE_HTTP) {
embedded_test_server_.RegisterRequestHandler(
base::BindRepeating(&HandleTwoPhaseRequest));
}
LocalTwoPhaseTestServer::~LocalTwoPhaseTestServer() {}
} // namespace safe_browsing