out.append(&*last, p - last);
}
-namespace detail {
-// Map from character code to escape mode:
-// 0 = pass through
-// 1 = unused
-// 2 = pass through in PATH mode
-// 3 = space, replace with '+' in QUERY mode
-// 4 = percent-encode
-extern const unsigned char uriEscapeTable[];
-} // namespace detail
-
-template <class String>
-void uriEscape(StringPiece str, String& out, UriEscapeMode mode) {
- static const char hexValues[] = "0123456789abcdef";
- char esc[3];
- esc[0] = '%';
- // Preallocate assuming that 25% of the input string will be escaped
- out.reserve(out.size() + str.size() + 3 * (str.size() / 4));
- auto p = str.begin();
- auto last = p; // last regular character
- // We advance over runs of passthrough characters and copy them in one go;
- // this is faster than calling push_back repeatedly.
- unsigned char minEncode = static_cast<unsigned char>(mode);
- while (p != str.end()) {
- char c = *p;
- unsigned char v = static_cast<unsigned char>(c);
- unsigned char discriminator = detail::uriEscapeTable[v];
- if (LIKELY(discriminator <= minEncode)) {
- ++p;
- } else if (mode == UriEscapeMode::QUERY && discriminator == 3) {
- out.append(&*last, p - last);
- out.push_back('+');
- ++p;
- last = p;
- } else {
- out.append(&*last, p - last);
- esc[1] = hexValues[v >> 4];
- esc[2] = hexValues[v & 0x0f];
- out.append(esc, 3);
- ++p;
- last = p;
- }
- }
- out.append(&*last, p - last);
-}
-
-template <class String>
-void uriUnescape(StringPiece str, String& out, UriEscapeMode mode) {
- out.reserve(out.size() + str.size());
- auto p = str.begin();
- auto last = p;
- // We advance over runs of passthrough characters and copy them in one go;
- // this is faster than calling push_back repeatedly.
- while (p != str.end()) {
- char c = *p;
- unsigned char v = static_cast<unsigned char>(v);
- switch (c) {
- case '%':
- {
- if (UNLIKELY(std::distance(p, str.end()) < 3)) {
- throw std::invalid_argument("incomplete percent encode sequence");
- }
- auto h1 = detail::hexTable[static_cast<unsigned char>(p[1])];
- auto h2 = detail::hexTable[static_cast<unsigned char>(p[2])];
- if (UNLIKELY(h1 == 16 || h2 == 16)) {
- throw std::invalid_argument("invalid percent encode sequence");
- }
- out.append(&*last, p - last);
- out.push_back((h1 << 4) | h2);
- p += 3;
- last = p;
- break;
- }
- case '+':
- if (mode == UriEscapeMode::QUERY) {
- out.append(&*last, p - last);
- out.push_back(' ');
- ++p;
- last = p;
- break;
- }
- // else fallthrough
- default:
- ++p;
- break;
- }
- }
- out.append(&*last, p - last);
-}
-
namespace detail {
/*
return out;
}
-/**
- * URI-escape a string. Appends the result to the output string.
- *
- * Alphanumeric characters and other characters marked as "unreserved" in RFC
- * 3986 ( -_.~ ) are left unchanged. In PATH mode, the forward slash (/) is
- * also left unchanged. In QUERY mode, spaces are replaced by '+'. All other
- * characters are percent-encoded.
- */
-enum class UriEscapeMode : unsigned char {
- // The values are meaningful, see generate_escape_tables.py
- ALL = 0,
- QUERY = 1,
- PATH = 2
-};
-template <class String>
-void uriEscape(StringPiece str,
- String& out,
- UriEscapeMode mode = UriEscapeMode::ALL);
-
-/**
- * Similar to uriEscape above, but returns the escaped string.
- */
-template <class String>
-String uriEscape(StringPiece str, UriEscapeMode mode = UriEscapeMode::ALL) {
- String out;
- uriEscape(str, out, mode);
- return out;
-}
-
-/**
- * URI-unescape a string. Appends the result to the output string.
- *
- * In QUERY mode, '+' are replaced by space. %XX sequences are decoded if
- * XX is a valid hex sequence, otherwise we throw invalid_argument.
- */
-template <class String>
-void uriUnescape(StringPiece str,
- String& out,
- UriEscapeMode mode = UriEscapeMode::ALL);
-
-/**
- * Similar to uriUnescape above, but returns the unescaped string.
- */
-template <class String>
-String uriUnescape(StringPiece str, UriEscapeMode mode = UriEscapeMode::ALL) {
- String out;
- uriUnescape(str, out, mode);
- return out;
-}
-
/**
* stringPrintf is much like printf but deposits its result into a
* string. Two signatures are supported: the first simply returns the
+++ /dev/null
-/*
- * Copyright 2013 Facebook, Inc.
- *
- * 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.
- */
-
-#ifndef FOLLY_URI_H_
-#error This file may only be included from folly/Uri.h
-#endif
-
-#include "folly/Conv.h"
-
-namespace folly {
-
-template <class String>
-String Uri::toString() const {
- String str;
- toAppend(scheme_, "://", &str);
- if (!password_.empty()) {
- toAppend(username_, ":", password_, "@", &str);
- } else if (!username_.empty()) {
- toAppend(username_, "@", &str);
- }
- toAppend(host_, &str);
- if (port_ != 0) {
- toAppend(":", port_, &str);
- }
- toAppend(path_, &str);
- if (!query_.empty()) {
- toAppend("?", query_, &str);
- }
- if (!fragment_.empty()) {
- toAppend("#", fragment_, &str);
- }
- return str;
-}
-
-} // namespace folly
-
+++ /dev/null
-/*
- * Copyright 2013 Facebook, Inc.
- *
- * 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.
- */
-
-#include "folly/Uri.h"
-
-#include <ctype.h>
-#include <boost/regex.hpp>
-
-namespace folly {
-
-namespace {
-
-fbstring submatch(const boost::cmatch& m, size_t idx) {
- auto& sub = m[idx];
- return fbstring(sub.first, sub.second);
-}
-
-template <class String>
-void toLower(String& s) {
- for (auto& c : s) {
- c = tolower(c);
- }
-}
-
-} // namespace
-
-Uri::Uri(StringPiece str) : port_(0) {
- static const boost::regex uriRegex(
- "([a-zA-Z][a-zA-Z0-9+.-]*):" // scheme:
- "([^?#]*)" // authority and path
- "(?:\\?([^#]*))?" // ?query
- "(?:#(.*))?"); // #fragment
- static const boost::regex authorityAndPathRegex("//([^/]*)(/.*)?");
-
- boost::cmatch match;
- if (UNLIKELY(!boost::regex_match(str.begin(), str.end(), match, uriRegex))) {
- throw std::invalid_argument("invalid URI");
- }
-
- scheme_ = submatch(match, 1);
- toLower(scheme_);
-
- StringPiece authorityAndPath(match[2].first, match[2].second);
- boost::cmatch authorityAndPathMatch;
- if (!boost::regex_match(authorityAndPath.begin(),
- authorityAndPath.end(),
- authorityAndPathMatch,
- authorityAndPathRegex)) {
- // Does not start with //, doesn't have authority
- path_ = authorityAndPath.fbstr();
- } else {
- static const boost::regex authorityRegex(
- "(?:([^@:]*)(?::([^@]*))?@)?" // username, password
- "(\\[[^\\]]*\\]|[^\\[:]*)" // host (IP-literal, dotted-IPv4, or
- // named host)
- "(?::(\\d*))?"); // port
-
- auto authority = authorityAndPathMatch[1];
- boost::cmatch authorityMatch;
- if (!boost::regex_match(authority.first,
- authority.second,
- authorityMatch,
- authorityRegex)) {
- throw std::invalid_argument("invalid URI authority");
- }
-
- StringPiece port(authorityMatch[4].first, authorityMatch[4].second);
- if (!port.empty()) {
- port_ = to<uint32_t>(port);
- }
-
- username_ = submatch(authorityMatch, 1);
- password_ = submatch(authorityMatch, 2);
- host_ = submatch(authorityMatch, 3);
- path_ = submatch(authorityAndPathMatch, 2);
- }
-
- query_ = submatch(match, 3);
- fragment_ = submatch(match, 4);
-}
-
-} // namespace folly
+++ /dev/null
-/*
- * Copyright 2013 Facebook, Inc.
- *
- * 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.
- */
-
-#ifndef FOLLY_URI_H_
-#define FOLLY_URI_H_
-
-#include "folly/String.h"
-
-namespace folly {
-
-/**
- * Class representing a URI.
- *
- * Consider http://www.facebook.com/foo/bar?key=foo#anchor
- *
- * The URI is broken down into its parts: scheme ("http"), authority
- * (ie. host and port, in most cases: "www.facebook.com"), path
- * ("/foo/bar"), query ("key=foo") and fragment ("anchor"). The scheme is
- * lower-cased.
- *
- * If this Uri represents a URL, note that, to prevent ambiguity, the component
- * parts are NOT percent-decoded; you should do this yourself with
- * uriUnescape() (for the authority and path) and uriUnescape(...,
- * UriEscapeMode::QUERY) (for the query, but probably only after splitting at
- * '&' to identify the individual parameters).
- */
-class Uri {
- public:
- /**
- * Parse a Uri from a string. Throws std::invalid_argument on parse error.
- */
- explicit Uri(StringPiece str);
-
- const fbstring& scheme() const { return scheme_; }
- const fbstring& username() const { return username_; }
- const fbstring& password() const { return password_; }
- const fbstring& host() const { return host_; }
- uint32_t port() const { return port_; }
- const fbstring& path() const { return path_; }
- const fbstring& query() const { return query_; }
- const fbstring& fragment() const { return fragment_; }
-
- template <class String>
- String toString() const;
-
- std::string str() const { return toString<std::string>(); }
- fbstring fbstr() const { return toString<fbstring>(); }
-
- private:
- fbstring scheme_;
- fbstring username_;
- fbstring password_;
- fbstring host_;
- uint32_t port_;
- fbstring path_;
- fbstring query_;
- fbstring fragment_;
-};
-
-} // namespace folly
-
-#include "folly/Uri-inl.h"
-
-#endif /* FOLLY_URI_H_ */
f.write("namespace folly {\n"
"namespace detail {\n"
"\n")
-
f.write("extern const char cEscapeTable[] =\n")
escapes = dict((
('"', '\\"'),
else:
c = 'P' # printable
f.write(c)
- f.write("\";\n\n")
+ f.write("\";\n"
+ "\n")
f.write("extern const char cUnescapeTable[] =\n")
for i in range(0, 256):
f.write("X") # hex
else:
f.write("I") # invalid
- f.write("\";\n\n")
+ f.write("\";\n"
+ "\n"
+ "extern const unsigned char hexTable[] = {")
- f.write("extern const unsigned char hexTable[] = {")
for i in range(0, 256):
if i % 16 == 0:
f.write("\n ")
f.write("{0:2d}, ".format(i - ord('A') + 10))
else:
f.write("16, ")
- f.write("\n};\n\n")
-
- # 0 = passthrough
- # 1 = unused
- # 2 = safe in path (/)
- # 3 = space (replace with '+' in query)
- # 4 = always percent-encode
- f.write("extern const unsigned char uriEscapeTable[] = {")
- passthrough = (
- range(ord('0'), ord('9')) +
- range(ord('A'), ord('Z')) +
- range(ord('a'), ord('z')) +
- map(ord, '-_.~'))
- for i in range(0, 256):
- if i % 16 == 0:
- f.write("\n ")
- if i in passthrough:
- f.write("0, ")
- elif i == ord('/'):
- f.write("2, ")
- elif i == ord(' '):
- f.write("3, ")
- else:
- f.write("4, ")
- f.write("\n};\n\n")
+ f.write("\n};\n"
+ "\n")
f.write("} // namespace detail\n"
"} // namespace folly\n")
std::invalid_argument);
}
-TEST(Escape, uriEscape) {
- EXPECT_EQ("hello%2c%20%2fworld", uriEscape<std::string>("hello, /world"));
- EXPECT_EQ("hello%2c%20/world", uriEscape<std::string>("hello, /world",
- UriEscapeMode::PATH));
- EXPECT_EQ("hello%2c+%2fworld", uriEscape<std::string>("hello, /world",
- UriEscapeMode::QUERY));
-}
-
-TEST(Escape, uriUnescape) {
- EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello, /world"));
- EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c%20%2fworld"));
- EXPECT_EQ("hello,+/world", uriUnescape<std::string>("hello%2c+%2fworld"));
- EXPECT_EQ("hello, /world", uriUnescape<std::string>("hello%2c+%2fworld",
- UriEscapeMode::QUERY));
- EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2f"));
- EXPECT_EQ("hello/", uriUnescape<std::string>("hello%2F"));
- EXPECT_THROW({uriUnescape<std::string>("hello%");},
- std::invalid_argument);
- EXPECT_THROW({uriUnescape<std::string>("hello%2");},
- std::invalid_argument);
- EXPECT_THROW({uriUnescape<std::string>("hello%2g");},
- std::invalid_argument);
-}
-
-namespace {
-void expectPrintable(StringPiece s) {
- for (char c : s) {
- EXPECT_LE(32, c);
- EXPECT_GE(127, c);
- }
-}
-} // namespace
-
-TEST(Escape, uriEscapeAllCombinations) {
- char c[3];
- c[2] = '\0';
- StringPiece in(c, 2);
- fbstring tmp;
- fbstring out;
- for (int i = 0; i < 256; ++i) {
- c[0] = i;
- for (int j = 0; j < 256; ++j) {
- c[1] = j;
- tmp.clear();
- out.clear();
- uriEscape(in, tmp);
- expectPrintable(tmp);
- uriUnescape(tmp, out);
- EXPECT_EQ(in, out);
- }
- }
-}
-
-namespace {
-bool isHex(int v) {
- return ((v >= '0' && v <= '9') ||
- (v >= 'A' && v <= 'F') ||
- (v >= 'a' && v <= 'f'));
-}
-} // namespace
-
-TEST(Escape, uriUnescapePercentDecoding) {
- char c[4] = {'%', '\0', '\0', '\0'};
- StringPiece in(c, 3);
- fbstring out;
- unsigned int expected = 0;
- for (int i = 0; i < 256; ++i) {
- c[1] = i;
- for (int j = 0; j < 256; ++j) {
- c[2] = j;
- if (isHex(i) && isHex(j)) {
- out.clear();
- uriUnescape(in, out);
- EXPECT_EQ(1, out.size());
- EXPECT_EQ(1, sscanf(c + 1, "%x", &expected));
- unsigned char v = out[0];
- EXPECT_EQ(expected, v);
- } else {
- EXPECT_THROW({uriUnescape(in, out);}, std::invalid_argument);
- }
- }
- }
-}
-
namespace {
-fbstring cbmString;
-fbstring cbmEscapedString;
-fbstring cEscapedString;
-fbstring cUnescapedString;
-const size_t kCBmStringLength = 64 << 10;
-const uint32_t kCPrintablePercentage = 90;
-
-fbstring uribmString;
-fbstring uribmEscapedString;
-fbstring uriEscapedString;
-fbstring uriUnescapedString;
-const size_t kURIBmStringLength = 256;
-const uint32_t kURIPassThroughPercentage = 50;
+fbstring bmString;
+fbstring bmEscapedString;
+fbstring escapedString;
+fbstring unescapedString;
+const size_t kBmStringLength = 64 << 10;
+const uint32_t kPrintablePercentage = 90;
void initBenchmark() {
- std::mt19937 rnd;
+ bmString.reserve(kBmStringLength);
- // C escape
+ std::mt19937 rnd;
std::uniform_int_distribution<uint32_t> printable(32, 126);
std::uniform_int_distribution<uint32_t> nonPrintable(0, 160);
std::uniform_int_distribution<uint32_t> percentage(0, 99);
- cbmString.reserve(kCBmStringLength);
- for (size_t i = 0; i < kCBmStringLength; ++i) {
+ for (size_t i = 0; i < kBmStringLength; ++i) {
unsigned char c;
- if (percentage(rnd) < kCPrintablePercentage) {
+ if (percentage(rnd) < kPrintablePercentage) {
c = printable(rnd);
} else {
c = nonPrintable(rnd);
c += (126 - 32) + 1;
}
}
- cbmString.push_back(c);
- }
-
- cbmEscapedString = cEscape<fbstring>(cbmString);
-
- // URI escape
- std::uniform_int_distribution<uint32_t> passthrough('a', 'z');
- std::string encodeChars = " ?!\"',+[]";
- std::uniform_int_distribution<uint32_t> encode(0, encodeChars.size() - 1);
-
- uribmString.reserve(kURIBmStringLength);
- for (size_t i = 0; i < kURIBmStringLength; ++i) {
- unsigned char c;
- if (percentage(rnd) < kURIPassThroughPercentage) {
- c = passthrough(rnd);
- } else {
- c = encodeChars[encode(rnd)];
- }
- uribmString.push_back(c);
+ bmString.push_back(c);
}
- uribmEscapedString = uriEscape<fbstring>(uribmString);
+ bmEscapedString = cEscape<fbstring>(bmString);
}
BENCHMARK(BM_cEscape, iters) {
while (iters--) {
- cEscapedString = cEscape<fbstring>(cbmString);
- doNotOptimizeAway(cEscapedString.size());
+ escapedString = cEscape<fbstring>(bmString);
+ doNotOptimizeAway(escapedString.size());
}
}
BENCHMARK(BM_cUnescape, iters) {
while (iters--) {
- cUnescapedString = cUnescape<fbstring>(cbmEscapedString);
- doNotOptimizeAway(cUnescapedString.size());
- }
-}
-
-BENCHMARK(BM_uriEscape, iters) {
- while (iters--) {
- uriEscapedString = uriEscape<fbstring>(uribmString);
- doNotOptimizeAway(uriEscapedString.size());
- }
-}
-
-BENCHMARK(BM_uriUnescape, iters) {
- while (iters--) {
- uriUnescapedString = uriUnescape<fbstring>(uribmEscapedString);
- doNotOptimizeAway(uriUnescapedString.size());
+ unescapedString = cUnescape<fbstring>(bmEscapedString);
+ doNotOptimizeAway(unescapedString.size());
}
}
+++ /dev/null
-/*
- * Copyright 2013 Facebook, Inc.
- *
- * 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.
- */
-
-#include "folly/Uri.h"
-
-#include <glog/logging.h>
-#include <gtest/gtest.h>
-
-using namespace folly;
-
-namespace {
-
-} // namespace
-
-TEST(Uri, Simple) {
- {
- fbstring s("http://www.facebook.com/hello/world?query#fragment");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("www.facebook.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/hello/world", u.path());
- EXPECT_EQ("query", u.query());
- EXPECT_EQ("fragment", u.fragment());
- EXPECT_EQ(s, u.fbstr()); // canonical
- }
-
- {
- fbstring s("http://www.facebook.com:8080/hello/world?query#fragment");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("www.facebook.com", u.host());
- EXPECT_EQ(8080, u.port());
- EXPECT_EQ("/hello/world", u.path());
- EXPECT_EQ("query", u.query());
- EXPECT_EQ("fragment", u.fragment());
- EXPECT_EQ(s, u.fbstr()); // canonical
- }
-
- {
- fbstring s("http://127.0.0.1:8080/hello/world?query#fragment");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("127.0.0.1", u.host());
- EXPECT_EQ(8080, u.port());
- EXPECT_EQ("/hello/world", u.path());
- EXPECT_EQ("query", u.query());
- EXPECT_EQ("fragment", u.fragment());
- EXPECT_EQ(s, u.fbstr()); // canonical
- }
-
- {
- fbstring s("http://[::1]:8080/hello/world?query#fragment");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("[::1]", u.host());
- EXPECT_EQ(8080, u.port());
- EXPECT_EQ("/hello/world", u.path());
- EXPECT_EQ("query", u.query());
- EXPECT_EQ("fragment", u.fragment());
- EXPECT_EQ(s, u.fbstr()); // canonical
- }
-
- {
- fbstring s("http://user:pass@host.com/");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("user", u.username());
- EXPECT_EQ("pass", u.password());
- EXPECT_EQ("host.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ(s, u.fbstr());
- }
-
- {
- fbstring s("http://user@host.com/");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("user", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("host.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ(s, u.fbstr());
- }
-
- {
- fbstring s("http://user:@host.com/");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("user", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("host.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ("http://user@host.com/", u.fbstr());
- }
-
- {
- fbstring s("http://:pass@host.com/");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("pass", u.password());
- EXPECT_EQ("host.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ(s, u.fbstr());
- }
-
- {
- fbstring s("http://@host.com/");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("host.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ("http://host.com/", u.fbstr());
- }
-
- {
- fbstring s("http://:@host.com/");
- Uri u(s);
- EXPECT_EQ("http", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("host.com", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ("http://host.com/", u.fbstr());
- }
-
- {
- fbstring s("file:///etc/motd");
- Uri u(s);
- EXPECT_EQ("file", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/etc/motd", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ(s, u.fbstr());
- }
-
- {
- fbstring s("file:/etc/motd");
- Uri u(s);
- EXPECT_EQ("file", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/etc/motd", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ("file:///etc/motd", u.fbstr());
- }
-
- {
- fbstring s("file://etc/motd");
- Uri u(s);
- EXPECT_EQ("file", u.scheme());
- EXPECT_EQ("", u.username());
- EXPECT_EQ("", u.password());
- EXPECT_EQ("etc", u.host());
- EXPECT_EQ(0, u.port());
- EXPECT_EQ("/motd", u.path());
- EXPECT_EQ("", u.query());
- EXPECT_EQ("", u.fragment());
- EXPECT_EQ(s, u.fbstr());
- }
-
- EXPECT_THROW({Uri("2http://www.facebook.com/");},
- std::invalid_argument);
-}