Skip to content

feat: Improve napi header support further #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions crates/lang_handler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,7 @@ name = "lang_handler"
crate-type = ["cdylib", "rlib"]
path = "src/lib.rs"

[features]
default = []
napi = ["dep:napi", "dep:napi-build"]

[build-dependencies]
napi-build = { version = "2.0.1", optional = true }

[dependencies]
bytes = "1.10.1"
napi = { version = "2.16.17", optional = true }
regex = "1.11.1"
url = "2.5.4"
7 changes: 0 additions & 7 deletions crates/lang_handler/build.rs

This file was deleted.

125 changes: 0 additions & 125 deletions crates/lang_handler/src/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,47 +38,6 @@ impl From<Vec<String>> for Header {
}
}

#[cfg(feature = "napi")]
mod napi_header {
use super::*;

use napi::bindgen_prelude::*;
use napi::sys;

impl FromNapiValue for Header {
unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
let mut header_type = sys::ValueType::napi_undefined;
unsafe { check_status!(sys::napi_typeof(env, value, &mut header_type)) }?;

let header_type: ValueType = header_type.into();

match header_type {
ValueType::String => {
let s = String::from_napi_value(env, value)?;
Ok(Header::Single(s))
}
ValueType::Object => {
let obj = Vec::<String>::from_napi_value(env, value)?;
Ok(Header::Multiple(obj))
}
_ => Err(napi::Error::new(
Status::InvalidArg,
"Expected a string or an object for Header",
)),
}
}
}

impl ToNapiValue for Header {
unsafe fn to_napi_value(env: sys::napi_env, value: Self) -> Result<sys::napi_value> {
match value {
Header::Single(value) => String::to_napi_value(env, value),
Header::Multiple(values) => Vec::<String>::to_napi_value(env, values),
}
}
}
}

/// A multi-map of HTTP headers.
///
/// # Examples
Expand Down Expand Up @@ -371,87 +330,3 @@ impl Default for Headers {
Self::new()
}
}

#[cfg(feature = "napi")]
mod napi_headers {
use super::*;

use std::ptr;

use napi::bindgen_prelude::*;
use napi::sys;

impl FromNapiValue for Headers {
unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
let mut header_type = sys::ValueType::napi_undefined;
unsafe { check_status!(sys::napi_typeof(env, value, &mut header_type)) }?;

let header_type: ValueType = header_type.into();

if header_type != ValueType::Object {
return Err(napi::Error::new(
napi::Status::InvalidArg,
"Expected an object for Headers",
));
}

let mut headers = Headers::new();
unsafe {
let mut keys: sys::napi_value = ptr::null_mut();
check_status!(
sys::napi_get_property_names(env, value, &mut keys),
"Failed to get Headers property names"
)?;

let mut key_count = 0;
check_status!(sys::napi_get_array_length(env, keys, &mut key_count))?;

for i in 0..key_count {
let mut key: sys::napi_value = ptr::null_mut();
check_status!(
sys::napi_get_element(env, keys, i, &mut key),
"Failed to get header name"
)?;
let key_str = String::from_napi_value(env, key)?;
let key_cstr = std::ffi::CString::new(key_str.clone())?;

let mut header_value: sys::napi_value = ptr::null_mut();
check_status!(
sys::napi_get_named_property(env, value, key_cstr.as_ptr(), &mut header_value),
"Failed to get header value"
)?;

if let Ok(header) = Header::from_napi_value(env, header_value) {
headers.set(key_str, header);
}
}
}

Ok(headers)
}
}

impl ToNapiValue for Headers {
unsafe fn to_napi_value(env: sys::napi_env, value: Self) -> Result<sys::napi_value> {
let mut result: sys::napi_value = ptr::null_mut();
unsafe {
check_status!(
sys::napi_create_object(env, &mut result),
"Failed to create Headers object"
)?;

for (key, header) in value.iter() {
let key_cstr = std::ffi::CString::new(key.to_string())?;
let value_napi_value = Header::to_napi_value(env, header.to_owned())?;

check_status!(
sys::napi_set_named_property(env, result, key_cstr.as_ptr(), value_napi_value),
"Failed to set header property"
)?;
}
}

Ok(result)
}
}
}
2 changes: 1 addition & 1 deletion crates/php/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ bytes = "1.10.1"
hostname = "0.4.1"
ext-php-rs = { git = "https://github.com/platformatic/ext-php-rs.git" }
# ext-php-rs = { path = "../../../ext-php-rs" }
lang_handler = { path = "../lang_handler", features = ["napi"] }
lang_handler = { path = "../lang_handler" }
libc = "0.2.171"
once_cell = "1.21.0"

Expand Down
49 changes: 33 additions & 16 deletions crates/php_node/src/headers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ptr;
use std::{collections::HashMap, ptr};

use napi::bindgen_prelude::*;
use napi::Result;
Expand Down Expand Up @@ -73,22 +73,35 @@ impl Into<Headers> for PhpHeaders {
}
}

impl From<Headers> for PhpHeaders {
fn from(headers: Headers) -> Self {
pub type PhpHeadersMap = HashMap<String, Either<String, Vec<String>>>;
pub type PhpHeadersInput = Either<ClassInstance<PhpHeaders>, PhpHeadersMap>;

impl From<PhpHeadersMap> for PhpHeaders {
fn from(map: PhpHeadersMap) -> Self {
let mut headers = Headers::new();

// Convert the map to a Headers instance.
for (k, v) in map.into_iter() {
match v {
Either::A(value) => headers.set(k, value),
Either::B(values) => {
for value in values {
headers.add(k.clone(), value);
}
}
}
}

PhpHeaders { headers }
}
}

// This replaces the FromNapiValue impl inherited from ClassInstance to allow
// unwrapping a PhpHeaders instance directly to Headers. This allows both
// object and instance form of Headers to be used interchangeably.
impl FromNapiValue for PhpHeaders {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let headers = ClassInstance::<PhpHeaders>::from_napi_value(env, napi_val)
.map(|php_headers| php_headers.headers.clone())
.or_else(|_| Headers::from_napi_value(env, napi_val))?;

Ok(PhpHeaders { headers })
impl From<PhpHeadersInput> for PhpHeaders {
fn from(input: PhpHeadersInput) -> Self {
match input {
Either::A(instance) => instance.clone(),
Either::B(map) => map.into(),
}
}
}

Expand All @@ -102,9 +115,13 @@ impl PhpHeaders {
/// const headers = new Headers();
/// ```
#[napi(constructor)]
pub fn constructor(headers: Option<Headers>) -> Self {
PhpHeaders {
headers: headers.unwrap_or_default(),
pub fn constructor(input: Option<PhpHeadersInput>) -> Self {
match input {
None => PhpHeaders {
headers: Headers::new(),
},
Some(Either::A(input)) => input.clone(),
Some(Either::B(input)) => input.into(),
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/php_node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mod response;
mod rewriter;
mod runtime;

pub use headers::PhpHeaders;
pub use headers::{PhpHeaders, PhpHeadersInput};
pub use request::PhpRequest;
pub use response::PhpResponse;
pub use rewriter::PhpRewriter;
Expand Down
6 changes: 3 additions & 3 deletions crates/php_node/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use napi::Result;

use php::{Request, RequestBuilder};

use crate::PhpHeaders;
use crate::{PhpHeaders, PhpHeadersInput};

#[napi(object)]
#[derive(Default)]
Expand Down Expand Up @@ -31,7 +31,7 @@ pub struct PhpRequestOptions {
/// The URL for the request.
pub url: String,
/// The headers for the request.
pub headers: Option<PhpHeaders>,
pub headers: Option<PhpHeadersInput>,
/// The body for the request.
pub body: Option<Uint8Array>,
/// The socket information for the request.
Expand Down Expand Up @@ -110,7 +110,7 @@ impl PhpRequest {
}

if let Some(headers) = options.headers {
builder = builder.headers(headers);
builder = builder.headers(Into::<PhpHeaders>::into(headers));
}

if let Some(body) = options.body {
Expand Down
6 changes: 3 additions & 3 deletions crates/php_node/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use napi::Result;

use php::Response;

use crate::PhpHeaders;
use crate::{PhpHeaders, PhpHeadersInput};

/// Options for creating a new PHP response.
#[napi(object)]
Expand All @@ -12,7 +12,7 @@ pub struct PhpResponseOptions {
/// The HTTP status code for the response.
pub status: Option<i32>,
/// The headers for the response.
pub headers: Option<PhpHeaders>,
pub headers: Option<PhpHeadersInput>,
/// The body for the response.
pub body: Option<Uint8Array>,
/// The log for the response.
Expand Down Expand Up @@ -59,7 +59,7 @@ impl PhpResponse {
}

if let Some(headers) = options.headers {
builder = builder.headers(headers);
builder = builder.headers(Into::<PhpHeaders>::into(headers));
}

if let Some(body) = options.body {
Expand Down
Loading