mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Rewrite url parsing without use of regex.
PiperOrigin-RevId: 750731428
This commit is contained in:
committed by
Copybara-Service
parent
ce58d19c1a
commit
4c0f9c913d
+51
-32
@@ -14,12 +14,15 @@
|
||||
|
||||
#include "internal/network/url.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <regex> //NOLINT
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/numbers.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/network/utils.h"
|
||||
@@ -36,10 +39,6 @@ absl::StatusOr<Url> Url::Create(absl::string_view url_string) {
|
||||
return url;
|
||||
}
|
||||
|
||||
bool Url::SetUrlPath(absl::string_view url_path) {
|
||||
return ApplyUrlString(url_path);
|
||||
}
|
||||
|
||||
std::string Url::GetUrlPath() const {
|
||||
return scheme_ + "://" + host_ + GetPortString() + path_ + GetQueryString() +
|
||||
GetFragmentString();
|
||||
@@ -55,47 +54,66 @@ uint16_t Url::GetPort() const { return port_; }
|
||||
|
||||
absl::string_view Url::GetFragment() const { return fragment_; }
|
||||
|
||||
bool Url::ApplyUrlString(absl::string_view url_string) {
|
||||
bool Url::SetUrlPath(absl::string_view url_string) {
|
||||
// Refer to: https://www.rfc-editor.org/rfc/rfc3986#page-50
|
||||
std::regex url_reg(
|
||||
R"(^(([^:\/?#]+):)?(//([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)",
|
||||
std::regex::extended);
|
||||
|
||||
std::smatch matches;
|
||||
std::string url{url_string};
|
||||
|
||||
std::regex_search(url, matches, url_reg);
|
||||
scheme_ = matches[2];
|
||||
if (!(scheme_ == "http" || scheme_ == "https")) {
|
||||
if (url_string.starts_with("http://")) {
|
||||
url_string = url_string.substr(7);
|
||||
scheme_ = "http";
|
||||
} else if (url_string.starts_with("https://")) {
|
||||
url_string = url_string.substr(8);
|
||||
scheme_ = "https";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string authority = matches[4];
|
||||
absl::string_view authority;
|
||||
size_t path_start = url_string.find_first_of("?/#");
|
||||
if (path_start != std::string::npos) {
|
||||
authority = url_string.substr(0, path_start);
|
||||
url_string = url_string.substr(path_start);
|
||||
} else {
|
||||
authority = url_string;
|
||||
url_string = "";
|
||||
}
|
||||
if (authority.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t pos = authority.find(':');
|
||||
if (pos != std::string::npos) {
|
||||
host_ = authority.substr(0, pos);
|
||||
port_ = std::stoi(authority.substr(pos + 1));
|
||||
size_t port_start = authority.find(':');
|
||||
if (port_start != std::string::npos) {
|
||||
host_ = authority.substr(0, port_start);
|
||||
int port;
|
||||
if (absl::SimpleAtoi(authority.substr(port_start + 1), &port)) {
|
||||
port_ = port;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
host_ = authority;
|
||||
port_ = scheme_ == "http" ? 80 : 443;
|
||||
}
|
||||
path_ = matches[5];
|
||||
if (path_ == "/") {
|
||||
path_ = "";
|
||||
if (url_string.empty()) {
|
||||
return true;
|
||||
}
|
||||
size_t query_start = url_string.find_first_of('?');
|
||||
if (query_start != std::string::npos) {
|
||||
path_ = url_string.substr(0, query_start);
|
||||
url_string = url_string.substr(query_start + 1);
|
||||
} else {
|
||||
path_ = url_string;
|
||||
}
|
||||
absl::string_view query;
|
||||
size_t fragment_start = url_string.find_first_of('#');
|
||||
if (fragment_start != std::string::npos) {
|
||||
query = url_string.substr(0, fragment_start);
|
||||
fragment_ = url_string.substr(fragment_start + 1);
|
||||
} else {
|
||||
query = url_string;
|
||||
}
|
||||
|
||||
query_parameters_.clear();
|
||||
std::string query = matches[7];
|
||||
if (!query.empty()) {
|
||||
// split by &
|
||||
size_t start = 0;
|
||||
size_t end = 0;
|
||||
while ((end = query.find('&', start)) != std::string::npos) {
|
||||
std::string kv = query.substr(start, end - start);
|
||||
absl::string_view kv = query.substr(start, end - start);
|
||||
start = end + 1;
|
||||
size_t eq_pos = kv.find('=');
|
||||
if (eq_pos <= 0 || eq_pos == std::string::npos) {
|
||||
@@ -114,8 +132,9 @@ bool Url::ApplyUrlString(absl::string_view url_string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment_ = matches[9];
|
||||
if (path_ == "/") {
|
||||
path_ = "";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_INTERNAL_NETWORK_URL_H_
|
||||
#define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_URL_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
@@ -41,7 +42,7 @@ class Url {
|
||||
|
||||
static absl::StatusOr<Url> Create(absl::string_view url_string);
|
||||
|
||||
bool SetUrlPath(absl::string_view url_path);
|
||||
bool SetUrlPath(absl::string_view url_string);
|
||||
std::string GetUrlPath() const;
|
||||
|
||||
absl::string_view GetScheme() const;
|
||||
@@ -56,7 +57,6 @@ class Url {
|
||||
const QueryParameters& GetAllQueryStrings() const;
|
||||
|
||||
private:
|
||||
bool ApplyUrlString(absl::string_view url_string);
|
||||
std::string GetQueryString() const;
|
||||
std::string GetPortString() const;
|
||||
std::string GetFragmentString() const;
|
||||
|
||||
@@ -114,6 +114,10 @@ TEST(Url, TestInvalidUrl) {
|
||||
ASSERT_FALSE(url.ok());
|
||||
url = Url::Create("::::hjskoiskjk");
|
||||
ASSERT_FALSE(url.ok());
|
||||
url = Url::Create("http://www.google.com:abcd/erwe");
|
||||
ASSERT_FALSE(url.ok());
|
||||
url = Url::Create("http:///www.google.com");
|
||||
ASSERT_FALSE(url.ok());
|
||||
}
|
||||
|
||||
TEST(Url, TestStreamOutput) {
|
||||
|
||||
Reference in New Issue
Block a user