std::string user;
std::string password;
std::string host;
+ int port;
std::string path;
};
parts.host = rest;
parts.path = "/";
}
+
+ auto colon_pos = parts.host.find(':');
+
+ if (colon_pos != std::string::npos) {
+ parts.port = std::stoi(parts.host.substr(colon_pos + 1));
+ parts.host = parts.host.substr(0, colon_pos);
+ } else if (parts.scheme == "http") {
+ parts.port = 80;
+ } else if (parts.scheme == "https") {
+ parts.port = 443;
+ } else {
+ throw std::runtime_error("unsupported URL scheme: " + parts.scheme);
+ }
+
return parts;
}
}
#endif
- httplib::Client cli(parts.scheme + "://" + parts.host);
+ httplib::Client cli(parts.scheme + "://" + parts.host + ":" + std::to_string(parts.port));
if (!parts.user.empty()) {
cli.set_basic_auth(parts.user, parts.password);
throw std::runtime_error("unsupported URL scheme in target URL: " + parsed_url.scheme);
}
- SRV_INF("proxying %s request to %s://%s%s\n", method.c_str(), parsed_url.scheme.c_str(), parsed_url.host.c_str(), parsed_url.path.c_str());
+ SRV_INF("proxying %s request to %s://%s:%i%s\n", method.c_str(), parsed_url.scheme.c_str(), parsed_url.host.c_str(), parsed_url.port, parsed_url.path.c_str());
auto proxy = std::make_unique<server_http_proxy>(
method,
+ parsed_url.scheme,
parsed_url.host,
- parsed_url.scheme == "http" ? 80 : 443,
+ parsed_url.port,
parsed_url.path,
req.headers,
req.body,
}
auto proxy = std::make_unique<server_http_proxy>(
method,
+ "http",
CHILD_ADDR,
meta->port,
proxy_path,
server_http_proxy::server_http_proxy(
const std::string & method,
+ const std::string & scheme,
const std::string & host,
int port,
const std::string & path,
auto cli = std::make_shared<httplib::ClientImpl>(host, port);
auto pipe = std::make_shared<pipe_t<msg_t>>();
- if (port == 443) {
+ if (scheme == "https") {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
cli.reset(new httplib::SSLClient(host, port));
#else
std::function<void()> cleanup = nullptr;
public:
server_http_proxy(const std::string & method,
+ const std::string & scheme,
const std::string & host,
int port,
const std::string & path,
--- /dev/null
+import pytest
+from utils import *
+
+server = ServerPreset.tinyllama2()
+
+
+@pytest.fixture(autouse=True)
+def create_server():
+ global server
+ server = ServerPreset.tinyllama2()
+
+
+def test_mcp_no_proxy():
+ global server
+ server.webui_mcp_proxy = False
+ server.start()
+
+ res = server.make_request("GET", "/cors-proxy")
+ assert res.status_code == 404
+
+
+def test_mcp_proxy():
+ global server
+ server.webui_mcp_proxy = True
+ server.start()
+
+ url = f"http://{server.server_host}:{server.server_port}/cors-proxy?url=http://example.com"
+ res = requests.get(url)
+ assert res.status_code == 200
+ assert "Example Domain" in res.text
+
+
+def test_mcp_proxy_custom_port():
+ global server
+ server.webui_mcp_proxy = True
+ server.start()
+
+ # try getting the server's models API via the proxy
+ res = server.make_request("GET", f"/cors-proxy?url=http://{server.server_host}:{server.server_port}/models")
+ assert res.status_code == 200
+ assert "data" in res.body
mmproj_url: str | None = None
media_path: str | None = None
sleep_idle_seconds: int | None = None
+ webui_mcp_proxy: bool = False
# session variables
process: subprocess.Popen | None = None
server_args.extend(["--media-path", self.media_path])
if self.sleep_idle_seconds is not None:
server_args.extend(["--sleep-idle-seconds", self.sleep_idle_seconds])
+ if self.webui_mcp_proxy:
+ server_args.append("--webui-mcp-proxy")
args = [str(arg) for arg in [server_path, *server_args]]
print(f"tests: starting server with: {' '.join(args)}")