Skip to content

Commit 511be2a

Browse files
committed
Borrow contacts as &str from configuration pool.
1 parent a482169 commit 511be2a

File tree

4 files changed

+42
-19
lines changed

4 files changed

+42
-19
lines changed

src/acme.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,9 @@ where
227227
pub async fn new_account(&mut self) -> Result<types::Account> {
228228
self.directory = self.get_directory().await?;
229229

230-
// We validate that the strings are valid UTF-8 at configuration time.
231-
let contact: Vec<&str> = self
232-
.issuer
233-
.contacts
234-
.iter()
235-
.map(|x| x.to_str())
236-
.collect::<Result<_, _>>()?;
237-
238230
let payload = types::AccountRequest {
239231
terms_of_service_agreed: self.issuer.accept_tos,
240-
contact,
232+
contact: &self.issuer.contacts,
241233

242234
..Default::default()
243235
};

src/acme/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ pub struct Account {
6767
#[derive(Debug, Default, Serialize)]
6868
#[serde(rename_all = "camelCase")]
6969
pub struct AccountRequest<'a> {
70-
#[serde(skip_serializing_if = "Vec::is_empty")]
71-
pub contact: Vec<&'a str>,
70+
#[serde(skip_serializing_if = "<[_]>::is_empty")]
71+
pub contact: &'a [&'a str],
7272
#[serde(skip_serializing_if = "Option::is_none")]
7373
pub terms_of_service_agreed: Option<bool>,
7474
#[serde(skip_serializing_if = "Option::is_none")]

src/conf.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub mod shared_zone;
3333
pub mod ssl;
3434

3535
const NGX_CONF_DUPLICATE: *mut c_char = c"is duplicate".as_ptr().cast_mut();
36+
const NGX_CONF_INVALID_VALUE: *mut c_char = c"invalid value".as_ptr().cast_mut();
3637

3738
/// Main (http block) level configuration.
3839
#[derive(Debug, Default)]
@@ -337,12 +338,12 @@ extern "C" fn cmd_issuer_add_contact(
337338
// NGX_CONF_TAKE1 ensures that args contains 2 elements
338339
let args = cf.args();
339340

340-
if args[1].is_empty() || core::str::from_utf8(args[1].as_bytes()).is_err() {
341-
return c"invalid value".as_ptr().cast_mut();
341+
if args[1].is_empty() {
342+
return NGX_CONF_INVALID_VALUE;
342343
};
343344

344-
if has_scheme(args[1].as_ref()) {
345-
issuer.contacts.push(args[1]);
345+
let value = if has_scheme(args[1].as_ref()) {
346+
args[1]
346347
} else {
347348
let mut value = ngx_str_t::empty();
348349
value.len = MAILTO.len() + args[1].len;
@@ -353,11 +354,18 @@ extern "C" fn cmd_issuer_add_contact(
353354

354355
value.as_bytes_mut()[..MAILTO.len()].copy_from_slice(MAILTO);
355356
value.as_bytes_mut()[MAILTO.len()..].copy_from_slice(args[1].as_ref());
357+
value
358+
};
356359

357-
issuer.contacts.push(value);
360+
// SAFETY: the value is not empty, well aligned, and the conversion result is assigned to an
361+
// object in the same pool.
362+
match unsafe { conf_value_to_str(&value) } {
363+
Ok(x) => {
364+
issuer.contacts.push(x);
365+
NGX_CONF_OK
366+
}
367+
Err(_) => NGX_CONF_INVALID_VALUE,
358368
}
359-
360-
NGX_CONF_OK
361369
}
362370

363371
extern "C" fn cmd_issuer_set_account_key(
@@ -566,3 +574,26 @@ fn conf_check_nargs(cmd: &ngx_command_t, nargs: ngx_uint_t) -> bool {
566574
nargs <= ARGUMENT_NUMBER.len() && (flags & ARGUMENT_NUMBER[nargs - 1]) != 0
567575
}
568576
}
577+
578+
/// Unsafely converts `ngx_str_t` into a static UTF-8 string reference.
579+
///
580+
/// # Safety
581+
///
582+
/// `value` must be allocated on the configuration (cycle) pool, and stored in another object on the
583+
/// same pool. With that, we can expect that both the borrowed string and the owning object will be
584+
/// destroyed simultaneously.
585+
///
586+
/// In the worker process this happens at the process exit, making the `'static` lifetime specifier
587+
/// accurate.
588+
/// In the master process, the cycle pool is destroyed after reloading the configuration, along with
589+
/// all the configuration objects. But this process role is not capable of serving connections or
590+
/// running background tasks, and thus will not create additional borrows with potentially extended
591+
/// lifetime.
592+
unsafe fn conf_value_to_str(value: &ngx_str_t) -> Result<&'static str, core::str::Utf8Error> {
593+
if value.len == 0 {
594+
Ok("")
595+
} else {
596+
let bytes = core::slice::from_raw_parts(value.data, value.len);
597+
core::str::from_utf8(bytes)
598+
}
599+
}

src/conf/issuer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub struct Issuer {
4343
pub name: ngx_str_t,
4444
pub uri: Uri,
4545
pub account_key: PrivateKey,
46-
pub contacts: Vec<ngx_str_t, Pool>,
46+
pub contacts: Vec<&'static str, Pool>,
4747
pub resolver: Option<NonNull<ngx_resolver_t>>,
4848
pub resolver_timeout: ngx_msec_t,
4949
pub ssl_trusted_certificate: ngx_str_t,

0 commit comments

Comments
 (0)