Skip to content

Commit e264c13

Browse files
committed
feat: Improve napi header support further
1 parent 3362233 commit e264c13

File tree

8 files changed

+42
-165
lines changed

8 files changed

+42
-165
lines changed

crates/lang_handler/Cargo.toml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,7 @@ name = "lang_handler"
88
crate-type = ["cdylib", "rlib"]
99
path = "src/lib.rs"
1010

11-
[features]
12-
default = []
13-
napi = ["dep:napi", "dep:napi-build"]
14-
15-
[build-dependencies]
16-
napi-build = { version = "2.0.1", optional = true }
17-
1811
[dependencies]
1912
bytes = "1.10.1"
20-
napi = { version = "2.16.17", optional = true }
2113
regex = "1.11.1"
2214
url = "2.5.4"

crates/lang_handler/build.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

crates/lang_handler/src/headers.rs

Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -38,47 +38,6 @@ impl From<Vec<String>> for Header {
3838
}
3939
}
4040

41-
#[cfg(feature = "napi")]
42-
mod napi_header {
43-
use super::*;
44-
45-
use napi::bindgen_prelude::*;
46-
use napi::sys;
47-
48-
impl FromNapiValue for Header {
49-
unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
50-
let mut header_type = sys::ValueType::napi_undefined;
51-
unsafe { check_status!(sys::napi_typeof(env, value, &mut header_type)) }?;
52-
53-
let header_type: ValueType = header_type.into();
54-
55-
match header_type {
56-
ValueType::String => {
57-
let s = String::from_napi_value(env, value)?;
58-
Ok(Header::Single(s))
59-
}
60-
ValueType::Object => {
61-
let obj = Vec::<String>::from_napi_value(env, value)?;
62-
Ok(Header::Multiple(obj))
63-
}
64-
_ => Err(napi::Error::new(
65-
Status::InvalidArg,
66-
"Expected a string or an object for Header",
67-
)),
68-
}
69-
}
70-
}
71-
72-
impl ToNapiValue for Header {
73-
unsafe fn to_napi_value(env: sys::napi_env, value: Self) -> Result<sys::napi_value> {
74-
match value {
75-
Header::Single(value) => String::to_napi_value(env, value),
76-
Header::Multiple(values) => Vec::<String>::to_napi_value(env, values),
77-
}
78-
}
79-
}
80-
}
81-
8241
/// A multi-map of HTTP headers.
8342
///
8443
/// # Examples
@@ -371,87 +330,3 @@ impl Default for Headers {
371330
Self::new()
372331
}
373332
}
374-
375-
#[cfg(feature = "napi")]
376-
mod napi_headers {
377-
use super::*;
378-
379-
use std::ptr;
380-
381-
use napi::bindgen_prelude::*;
382-
use napi::sys;
383-
384-
impl FromNapiValue for Headers {
385-
unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
386-
let mut header_type = sys::ValueType::napi_undefined;
387-
unsafe { check_status!(sys::napi_typeof(env, value, &mut header_type)) }?;
388-
389-
let header_type: ValueType = header_type.into();
390-
391-
if header_type != ValueType::Object {
392-
return Err(napi::Error::new(
393-
napi::Status::InvalidArg,
394-
"Expected an object for Headers",
395-
));
396-
}
397-
398-
let mut headers = Headers::new();
399-
unsafe {
400-
let mut keys: sys::napi_value = ptr::null_mut();
401-
check_status!(
402-
sys::napi_get_property_names(env, value, &mut keys),
403-
"Failed to get Headers property names"
404-
)?;
405-
406-
let mut key_count = 0;
407-
check_status!(sys::napi_get_array_length(env, keys, &mut key_count))?;
408-
409-
for i in 0..key_count {
410-
let mut key: sys::napi_value = ptr::null_mut();
411-
check_status!(
412-
sys::napi_get_element(env, keys, i, &mut key),
413-
"Failed to get header name"
414-
)?;
415-
let key_str = String::from_napi_value(env, key)?;
416-
let key_cstr = std::ffi::CString::new(key_str.clone())?;
417-
418-
let mut header_value: sys::napi_value = ptr::null_mut();
419-
check_status!(
420-
sys::napi_get_named_property(env, value, key_cstr.as_ptr(), &mut header_value),
421-
"Failed to get header value"
422-
)?;
423-
424-
if let Ok(header) = Header::from_napi_value(env, header_value) {
425-
headers.set(key_str, header);
426-
}
427-
}
428-
}
429-
430-
Ok(headers)
431-
}
432-
}
433-
434-
impl ToNapiValue for Headers {
435-
unsafe fn to_napi_value(env: sys::napi_env, value: Self) -> Result<sys::napi_value> {
436-
let mut result: sys::napi_value = ptr::null_mut();
437-
unsafe {
438-
check_status!(
439-
sys::napi_create_object(env, &mut result),
440-
"Failed to create Headers object"
441-
)?;
442-
443-
for (key, header) in value.iter() {
444-
let key_cstr = std::ffi::CString::new(key.to_string())?;
445-
let value_napi_value = Header::to_napi_value(env, header.to_owned())?;
446-
447-
check_status!(
448-
sys::napi_set_named_property(env, result, key_cstr.as_ptr(), value_napi_value),
449-
"Failed to set header property"
450-
)?;
451-
}
452-
}
453-
454-
Ok(result)
455-
}
456-
}
457-
}

crates/php/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ bytes = "1.10.1"
1616
hostname = "0.4.1"
1717
ext-php-rs = { git = "https://github.com/platformatic/ext-php-rs.git" }
1818
# ext-php-rs = { path = "../../../ext-php-rs" }
19-
lang_handler = { path = "../lang_handler", features = ["napi"] }
19+
lang_handler = { path = "../lang_handler" }
2020
libc = "0.2.171"
2121
once_cell = "1.21.0"
2222

crates/php_node/src/headers.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::ptr;
1+
use std::{collections::HashMap, ptr};
22

33
use napi::bindgen_prelude::*;
44
use napi::Result;
@@ -73,22 +73,37 @@ impl Into<Headers> for PhpHeaders {
7373
}
7474
}
7575

76-
impl From<Headers> for PhpHeaders {
77-
fn from(headers: Headers) -> Self {
78-
PhpHeaders { headers }
76+
pub type PhpHeadersMap = HashMap<String, Either<String, Vec<String>>>;
77+
pub type PhpHeadersInput = Either<ClassInstance<PhpHeaders>, PhpHeadersMap>;
78+
79+
impl From<PhpHeadersMap> for PhpHeaders {
80+
fn from(map: PhpHeadersMap) -> Self {
81+
let mut headers = Headers::new();
82+
83+
// Convert the map to a Headers instance.
84+
for (k, v) in map.into_iter() {
85+
match v {
86+
Either::A(value) => headers.set(k, value),
87+
Either::B(values) => {
88+
for value in values {
89+
headers.add(k.clone(), value);
90+
}
91+
}
92+
}
93+
}
94+
95+
PhpHeaders {
96+
headers,
97+
}
7998
}
8099
}
81100

82-
// This replaces the FromNapiValue impl inherited from ClassInstance to allow
83-
// unwrapping a PhpHeaders instance directly to Headers. This allows both
84-
// object and instance form of Headers to be used interchangeably.
85-
impl FromNapiValue for PhpHeaders {
86-
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
87-
let headers = ClassInstance::<PhpHeaders>::from_napi_value(env, napi_val)
88-
.map(|php_headers| php_headers.headers.clone())
89-
.or_else(|_| Headers::from_napi_value(env, napi_val))?;
90-
91-
Ok(PhpHeaders { headers })
101+
impl From<PhpHeadersInput> for PhpHeaders {
102+
fn from(input: PhpHeadersInput) -> Self {
103+
match input {
104+
Either::A(instance) => instance.clone(),
105+
Either::B(map) => map.into()
106+
}
92107
}
93108
}
94109

@@ -102,9 +117,11 @@ impl PhpHeaders {
102117
/// const headers = new Headers();
103118
/// ```
104119
#[napi(constructor)]
105-
pub fn constructor(headers: Option<Headers>) -> Self {
106-
PhpHeaders {
107-
headers: headers.unwrap_or_default(),
120+
pub fn constructor(input: Option<PhpHeadersInput>) -> Self {
121+
match input {
122+
None => PhpHeaders { headers: Headers::new() },
123+
Some(Either::A(input)) => input.clone(),
124+
Some(Either::B(input)) => input.into()
108125
}
109126
}
110127

crates/php_node/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod response;
77
mod rewriter;
88
mod runtime;
99

10-
pub use headers::PhpHeaders;
10+
pub use headers::{PhpHeaders, PhpHeadersInput};
1111
pub use request::PhpRequest;
1212
pub use response::PhpResponse;
1313
pub use rewriter::PhpRewriter;

crates/php_node/src/request.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use napi::Result;
33

44
use php::{Request, RequestBuilder};
55

6-
use crate::PhpHeaders;
6+
use crate::{PhpHeaders, PhpHeadersInput};
77

88
#[napi(object)]
99
#[derive(Default)]
@@ -31,7 +31,7 @@ pub struct PhpRequestOptions {
3131
/// The URL for the request.
3232
pub url: String,
3333
/// The headers for the request.
34-
pub headers: Option<PhpHeaders>,
34+
pub headers: Option<PhpHeadersInput>,
3535
/// The body for the request.
3636
pub body: Option<Uint8Array>,
3737
/// The socket information for the request.
@@ -110,7 +110,7 @@ impl PhpRequest {
110110
}
111111

112112
if let Some(headers) = options.headers {
113-
builder = builder.headers(headers);
113+
builder = builder.headers(Into::<PhpHeaders>::into(headers));
114114
}
115115

116116
if let Some(body) = options.body {

crates/php_node/src/response.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use napi::Result;
33

44
use php::Response;
55

6-
use crate::PhpHeaders;
6+
use crate::{PhpHeaders, PhpHeadersInput};
77

88
/// Options for creating a new PHP response.
99
#[napi(object)]
@@ -12,7 +12,7 @@ pub struct PhpResponseOptions {
1212
/// The HTTP status code for the response.
1313
pub status: Option<i32>,
1414
/// The headers for the response.
15-
pub headers: Option<PhpHeaders>,
15+
pub headers: Option<PhpHeadersInput>,
1616
/// The body for the response.
1717
pub body: Option<Uint8Array>,
1818
/// The log for the response.
@@ -59,7 +59,7 @@ impl PhpResponse {
5959
}
6060

6161
if let Some(headers) = options.headers {
62-
builder = builder.headers(headers);
62+
builder = builder.headers(Into::<PhpHeaders>::into(headers));
6363
}
6464

6565
if let Some(body) = options.body {

0 commit comments

Comments
 (0)