|
1 | 1 | use std::collections::HashMap;
|
2 | 2 | use std::net::SocketAddr;
|
| 3 | +use std::time::Duration; |
3 | 4 |
|
4 | 5 | use litep2p::protocol::request_response::DialOptions;
|
5 | 6 | use litep2p::protocol::request_response::RequestResponseEvent;
|
6 | 7 | use litep2p::types::RequestId;
|
7 | 8 | use litep2p::PeerId;
|
8 | 9 | use multiaddr::Multiaddr;
|
9 | 10 | use multiaddr::Protocol;
|
| 11 | +use tokio::io::AsyncReadExt; |
| 12 | +use tokio::io::AsyncWriteExt; |
| 13 | +use tokio::net::TcpStream; |
10 | 14 | use tokio::sync::mpsc;
|
11 | 15 | use tokio::sync::oneshot;
|
| 16 | +use tokio::time::timeout; |
12 | 17 | use tracing::warn;
|
13 | 18 |
|
14 | 19 | use crate::command::proto::AddPeerRequest;
|
@@ -49,21 +54,23 @@ pub struct PProxy {
|
49 | 54 | command_rx: mpsc::Receiver<(PProxyCommand, CommandNotifier)>,
|
50 | 55 | tunnel_notifier: HashMap<RequestId, CommandNotifier>,
|
51 | 56 | p2p_server: P2pServer,
|
| 57 | + proxy_addr: Option<SocketAddr>, |
52 | 58 | }
|
53 | 59 |
|
54 | 60 | pub struct PProxyHandle {
|
55 | 61 | command_tx: mpsc::Sender<(PProxyCommand, CommandNotifier)>,
|
56 | 62 | }
|
57 | 63 |
|
58 | 64 | impl PProxy {
|
59 |
| - pub fn new(server_addr: SocketAddr) -> (Self, PProxyHandle) { |
| 65 | + pub fn new(server_addr: SocketAddr, proxy_addr: Option<SocketAddr>) -> (Self, PProxyHandle) { |
60 | 66 | let (command_tx, command_rx) = mpsc::channel(DEFAULT_CHANNEL_SIZE);
|
61 | 67 |
|
62 | 68 | (
|
63 | 69 | Self {
|
64 | 70 | command_rx,
|
65 | 71 | tunnel_notifier: HashMap::new(),
|
66 | 72 | p2p_server: P2pServer::new(server_addr),
|
| 73 | + proxy_addr, |
67 | 74 | },
|
68 | 75 | PProxyHandle { command_tx },
|
69 | 76 | )
|
@@ -97,11 +104,42 @@ impl PProxy {
|
97 | 104 | match event {
|
98 | 105 | P2pServerEvent::TunnelEvent(RequestResponseEvent::RequestReceived {
|
99 | 106 | request_id,
|
| 107 | + request, |
100 | 108 | ..
|
101 |
| - }) => self |
102 |
| - .p2p_server |
103 |
| - .tunnel_handle |
104 |
| - .send_response(*request_id, vec![1, 2, 3, 4]), |
| 109 | + }) => { |
| 110 | + let Some(proxy_addr) = self.proxy_addr else { |
| 111 | + return Err(Error::ProtocolNotSupport); |
| 112 | + }; |
| 113 | + |
| 114 | + let mut headers = [httparse::EMPTY_HEADER; 64]; |
| 115 | + let mut req = httparse::Request::new(&mut headers); |
| 116 | + if req.parse(request)?.is_partial() { |
| 117 | + return Err(Error::IncompleteHttpRequest); |
| 118 | + } |
| 119 | + |
| 120 | + let mut stream = tcp_connect_with_timeout(&proxy_addr, 5).await?; |
| 121 | + stream.write_all(request).await?; |
| 122 | + |
| 123 | + let mut response = Vec::new(); |
| 124 | + loop { |
| 125 | + let mut buf = [0u8; 30000]; |
| 126 | + match stream.read(&mut buf).await { |
| 127 | + Err(_) => break, |
| 128 | + Ok(0) => break, |
| 129 | + Ok(n) => { |
| 130 | + response.extend_from_slice(&buf[..n]); |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + if response.is_empty() { |
| 136 | + response = b"HTTP/1.1 500 Internal Server Error\r\n\r\n".to_vec(); |
| 137 | + } |
| 138 | + |
| 139 | + self.p2p_server |
| 140 | + .tunnel_handle |
| 141 | + .send_response(*request_id, response); |
| 142 | + } |
105 | 143 |
|
106 | 144 | P2pServerEvent::TunnelEvent(RequestResponseEvent::RequestFailed {
|
107 | 145 | request_id,
|
@@ -212,6 +250,12 @@ impl PProxyHandle {
|
212 | 250 | &self,
|
213 | 251 | request: RequestHttpServerRequest,
|
214 | 252 | ) -> Result<RequestHttpServerResponse> {
|
| 253 | + let mut headers = [httparse::EMPTY_HEADER; 64]; |
| 254 | + let mut req = httparse::Request::new(&mut headers); |
| 255 | + if req.parse(&request.data)?.is_partial() { |
| 256 | + return Err(Error::IncompleteHttpRequest); |
| 257 | + } |
| 258 | + |
215 | 259 | let (tx, rx) = oneshot::channel();
|
216 | 260 |
|
217 | 261 | self.command_tx
|
@@ -239,3 +283,20 @@ fn extract_peer_id_from_multiaddr(multiaddr: &Multiaddr) -> Result<PeerId> {
|
239 | 283 | PeerId::from_multihash(multihash)
|
240 | 284 | .map_err(|_| Error::FailedToExtractPeerIdFromMultiaddr(multiaddr.to_string()))
|
241 | 285 | }
|
| 286 | + |
| 287 | +pub async fn tcp_connect_with_timeout( |
| 288 | + addr: &SocketAddr, |
| 289 | + request_timeout_s: u64, |
| 290 | +) -> Result<TcpStream> { |
| 291 | + match timeout( |
| 292 | + Duration::from_secs(request_timeout_s), |
| 293 | + TcpStream::connect(addr), |
| 294 | + ) |
| 295 | + .await |
| 296 | + { |
| 297 | + Ok(result) => result.map_err(Error::Io), |
| 298 | + Err(_) => Err(Error::Io(std::io::Error::from( |
| 299 | + std::io::ErrorKind::TimedOut, |
| 300 | + ))), |
| 301 | + } |
| 302 | +} |
0 commit comments