Skip to content

Commit 3ad8501

Browse files
authored
Merge pull request #173 from hyperware-ai/hf/hyperapp-get-http-request
hyperapp: allow accessing IncomingHttpRequest
2 parents ce4ee3d + cce3228 commit 3ad8501

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/http/server.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ pub enum HttpServerRequest {
2020
WebSocketOpen {
2121
path: String,
2222
channel_id: u32,
23+
#[serde(default)]
24+
source_socket_addr: Option<String>,
25+
/// IP address from proxy headers (X-Forwarded-For, X-Real-IP, Cf-Connecting-Ip)
26+
#[serde(default)]
27+
forwarded_for: Option<String>,
2328
},
2429
/// Processes can both SEND and RECEIVE this kind of [`crate::Request`]
2530
/// (send as [`HttpServerAction::WebSocketPush`]).
@@ -300,6 +305,8 @@ pub struct HttpServer {
300305
ws_paths: HashMap<String, WsBindingConfig>,
301306
/// A mapping of WebSocket paths to the channels that are open on them.
302307
ws_channels: HashMap<String, HashSet<u32>>,
308+
/// A mapping of WebSocket channel IDs to their client socket addresses.
309+
ws_channel_addrs: HashMap<u32, String>,
303310
/// The timeout given for `http-server:distro:sys` to respond to a configuration request.
304311
pub timeout: u64,
305312
}
@@ -451,6 +458,7 @@ impl HttpServer {
451458
http_paths: HashMap::new(),
452459
ws_paths: HashMap::new(),
453460
ws_channels: HashMap::new(),
461+
ws_channel_addrs: HashMap::new(),
454462
timeout,
455463
}
456464
}
@@ -983,18 +991,35 @@ impl HttpServer {
983991
}
984992

985993
/// Handle a WebSocket open event from the HTTP server.
986-
pub fn handle_websocket_open(&mut self, path: &str, channel_id: u32) {
994+
pub fn handle_websocket_open(
995+
&mut self,
996+
path: &str,
997+
channel_id: u32,
998+
source_socket_addr: Option<String>,
999+
forwarded_for: Option<String>,
1000+
) {
9871001
self.ws_channels
9881002
.entry(path.to_string())
9891003
.or_insert(HashSet::new())
9901004
.insert(channel_id);
1005+
// Store the client IP, preferring forwarded_for (from proxy headers) over socket addr
1006+
let client_ip = forwarded_for.or(source_socket_addr);
1007+
if let Some(ip) = client_ip {
1008+
self.ws_channel_addrs.insert(channel_id, ip);
1009+
}
1010+
}
1011+
1012+
/// Get the socket address for a WebSocket channel.
1013+
pub fn get_ws_channel_addr(&self, channel_id: u32) -> Option<&String> {
1014+
self.ws_channel_addrs.get(&channel_id)
9911015
}
9921016

9931017
/// Handle a WebSocket close event from the HTTP server.
9941018
pub fn handle_websocket_close(&mut self, channel_id: u32) {
9951019
self.ws_channels.iter_mut().for_each(|(_, channels)| {
9961020
channels.remove(&channel_id);
9971021
});
1022+
self.ws_channel_addrs.remove(&channel_id);
9981023
}
9991024

10001025
pub fn parse_request(&self, body: &[u8]) -> Result<HttpServerRequest, HttpServerError> {
@@ -1024,8 +1049,13 @@ impl HttpServer {
10241049
channel_id,
10251050
message_type,
10261051
} => ws_handler(channel_id, message_type, last_blob().unwrap_or_default()),
1027-
HttpServerRequest::WebSocketOpen { path, channel_id } => {
1028-
self.handle_websocket_open(&path, channel_id);
1052+
HttpServerRequest::WebSocketOpen {
1053+
path,
1054+
channel_id,
1055+
source_socket_addr,
1056+
forwarded_for,
1057+
} => {
1058+
self.handle_websocket_open(&path, channel_id, source_socket_addr, forwarded_for);
10291059
}
10301060
HttpServerRequest::WebSocketClose(channel_id) => {
10311061
self.handle_websocket_close(channel_id);

src/hyperapp.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ pub fn get_server() -> Option<&'static mut HttpServer> {
7272
APP_HELPERS.with(|ctx| ctx.borrow().current_server.map(|ptr| unsafe { &mut *ptr }))
7373
}
7474

75+
/// Get the socket address for a WebSocket channel by its ID.
76+
/// Returns None if the channel doesn't exist or has no recorded address.
77+
pub fn get_ws_channel_addr(channel_id: u32) -> Option<String> {
78+
get_server().and_then(|server| server.get_ws_channel_addr(channel_id).cloned())
79+
}
80+
81+
pub fn get_http_request() -> Option<IncomingHttpRequest> {
82+
APP_HELPERS.with(|helpers| {
83+
helpers
84+
.borrow()
85+
.current_http_context
86+
.as_ref()
87+
.map(|ctx| ctx.request.clone())
88+
})
89+
}
90+
7591
pub fn get_http_method() -> Option<String> {
7692
APP_HELPERS.with(|helpers| {
7793
helpers

0 commit comments

Comments
 (0)