| 323 | } |
| 324 | |
| 325 | int handle_request(Request &req, Response &resp, std::string_view prefix) override { |
| 326 | if (req.verb() == Verb::CONNECT) { |
| 327 | auto pos = req.target().find(":"); |
| 328 | estring_view host, port; |
| 329 | if (pos != std::string_view::npos) { |
| 330 | host = req.target().substr(0, pos); |
| 331 | port = req.target().substr(pos + 1); |
| 332 | } else { |
| 333 | host = req.target(); |
| 334 | port = "443"; |
| 335 | } |
| 336 | |
| 337 | auto server_stream = m_client->native_connect(host, port.to_uint64()); |
| 338 | if (server_stream == nullptr) { |
| 339 | resp.set_result(502); |
| 340 | LOG_ERRNO_RETURN(0, 0, "failed to connect to host `", req.target()); |
| 341 | } |
| 342 | DEFER(delete server_stream); |
| 343 | |
| 344 | auto client_stream = req.get_socket_stream(); |
| 345 | resp.set_result(200, "Connection Established"); |
| 346 | resp.send(); |
| 347 | bool stopped = false; |
| 348 | |
| 349 | auto th = photon::thread_enable_join(photon::thread_create11([&, other=photon::CURRENT]{ |
| 350 | tunnel_copy(server_stream, client_stream); |
| 351 | if (!stopped) |
| 352 | photon::thread_interrupt(other, ECANCELED); |
| 353 | })); |
| 354 | |
| 355 | tunnel_copy(client_stream, server_stream); |
| 356 | stopped = true; |
| 357 | |
| 358 | photon::thread_interrupt((thread*)th, ECANCELED); |
| 359 | photon::thread_join(th); |
| 360 | LOG_DEBUG("tunnel exit"); |
| 361 | return 0; |
| 362 | } |
| 363 | |
| 364 | return ProxyHandler::handle_request(req, resp, prefix); |
| 365 | } |
| 366 | |
| 367 | static int default_forward_proxy_director(void*, Request &src, Request &dst) { |
| 368 | LOG_DEBUG("request target = `", src.target()); |
nothing calls this directly
no test coverage detected