Add limited version of URL cracking

This is a very basic form of URL cracking to break a
HTTPTransport::SetURL() argument up into component parts. This is split
out of the (upcoming)
https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1008407
for Linux and Fuchsia.

Bug: crashpad:196
Change-Id: Iba075d9c8720c14550ce53e23d684362da84740c
Reviewed-on: https://chromium-review.googlesource.com/1010972
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Scott Graham 2018-04-12 14:42:20 -07:00 committed by Commit Bot
parent c2583364a3
commit eca0ea8427
3 changed files with 152 additions and 0 deletions

View File

@ -16,6 +16,7 @@
#include <string.h>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
namespace crashpad {
@ -41,4 +42,51 @@ std::string URLEncode(const std::string& url) {
return encoded;
}
bool CrackURL(const std::string& url,
std::string* scheme,
std::string* host,
std::string* port,
std::string* rest) {
std::string result_scheme;
std::string result_port;
size_t host_start;
static constexpr const char kHttp[] = "http://";
static constexpr const char kHttps[] = "https://";
if (url.compare(0, strlen(kHttp), kHttp) == 0) {
result_scheme = "http";
result_port = "80";
host_start = strlen(kHttp);
} else if (url.compare(0, strlen(kHttps), kHttps) == 0) {
result_scheme = "https";
result_port = "443";
host_start = strlen(kHttps);
} else {
LOG(ERROR) << "expecting http or https";
return false;
}
// Find the start of the resource.
size_t resource_start = url.find('/', host_start);
if (resource_start == std::string::npos) {
LOG(ERROR) << "no resource component";
return false;
}
scheme->swap(result_scheme);
port->swap(result_port);
std::string host_and_possible_port =
url.substr(host_start, resource_start - host_start);
size_t colon = host_and_possible_port.find(':');
if (colon == std::string::npos) {
*host = host_and_possible_port;
} else {
*host = host_and_possible_port.substr(0, colon);
*port = host_and_possible_port.substr(colon + 1);
}
*rest = url.substr(resource_start);
return true;
}
} // namespace crashpad

View File

@ -26,6 +26,25 @@ namespace crashpad {
//! \return The encoded string.
std::string URLEncode(const std::string& url);
//! \brief Crack a URL into component parts.
//!
//! This is not a general function, and works only on the limited style of URLs
//! that are expected to be used by HTTPTransport::SetURL().
//!
//! \param[in] url The URL to crack.
//! \param[out] scheme The request scheme, either http or https.
//! \param[out] host The hostname.
//! \param[out] port The port.
//! \param[out] rest The remainder of the URL (both resource and URL params).
//! \return `true` on success in which case all output parameters will be filled
//! out, or `false` on failure, in which case the output parameters will be
//! unmodified and an error will be logged.
bool CrackURL(const std::string& url,
std::string* scheme,
std::string* host,
std::string* port,
std::string* rest);
} // namespace crashpad
#endif // CRASHPAD_UTIL_NET_URL_H_

View File

@ -42,6 +42,91 @@ TEST(URLEncode, SimpleAddress) {
"3Dvalue");
}
TEST(CrackURL, Unsupported) {
std::string scheme, host, port, rest;
// Not HTTP.
EXPECT_FALSE(CrackURL("file://stuff/things", &scheme, &host, &port, &rest));
// No resource.
EXPECT_FALSE(CrackURL("file://stuff", &scheme, &host, &port, &rest));
EXPECT_FALSE(CrackURL("http://stuff", &scheme, &host, &port, &rest));
EXPECT_FALSE(CrackURL("https://stuff", &scheme, &host, &port, &rest));
}
TEST(CrackURL, UnsupportedDoesNotModifiedOutArgs) {
std::string scheme, host, port, rest;
scheme = "scheme";
host = "host";
port = "port";
rest = "rest";
// Bad scheme.
EXPECT_FALSE(CrackURL("file://stuff/things", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "scheme");
EXPECT_EQ(host, "host");
EXPECT_EQ(port, "port");
EXPECT_EQ(rest, "rest");
scheme = "scheme";
host = "host";
port = "port";
rest = "rest";
// No resource.
EXPECT_FALSE(CrackURL("http://stuff", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "scheme");
EXPECT_EQ(host, "host");
EXPECT_EQ(port, "port");
EXPECT_EQ(rest, "rest");
}
TEST(CrackURL, BasicWithDefaultPort) {
std::string scheme, host, port, rest;
ASSERT_TRUE(CrackURL("http://stuff/things", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "http");
EXPECT_EQ(host, "stuff");
EXPECT_EQ(port, "80");
EXPECT_EQ(rest, "/things");
ASSERT_TRUE(CrackURL("https://stuff/things", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "https");
EXPECT_EQ(host, "stuff");
EXPECT_EQ(port, "443");
EXPECT_EQ(rest, "/things");
}
TEST(CrackURL, BasicWithExplicitPort) {
std::string scheme, host, port, rest;
ASSERT_TRUE(
CrackURL("http://stuff:999/things", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "http");
EXPECT_EQ(host, "stuff");
EXPECT_EQ(port, "999");
EXPECT_EQ(rest, "/things");
ASSERT_TRUE(
CrackURL("https://stuff:1010/things", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "https");
EXPECT_EQ(host, "stuff");
EXPECT_EQ(port, "1010");
EXPECT_EQ(rest, "/things");
}
TEST(CrackURL, WithURLParams) {
std::string scheme, host, port, rest;
ASSERT_TRUE(CrackURL(
"http://stuff:999/things?blah=stuff:3", &scheme, &host, &port, &rest));
EXPECT_EQ(scheme, "http");
EXPECT_EQ(host, "stuff");
EXPECT_EQ(port, "999");
EXPECT_EQ(rest, "/things?blah=stuff:3");
}
} // namespace
} // namespace test
} // namespace crashpad