Skip to content

Commit 5938298

Browse files
authored
Add support for http+unix scheme to remap config (#12338)
* Add support for http+uds scheme to remap config * Change the suffix to +unix * Update the error message about supported schemes * Add unit tests * Add autest * Add documentation
1 parent 21bb611 commit 5938298

11 files changed

Lines changed: 265 additions & 30 deletions

File tree

doc/admin-guide/files/remap.config.en.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,35 @@ Examples
323323
regex_map http://x([0-9]+).z.com/ http://real-x$1.z.com/
324324
regex_redirect http://old.(.*).z.com http://new.$1.z.com
325325

326+
.. _map_with_recv_port:
327+
328+
map_with_recv_port
329+
==================
330+
331+
Format::
332+
333+
map_with_recv_port client-URL origin-server-URL
334+
335+
``map_with_recv_port`` supports two special URL schemes, ``http+unix`` and ``https+unix``.
336+
These are useful if you want to have different mapping rules or differnt plugin configuration for requests recevied via Unix Domain Socket.
337+
338+
map_with_recv_port Examples
339+
---------------------------
340+
341+
::
342+
343+
map_with_recv_port http://foo.example.com:8000/ http://x.example.com/
344+
map_with_recv_port http://foo.example.com:8888/ http://y.example.com/
345+
346+
Explanation: Requests received on port 8000 and 8888 are forwarded to different servers.
347+
348+
::
349+
350+
map http://foo.example.com/ http://x.example.com/ @plugin=plugin1.so
351+
map_with_recv_port http+unix://foo.example.com/ http://x.example.com/
352+
353+
Explanation: All requests are forwarded to the same server, but plugin1 does not run for requests received via Unix Domain Socket.
354+
326355
.. _map_with_referer:
327356

328357
map_with_referer

include/proxy/hdrs/URL.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ extern c_str_view URL_SCHEME_FILE;
125125
extern c_str_view URL_SCHEME_FTP;
126126
extern c_str_view URL_SCHEME_GOPHER;
127127
extern c_str_view URL_SCHEME_HTTP;
128+
extern c_str_view URL_SCHEME_HTTP_UDS;
128129
extern c_str_view URL_SCHEME_HTTPS;
130+
extern c_str_view URL_SCHEME_HTTPS_UDS;
129131
extern c_str_view URL_SCHEME_WS;
130132
extern c_str_view URL_SCHEME_WSS;
131133
extern c_str_view URL_SCHEME_MAILTO;
@@ -591,6 +593,9 @@ inline int
591593
URL::port_get() const
592594
{
593595
ink_assert(valid());
596+
if (auto scheme = m_url_impl->get_scheme(); scheme.length() >= 8 && scheme.ends_with("+unix")) {
597+
return 0;
598+
}
594599
return url_canonicalize_port(m_url_impl->get_type(), m_url_impl->get_port());
595600
}
596601

include/proxy/http/remap/UrlMappingPathIndex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class UrlMappingPathIndex
7676
idx = url->scheme_get_wksidx();
7777
// If the scheme is empty (e.g. because of a CONNECT method), guess it
7878
// based on port
79-
if (idx == -1) {
79+
if (idx == -1 && url->scheme_get().empty()) {
8080
if (port == 80) {
8181
idx = URL_WKSIDX_HTTP;
8282
} else {

src/proxy/hdrs/URL.cc

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ c_str_view URL_SCHEME_FILE;
3434
c_str_view URL_SCHEME_FTP;
3535
c_str_view URL_SCHEME_GOPHER;
3636
c_str_view URL_SCHEME_HTTP;
37+
c_str_view URL_SCHEME_HTTP_UDS;
3738
c_str_view URL_SCHEME_HTTPS;
39+
c_str_view URL_SCHEME_HTTPS_UDS;
3840
c_str_view URL_SCHEME_WSS;
3941
c_str_view URL_SCHEME_WS;
4042
c_str_view URL_SCHEME_MAILTO;
@@ -142,32 +144,35 @@ url_init()
142144

143145
hdrtoken_init();
144146

145-
URL_SCHEME_FILE = hdrtoken_string_to_wks_sv("file");
146-
URL_SCHEME_FTP = hdrtoken_string_to_wks_sv("ftp");
147-
URL_SCHEME_GOPHER = hdrtoken_string_to_wks_sv("gopher");
148-
URL_SCHEME_HTTP = hdrtoken_string_to_wks_sv("http");
149-
URL_SCHEME_HTTPS = hdrtoken_string_to_wks_sv("https");
150-
URL_SCHEME_WSS = hdrtoken_string_to_wks_sv("wss");
151-
URL_SCHEME_WS = hdrtoken_string_to_wks_sv("ws");
152-
URL_SCHEME_MAILTO = hdrtoken_string_to_wks_sv("mailto");
153-
URL_SCHEME_NEWS = hdrtoken_string_to_wks_sv("news");
154-
URL_SCHEME_NNTP = hdrtoken_string_to_wks_sv("nntp");
155-
URL_SCHEME_PROSPERO = hdrtoken_string_to_wks_sv("prospero");
156-
URL_SCHEME_TELNET = hdrtoken_string_to_wks_sv("telnet");
157-
URL_SCHEME_TUNNEL = hdrtoken_string_to_wks_sv("tunnel");
158-
URL_SCHEME_WAIS = hdrtoken_string_to_wks_sv("wais");
159-
URL_SCHEME_PNM = hdrtoken_string_to_wks_sv("pnm");
160-
URL_SCHEME_RTSP = hdrtoken_string_to_wks_sv("rtsp");
161-
URL_SCHEME_RTSPU = hdrtoken_string_to_wks_sv("rtspu");
162-
URL_SCHEME_MMS = hdrtoken_string_to_wks_sv("mms");
163-
URL_SCHEME_MMSU = hdrtoken_string_to_wks_sv("mmsu");
164-
URL_SCHEME_MMST = hdrtoken_string_to_wks_sv("mmst");
147+
URL_SCHEME_FILE = hdrtoken_string_to_wks_sv("file");
148+
URL_SCHEME_FTP = hdrtoken_string_to_wks_sv("ftp");
149+
URL_SCHEME_GOPHER = hdrtoken_string_to_wks_sv("gopher");
150+
URL_SCHEME_HTTP = hdrtoken_string_to_wks_sv("http");
151+
URL_SCHEME_HTTP_UDS = c_str_view("http+unix", 9);
152+
URL_SCHEME_HTTPS = hdrtoken_string_to_wks_sv("https");
153+
URL_SCHEME_HTTPS_UDS = c_str_view("https+unix", 10);
154+
URL_SCHEME_WSS = hdrtoken_string_to_wks_sv("wss");
155+
URL_SCHEME_WS = hdrtoken_string_to_wks_sv("ws");
156+
URL_SCHEME_MAILTO = hdrtoken_string_to_wks_sv("mailto");
157+
URL_SCHEME_NEWS = hdrtoken_string_to_wks_sv("news");
158+
URL_SCHEME_NNTP = hdrtoken_string_to_wks_sv("nntp");
159+
URL_SCHEME_PROSPERO = hdrtoken_string_to_wks_sv("prospero");
160+
URL_SCHEME_TELNET = hdrtoken_string_to_wks_sv("telnet");
161+
URL_SCHEME_TUNNEL = hdrtoken_string_to_wks_sv("tunnel");
162+
URL_SCHEME_WAIS = hdrtoken_string_to_wks_sv("wais");
163+
URL_SCHEME_PNM = hdrtoken_string_to_wks_sv("pnm");
164+
URL_SCHEME_RTSP = hdrtoken_string_to_wks_sv("rtsp");
165+
URL_SCHEME_RTSPU = hdrtoken_string_to_wks_sv("rtspu");
166+
URL_SCHEME_MMS = hdrtoken_string_to_wks_sv("mms");
167+
URL_SCHEME_MMSU = hdrtoken_string_to_wks_sv("mmsu");
168+
URL_SCHEME_MMST = hdrtoken_string_to_wks_sv("mmst");
165169

166170
ink_assert(URL_SCHEME_FILE.c_str() && URL_SCHEME_FTP.c_str() && URL_SCHEME_GOPHER.c_str() && URL_SCHEME_HTTP.c_str() &&
167-
URL_SCHEME_HTTPS.c_str() && URL_SCHEME_WS.c_str() && URL_SCHEME_WSS.c_str() && URL_SCHEME_MAILTO.c_str() &&
168-
URL_SCHEME_NEWS.c_str() && URL_SCHEME_NNTP.c_str() && URL_SCHEME_PROSPERO.c_str() && URL_SCHEME_TELNET.c_str() &&
169-
URL_SCHEME_TUNNEL.c_str() && URL_SCHEME_WAIS.c_str() && URL_SCHEME_PNM.c_str() && URL_SCHEME_RTSP.c_str() &&
170-
URL_SCHEME_RTSPU.c_str() && URL_SCHEME_MMS.c_str() && URL_SCHEME_MMSU.c_str() && URL_SCHEME_MMST.c_str());
171+
URL_SCHEME_HTTP_UDS.c_str() && URL_SCHEME_HTTPS.c_str() && URL_SCHEME_HTTPS_UDS.c_str() && URL_SCHEME_WS.c_str() &&
172+
URL_SCHEME_WSS.c_str() && URL_SCHEME_MAILTO.c_str() && URL_SCHEME_NEWS.c_str() && URL_SCHEME_NNTP.c_str() &&
173+
URL_SCHEME_PROSPERO.c_str() && URL_SCHEME_TELNET.c_str() && URL_SCHEME_TUNNEL.c_str() && URL_SCHEME_WAIS.c_str() &&
174+
URL_SCHEME_PNM.c_str() && URL_SCHEME_RTSP.c_str() && URL_SCHEME_RTSPU.c_str() && URL_SCHEME_MMS.c_str() &&
175+
URL_SCHEME_MMSU.c_str() && URL_SCHEME_MMST.c_str());
171176

172177
URL_WKSIDX_FILE = hdrtoken_wks_to_index(URL_SCHEME_FILE.c_str());
173178
URL_WKSIDX_FTP = hdrtoken_wks_to_index(URL_SCHEME_FTP.c_str());
@@ -398,7 +403,15 @@ URLImpl::set_scheme(HdrHeap *heap, std::string_view value, int scheme_wks_idx, b
398403
scheme_wks = nullptr;
399404
}
400405

401-
if (scheme_wks == URL_SCHEME_HTTP.c_str() || scheme_wks == URL_SCHEME_WS.c_str()) {
406+
if (scheme_wks == nullptr) {
407+
if (value == static_cast<std::string_view>(URL_SCHEME_HTTP_UDS)) {
408+
this->m_url_type = URLType::HTTP;
409+
} else if (value == static_cast<std::string_view>(URL_SCHEME_HTTPS_UDS)) {
410+
this->m_url_type = URLType::HTTPS;
411+
} else {
412+
this->m_url_type = URLType::HTTP;
413+
}
414+
} else if (scheme_wks == URL_SCHEME_HTTP.c_str() || scheme_wks == URL_SCHEME_WS.c_str()) {
402415
this->m_url_type = URLType::HTTP;
403416
} else if (scheme_wks == URL_SCHEME_HTTPS.c_str() || scheme_wks == URL_SCHEME_WSS.c_str()) {
404417
this->m_url_type = URLType::HTTPS;

src/proxy/hdrs/unit_tests/test_URL.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ TEST_CASE("Validate Scheme", "[proxy][validscheme]")
6868
{"example.", true },
6969
{"example++", true },
7070
{"example--.", true },
71+
{"http+unix", true },
72+
{"https+unix", true },
7173
{"++example", false},
7274
{"--example", false},
7375
{".example", false},

src/proxy/http/remap/RemapConfig.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,11 +1255,12 @@ remap_parse_config_bti(const char *path, BUILD_TABLE_INFO *bti)
12551255
// includes support for FILE scheme
12561256
if ((fromScheme != std::string_view{URL_SCHEME_HTTP} && fromScheme != std::string_view{URL_SCHEME_HTTPS} &&
12571257
fromScheme != std::string_view{URL_SCHEME_FILE} && fromScheme != std::string_view{URL_SCHEME_TUNNEL} &&
1258-
fromScheme != std::string_view{URL_SCHEME_WS} && fromScheme != std::string_view{URL_SCHEME_WSS}) ||
1258+
fromScheme != std::string_view{URL_SCHEME_WS} && fromScheme != std::string_view{URL_SCHEME_WSS} &&
1259+
fromScheme != std::string_view{URL_SCHEME_HTTP_UDS} && fromScheme != std::string_view{URL_SCHEME_HTTPS_UDS}) ||
12591260
(toScheme != std::string_view{URL_SCHEME_HTTP} && toScheme != std::string_view{URL_SCHEME_HTTPS} &&
12601261
toScheme != std::string_view{URL_SCHEME_TUNNEL} && toScheme != std::string_view{URL_SCHEME_WS} &&
12611262
toScheme != std::string_view{URL_SCHEME_WSS})) {
1262-
errStr = "only http, https, ws, wss, and tunnel remappings are supported";
1263+
errStr = "only http, https, http+unix, https+unix, ws, wss, and tunnel remappings are supported";
12631264
goto MAP_ERROR;
12641265
}
12651266

src/proxy/http/remap/RemapProcessor.cc

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,29 @@ RemapProcessor::setup_for_remap(HttpTransact::State *s, UrlRewrite *table)
8282
if (table->num_rules_forward_with_recv_port) {
8383
Dbg(dbg_ctl_url_rewrite, "[lookup] forward mappings with recv port found; Using recv port %d",
8484
s->client_info.dst_addr.host_order_port());
85-
if (table->forwardMappingWithRecvPortLookup(request_url, s->client_info.dst_addr.host_order_port(), request_host.data(),
86-
static_cast<int>(request_host.length()), s->url_map)) {
85+
86+
bool ret;
87+
if (s->client_info.dst_addr.host_order_port() == 0) {
88+
// Port number 0 means that UDS is used.
89+
// Adjust the scheme so that we can find rules with +unix suffix.
90+
URL adjusted_url;
91+
adjusted_url.create(nullptr);
92+
adjusted_url.copy(request_url);
93+
if (auto scheme = adjusted_url.scheme_get_wksidx(); scheme == URL_WKSIDX_HTTP) {
94+
adjusted_url.scheme_set("http+unix");
95+
} else if (scheme == URL_WKSIDX_HTTPS) {
96+
adjusted_url.scheme_set("https+unix");
97+
}
98+
Dbg(dbg_ctl_url_rewrite, "[lookup] scheme was adjusted to %.*s", static_cast<int>(adjusted_url.scheme_get().size()),
99+
adjusted_url.scheme_get().data());
100+
ret = table->forwardMappingWithRecvPortLookup(&adjusted_url, s->client_info.dst_addr.host_order_port(), request_host.data(),
101+
static_cast<int>(request_host.length()), s->url_map);
102+
adjusted_url.destroy();
103+
} else {
104+
ret = table->forwardMappingWithRecvPortLookup(request_url, s->client_info.dst_addr.host_order_port(), request_host.data(),
105+
static_cast<int>(request_host.length()), s->url_map);
106+
}
107+
if (ret) {
87108
Dbg(dbg_ctl_url_rewrite, "Found forward mapping with recv port");
88109
mapping_found = true;
89110
} else if (table->num_rules_forward == 0) {

src/proxy/http/remap/unit-tests/test_RemapRules.cc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,60 @@ map https://h1.example.com \
168168
REQUIRE(urlmap.getMapping()->filter->src_ip_array[0].match_all_addresses);
169169
}
170170
}
171+
GIVEN("map_with_recv_port keyword with a special URL scheme for Unix Domain Socket")
172+
{
173+
std::unique_ptr<UrlRewrite> urlrw = std::make_unique<UrlRewrite>();
174+
175+
std::string config = R"RMCFG(
176+
map_with_recv_port http+unix://front.example.com \
177+
http://origin.example.com
178+
)RMCFG";
179+
180+
auto cpath = write_test_remap(config, "unix-scheme");
181+
printf("wrote config to path: %s\n", cpath.c_str());
182+
int rc = urlrw->BuildTable(cpath.c_str());
183+
EasyURL url("http+unix://front.example.com");
184+
const char *host = "front.example.com";
185+
186+
THEN("only requests via unix domain socket matches")
187+
{
188+
// Checck if the rule is loaded
189+
REQUIRE(rc == TS_SUCCESS);
190+
REQUIRE(urlrw->rule_count() == 1);
191+
UrlMappingContainer urlmap;
192+
193+
// The rule must not match if a port number is available (the request is made on IP interface)
194+
REQUIRE(urlrw->forwardMappingWithRecvPortLookup(&url.url, 80, host, strlen(host), urlmap) == false);
195+
// The rule must match if a port number is unavailable (the request is made on Unix Domain Socket)
196+
REQUIRE(urlrw->forwardMappingWithRecvPortLookup(&url.url, 0, host, strlen(host), urlmap) == true);
197+
}
198+
}
199+
GIVEN("map_with_recv_port keyword with a regular URL scheme")
200+
{
201+
std::unique_ptr<UrlRewrite> urlrw = std::make_unique<UrlRewrite>();
202+
203+
std::string config = R"RMCFG(
204+
map_with_recv_port http://front.example.com \
205+
http://origin.example.com
206+
)RMCFG";
207+
208+
auto cpath = write_test_remap(config, "regular-scheme");
209+
printf("wrote config to path: %s\n", cpath.c_str());
210+
int rc = urlrw->BuildTable(cpath.c_str());
211+
EasyURL url("http://front.example.com");
212+
const char *host = "front.example.com";
213+
214+
THEN("only request via IP interface matches")
215+
{
216+
// Checck if the rule is loaded
217+
REQUIRE(rc == TS_SUCCESS);
218+
REQUIRE(urlrw->rule_count() == 1);
219+
UrlMappingContainer urlmap;
220+
221+
// The rule must match if a port number is available (the request is made on IP interface)
222+
REQUIRE(urlrw->forwardMappingWithRecvPortLookup(&url.url, 80, host, strlen(host), urlmap) == true);
223+
// The rule must not match if a port number is unavailable (the request is made on Unix Domain Socket)
224+
REQUIRE(urlrw->forwardMappingWithRecvPortLookup(&url.url, 0, host, strlen(host), urlmap) == false);
225+
}
226+
}
171227
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
``
2+
> GET /``
3+
> Host: test.example.com``
4+
> User-Agent: curl/``
5+
> Accept: */*
6+
``
7+
< HTTP/1.1 200 OK
8+
< Content-Length: 2
9+
< Date: ``
10+
< Age: ``
11+
< Server: ATS/``
12+
<
13+
``
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
``
2+
> GET /``
3+
> Host: test.example.com``
4+
> User-Agent: curl/``
5+
> Accept: */*
6+
``
7+
< HTTP/1.1 200 OK
8+
< Content-Length: 4
9+
< Date: ``
10+
< Age: ``
11+
< Server: ATS/``
12+
<
13+
``

0 commit comments

Comments
 (0)