@@ -33,6 +33,7 @@ pub mod shared_zone;
3333pub mod ssl;
3434
3535const 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
363371extern "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+ }
0 commit comments