Skip to content

Commit 3358cf5

Browse files
committed
Add support for passing socket info through to SERVER superglobal
1 parent 76343cc commit 3358cf5

File tree

9 files changed

+221
-50
lines changed

9 files changed

+221
-50
lines changed

crates/lang_handler/src/ffi.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{
2-
ffi,
3-
ffi::{c_char, CStr, CString},
2+
ffi::{self, c_char, CStr, CString},
3+
net::SocketAddr,
44
};
55

66
use bytes::{Buf, BufMut};
@@ -216,6 +216,20 @@ impl From<&lh_request_t> for Request {
216216
}
217217
}
218218

219+
fn c_char_to_socket_addr(value: *const ffi::c_char) -> Option<SocketAddr> {
220+
if value.is_null() {
221+
return None
222+
}
223+
224+
// Convert to &str
225+
let value = match unsafe { CStr::from_ptr(value) }.to_str() {
226+
Err(_) => return None,
227+
Ok(s) => s,
228+
};
229+
230+
value.parse::<SocketAddr>().ok()
231+
}
232+
219233
/// Create a new `lh_request_t`.
220234
///
221235
/// # Examples
@@ -229,6 +243,8 @@ pub extern "C" fn lh_request_new(
229243
url: *const ffi::c_char,
230244
headers: *mut lh_headers_t,
231245
body: *const ffi::c_char,
246+
local_socket: *const ffi::c_char,
247+
remote_socket: *const ffi::c_char,
232248
) -> *mut lh_request_t {
233249
let method = unsafe { CStr::from_ptr(method).to_string_lossy().into_owned() };
234250
let url_str = unsafe { CStr::from_ptr(url).to_string_lossy().into_owned() };
@@ -238,8 +254,10 @@ pub extern "C" fn lh_request_new(
238254
} else {
239255
Some(unsafe { CStr::from_ptr(body).to_bytes() })
240256
};
257+
let local_socket = c_char_to_socket_addr(local_socket);
258+
let remote_socket = c_char_to_socket_addr(remote_socket);
241259
let headers = unsafe { &*headers };
242-
let request = Request::new(method, url, headers.into(), body.unwrap_or(&[]));
260+
let request = Request::new(method, url, headers.into(), body.unwrap_or(&[]), local_socket, remote_socket);
243261
Box::into_raw(Box::new(request.into()))
244262
}
245263

crates/lang_handler/src/request.rs

Lines changed: 125 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fmt::Debug;
1+
use std::{fmt::Debug, net::{AddrParseError, SocketAddr}};
22

33
use bytes::{Bytes, BytesMut};
44
use url::{ParseError, Url};
@@ -37,6 +37,8 @@ pub struct Request {
3737
headers: Headers,
3838
// TODO: Support Stream bodies when napi.rs supports it
3939
body: Bytes,
40+
local_socket: Option<SocketAddr>,
41+
remote_socket: Option<SocketAddr>,
4042
}
4143

4244
unsafe impl Sync for Request {}
@@ -57,14 +59,18 @@ impl Request {
5759
/// "POST".to_string(),
5860
/// "http://example.com/test.php".parse().unwrap(),
5961
/// headers,
60-
/// "Hello, World!"
62+
/// "Hello, World!",
63+
/// None,
64+
/// None,
6165
/// );
62-
pub fn new<T: Into<Bytes>>(method: String, url: Url, headers: Headers, body: T) -> Self {
66+
pub fn new<T: Into<Bytes>>(method: String, url: Url, headers: Headers, body: T, local_socket: Option<SocketAddr>, remote_socket: Option<SocketAddr>) -> Self {
6367
Self {
6468
method,
6569
url,
6670
headers,
6771
body: body.into(),
72+
local_socket,
73+
remote_socket,
6874
}
6975
}
7076

@@ -133,7 +139,9 @@ impl Request {
133139
/// "POST".to_string(),
134140
/// "http://example.com/test.php".parse().unwrap(),
135141
/// Headers::new(),
136-
/// "Hello, World!"
142+
/// "Hello, World!",
143+
/// None,
144+
/// None,
137145
/// );
138146
///
139147
/// assert_eq!(request.method(), "POST");
@@ -153,7 +161,9 @@ impl Request {
153161
/// "POST".to_string(),
154162
/// "http://example.com/test.php".parse().unwrap(),
155163
/// Headers::new(),
156-
/// "Hello, World!"
164+
/// "Hello, World!",
165+
/// None,
166+
/// None,
157167
/// );
158168
///
159169
/// assert_eq!(request.url().as_str(), "http://example.com/test.php");
@@ -176,7 +186,9 @@ impl Request {
176186
/// "POST".to_string(),
177187
/// "http://example.com/test.php".parse().unwrap(),
178188
/// headers,
179-
/// "Hello, World!"
189+
/// "Hello, World!",
190+
/// None,
191+
/// None,
180192
/// );
181193
///
182194
/// assert_eq!(request.headers().get("Accept"), Some(&vec!["text/html".to_string()]));
@@ -196,14 +208,60 @@ impl Request {
196208
/// "POST".to_string(),
197209
/// "http://example.com/test.php".parse().unwrap(),
198210
/// Headers::new(),
199-
/// "Hello, World!"
211+
/// "Hello, World!",
212+
/// None,
213+
/// None,
200214
/// );
201215
///
202216
/// assert_eq!(request.body(), "Hello, World!");
203217
/// ```
204218
pub fn body(&self) -> Bytes {
205219
self.body.clone()
206220
}
221+
222+
/// Returns the local socket address of the request.
223+
///
224+
/// # Examples
225+
///
226+
/// ```
227+
/// use lang_handler::{Request, Headers};
228+
///
229+
/// let request = Request::new(
230+
/// "POST".to_string(),
231+
/// "http://example.com/test.php".parse().unwrap(),
232+
/// Headers::new(),
233+
/// "Hello, World!",
234+
/// None,
235+
/// None,
236+
/// );
237+
///
238+
/// assert_eq!(request.local_socket(), None);
239+
/// ```
240+
pub fn local_socket(&self) -> Option<SocketAddr> {
241+
self.local_socket
242+
}
243+
244+
/// Returns the remote socket address of the request.
245+
///
246+
/// # Examples
247+
///
248+
/// ```
249+
/// use lang_handler::{Request, Headers};
250+
///
251+
/// let request = Request::new(
252+
/// "POST".to_string(),
253+
/// "http://example.com/test.php".parse().unwrap(),
254+
/// Headers::new(),
255+
/// "Hello, World!",
256+
/// None,
257+
/// None,
258+
/// );
259+
///
260+
/// assert_eq!(request.remote_socket(), None);
261+
/// ```
262+
pub fn remote_socket(&self) -> Option<SocketAddr> {
263+
self.remote_socket
264+
}
207265
}
208266

209267
/// Builds an HTTP request.
@@ -233,6 +291,8 @@ pub struct RequestBuilder {
233291
url: Option<Url>,
234292
headers: Headers,
235293
body: BytesMut,
294+
local_socket: Option<SocketAddr>,
295+
remote_socket: Option<SocketAddr>,
236296
}
237297

238298
impl RequestBuilder {
@@ -251,6 +311,8 @@ impl RequestBuilder {
251311
url: None,
252312
headers: Headers::new(),
253313
body: BytesMut::with_capacity(1024),
314+
local_socket: None,
315+
remote_socket: None,
254316
}
255317
}
256318

@@ -285,6 +347,8 @@ impl RequestBuilder {
285347
url: Some(request.url().clone()),
286348
headers: request.headers().clone(),
287349
body: BytesMut::from(request.body()),
350+
local_socket: request.local_socket.clone(),
351+
remote_socket: request.remote_socket.clone(),
288352
}
289353
}
290354

@@ -372,6 +436,58 @@ impl RequestBuilder {
372436
self
373437
}
374438

439+
/// Sets the local socket of the request.
440+
///
441+
/// # Examples
442+
///
443+
/// ```
444+
/// use lang_handler::RequestBuilder;
445+
///
446+
/// let request = RequestBuilder::new()
447+
/// .local_socket("127.0.0.1:8080").expect("invalid local socket")
448+
/// .build();
449+
///
450+
/// assert_eq!(request.local_socket(), "127.0.0.1:8080");
451+
/// ```
452+
pub fn local_socket<T>(mut self, local_socket: T) -> Result<Self, AddrParseError>
453+
where
454+
T: Into<String>,
455+
{
456+
match local_socket.into().parse() {
457+
Err(e) => Err(e),
458+
Ok(local_socket) => {
459+
self.local_socket = Some(local_socket);
460+
Ok(self)
461+
}
462+
}
463+
}
464+
465+
/// Sets the remote socket of the request.
466+
///
467+
/// # Examples
468+
///
469+
/// ```
470+
/// use lang_handler::RequestBuilder;
471+
///
472+
/// let request = RequestBuilder::new()
473+
/// .remote_socket("127.0.0.1:8080").expect("invalid remote socket")
474+
/// .build();
475+
///
476+
/// assert_eq!(request.remote_socket(), "127.0.0.1:8080");
477+
/// ```
478+
pub fn remote_socket<T>(mut self, remote_socket: T) -> Result<Self, AddrParseError>
479+
where
480+
T: Into<String>,
481+
{
482+
match remote_socket.into().parse() {
483+
Err(e) => Err(e),
484+
Ok(remote_socket) => {
485+
self.remote_socket = Some(remote_socket);
486+
Ok(self)
487+
}
488+
}
489+
}
490+
375491
/// Builds the request.
376492
///
377493
/// # Examples
@@ -395,6 +511,8 @@ impl RequestBuilder {
395511
.unwrap_or_else(|| Url::parse("http://example.com").unwrap()),
396512
headers: self.headers,
397513
body: self.body.freeze(),
514+
local_socket: self.local_socket,
515+
remote_socket: self.remote_socket,
398516
}
399517
}
400518
}

crates/php/src/embed.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -727,11 +727,6 @@ pub extern "C" fn sapi_module_register_server_variables(vars: *mut ext_php_rs::t
727727
c"".as_ptr()
728728
};
729729

730-
// php_register_variable(cstr("PATH").unwrap(), cstr("/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin").unwrap(), vars);
731-
// php_register_variable(cstr("SERVER_SIGNATURE").unwrap(), cstr("
732-
// Apache/2.4.62 (Debian) Server at localhost Port 8080
733-
734-
// ").unwrap(), vars);
735730
php_register_variable(
736731
cstr("REQUEST_SCHEME").unwrap(),
737732
cstr(request.url().scheme()).unwrap(),
@@ -773,15 +768,15 @@ pub extern "C" fn sapi_module_register_server_variables(vars: *mut ext_php_rs::t
773768
vars,
774769
);
775770

776-
// TODO: REMOTE_ADDR, REMOTE_PORT
771+
if let Some(info) = request.local_socket() {
772+
php_register_variable(cstr("SERVER_ADDR").unwrap(), cstr(info.ip().to_string()).unwrap(), vars);
773+
php_register_variable(cstr("SERVER_PORT").unwrap(), cstr(info.port().to_string()).unwrap(), vars);
774+
}
777775

778-
// TODO: This should pull from the _real_ headers
779-
php_register_variable(cstr("HTTP_HOST").unwrap(), c"localhost:3000".as_ptr(), vars);
780-
php_register_variable(cstr("SERVER_NAME").unwrap(), c"localhost".as_ptr(), vars);
781-
php_register_variable(cstr("SERVER_ADDR").unwrap(), c"172.19.0.2".as_ptr(), vars);
782-
php_register_variable(cstr("SERVER_PORT").unwrap(), c"3000".as_ptr(), vars);
783-
php_register_variable(cstr("REMOTE_ADDR").unwrap(), c"192.168.65.1".as_ptr(), vars);
784-
php_register_variable(cstr("REMOTE_PORT").unwrap(), c"21845".as_ptr(), vars);
776+
if let Some(info) = request.remote_socket() {
777+
php_register_variable(cstr("REMOTE_ADDR").unwrap(), cstr(info.ip().to_string()).unwrap(), vars);
778+
php_register_variable(cstr("REMOTE_PORT").unwrap(), cstr(info.port().to_string()).unwrap(), vars);
779+
}
785780

786781
if !req_info.request_method.is_null() {
787782
php_register_variable(

crates/php_node/src/request.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
use std::collections::HashMap;
22

3+
use napi::Result;
34
use napi::bindgen_prelude::*;
45

56
use php::{Request, RequestBuilder};
67

78
use crate::PhpHeaders;
89

10+
#[napi(object)]
11+
#[derive(Default)]
12+
pub struct PhpRequestSocketOptions {
13+
/// The string representation of the local IP address the remote client is connecting on.
14+
pub local_address: String,
15+
/// The numeric representation of the local port. For example, 80 or 21.
16+
pub local_port: String,
17+
/// The string representation of the remote IP address.
18+
pub remote_address: String,
19+
/// The numeric representation of the remote port. For example, 80 or 21.
20+
pub remote_port: String,
21+
}
22+
923
/// Options for creating a new PHP request.
1024
#[napi(object)]
1125
#[derive(Default)]
@@ -20,6 +34,8 @@ pub struct PhpRequestOptions {
2034
pub headers: Option<HashMap<String, Vec<String>>>,
2135
/// The body for the request.
2236
pub body: Option<Uint8Array>,
37+
/// The socket information for the request.
38+
pub socket: Option<PhpRequestSocketOptions>,
2339
}
2440

2541
/// A PHP request.
@@ -61,17 +77,28 @@ impl PhpRequest {
6177
/// });
6278
/// ```
6379
#[napi(constructor)]
64-
pub fn constructor(options: PhpRequestOptions) -> Self {
80+
pub fn constructor(options: PhpRequestOptions) -> Result<Self> {
6581
let mut builder: RequestBuilder = Request::builder()
6682
.method(options.method)
67-
.url(options.url)
68-
.expect("invalid url");
83+
.url(&options.url)
84+
.map_err(|_| Error::from_reason(format!("Invalid URL \"{}\"", options.url)))?;
85+
86+
if let Some(socket) = options.socket {
87+
let local_socket = format!("{}:{}", socket.local_address, socket.local_port);
88+
let remote_socket = format!("{}:{}", socket.remote_address, socket.remote_port);
89+
90+
builder = builder
91+
.local_socket(&local_socket)
92+
.map_err(|_| Error::from_reason(format!("Invalid local socket \"{}\"", local_socket)))?
93+
.remote_socket(&remote_socket)
94+
.map_err(|_| Error::from_reason(format!("Invalid remote socket \"{}\"", remote_socket)))?;
95+
}
6996

7097
if let Some(headers) = options.headers {
7198
for key in headers.keys() {
7299
let values = headers
73100
.get(key)
74-
.expect(format!("missing header values for key: {}", key).as_str());
101+
.ok_or_else(|| Error::from_reason(format!("Missing header values for key \"{}\"", key)))?;
75102

76103
for value in values {
77104
builder = builder.header(key.clone(), value.clone())
@@ -83,9 +110,9 @@ impl PhpRequest {
83110
builder = builder.body(body.as_ref())
84111
}
85112

86-
PhpRequest {
113+
Ok(PhpRequest {
87114
request: builder.build(),
88-
}
115+
})
89116
}
90117

91118
/// Get the HTTP method for the request.

0 commit comments

Comments
 (0)