83 {
84 std::shared_ptr<web::http::client::tools::EventSource> eventSource;
85
86
87 static const std::regex re(R"(^(?:un://)([^/?#]+)(/[^?#]*)?(\?[^#]*)?(?:#.*)?$)", std::regex::ECMAScript | std::regex::icase);
88
89 auto pct_decode = [](std::string_view s) -> std::string {
90 std::string out;
91 out.reserve(s.size());
92 for (size_t i = 0; i < s.size(); ++i) {
93 if (s[i] == '%' && i + 2 < s.size()) {
94 auto hex = [](char c) -> int {
95 if (c >= '0' && c <= '9') {
96 return c - '0';
97 }
98 c |= 0x20;
99 if (c >= 'a' && c <= 'f') {
100 return 10 + (c - 'a');
101 }
102 return -1;
103 };
104 const int h = hex(s[i + 1]);
105 const int l = hex(s[i + 2]);
106 if (h >= 0 && l >= 0) {
107 out.push_back(static_cast<char>((h << 4) | l));
108 i += 2;
109 continue;
110 }
111 }
112 out.push_back(s[i]);
113 }
114 return out;
115 };
116
118 if (std::regex_match(url, match, re)) {
119
120
121
122
123
124
125 const std::string sockToken =
match[1].str();
126 std::string socketPath = pct_decode(sockToken);
127
128 if ((!socketPath.empty() && (socketPath.front() == '/' || socketPath.front() == '@'))) {
129 const std::string scheme = "un";
130 const std::string httpPath =
match[2].matched ?
match[2].str() :
"/";
131 const std::string query =
match[3].matched ?
match[3].str() :
"";
132
134 } else {
135 LOG(ERROR) << "UNIX socket must decode to absolute ('/..') or abstract ('@name'): " << sockToken;
136 }
137 } else {
138 LOG(ERROR) << "EventSource unix-domain url not accepted: " << url;
139 }
140
141 return eventSource;
142 }
bool match(const char *first, const char *second)
std::shared_ptr< web::http::client::tools::EventSource > EventSource(const std::string &scheme, const net::in::SocketAddress &socketAddress, const std::string &path)