rocket_http/uri/fmt/
formatter.rs

1use std::fmt::{self, Write};
2use std::marker::PhantomData;
3use std::borrow::Cow;
4
5use smallvec::SmallVec;
6
7use crate::uri::{Absolute, Origin, Reference};
8use crate::uri::fmt::{UriDisplay, Part, Path, Query, Kind};
9
10/// A struct used to format strings for [`UriDisplay`].
11///
12/// # Marker Generic: `Formatter<Path>` vs. `Formatter<Query>`
13///
14/// Like [`UriDisplay`], the [`Part`] parameter `P` in `Formatter<P>` must be
15/// either [`Path`] or [`Query`] resulting in either `Formatter<Path>` or
16/// `Formatter<Query>`. The `Path` version is used when formatting parameters
17/// in the path part of the URI while the `Query` version is used when
18/// formatting parameters in the query part of the URI. The
19/// [`write_named_value()`] method is only available to `UriDisplay<Query>`.
20///
21/// # Overview
22///
23/// A mutable version of this struct is passed to [`UriDisplay::fmt()`]. This
24/// struct properly formats series of values for use in URIs. In particular,
25/// this struct applies the following transformations:
26///
27///   * When **multiple values** are written, they are separated by `/` for
28///     `Path` types and `&` for `Query` types.
29///
30/// Additionally, for `Formatter<Query>`:
31///
32///   * When a **named value** is written with [`write_named_value()`], the name
33///     is written out, followed by a `=`, followed by the value.
34///
35///   * When **nested named values** are written, typically by passing a value
36///     to [`write_named_value()`] whose implementation of `UriDisplay` also
37///     calls `write_named_value()`, the nested names are joined by a `.`,
38///     written out followed by a `=`, followed by the value.
39///
40/// # Usage
41///
42/// Usage is fairly straightforward:
43///
44///   * For every _named value_ you wish to emit, call [`write_named_value()`].
45///   * For every _unnamed value_ you wish to emit, call [`write_value()`].
46///   * To write a string directly, call [`write_raw()`].
47///
48/// The `write_named_value` method automatically prefixes the `name` to the
49/// written value and, along with `write_value` and `write_raw`, handles nested
50/// calls to `write_named_value` automatically, prefixing names when necessary.
51/// Unlike the other methods, `write_raw` does _not_ prefix any nested names
52/// every time it is called. Instead, it only prefixes the _first_ time it is
53/// called, after a call to `write_named_value` or `write_value`, or after a
54/// call to [`refresh()`].
55///
56/// # Example
57///
58/// The following example uses all of the `write` methods in a varied order to
59/// display the semantics of `Formatter<Query>`. Note that `UriDisplay` should
60/// rarely be implemented manually, preferring to use the derive, and that this
61/// implementation is purely demonstrative.
62///
63/// ```rust
64/// # extern crate rocket;
65/// use std::fmt;
66///
67/// use rocket::http::uri::fmt::{Formatter, UriDisplay, Query};
68///
69/// struct Outer {
70///     value: Inner,
71///     another: usize,
72///     extra: usize
73/// }
74///
75/// struct Inner {
76///     value: usize,
77///     extra: usize
78/// }
79///
80/// impl UriDisplay<Query> for Outer {
81///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
82///         f.write_named_value("outer_field", &self.value)?;
83///         f.write_named_value("another", &self.another)?;
84///         f.write_raw("out")?;
85///         f.write_raw("side")?;
86///         f.write_value(&self.extra)
87///     }
88/// }
89///
90/// impl UriDisplay<Query> for Inner {
91///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
92///         f.write_named_value("inner_field", &self.value)?;
93///         f.write_value(&self.extra)?;
94///         f.write_raw("inside")
95///     }
96/// }
97///
98/// let inner = Inner { value: 0, extra: 1 };
99/// let outer = Outer { value: inner, another: 2, extra: 3 };
100/// let uri_string = format!("{}", &outer as &dyn UriDisplay<Query>);
101/// assert_eq!(uri_string, "outer_field.inner_field=0&\
102///                         outer_field=1&\
103///                         outer_field=inside&\
104///                         another=2&\
105///                         outside&\
106///                         3");
107/// ```
108///
109/// Note that you can also use the `write!` macro to write directly to the
110/// formatter as long as the [`std::fmt::Write`] trait is in scope. Internally,
111/// the `write!` macro calls [`write_raw()`], so care must be taken to ensure
112/// that the written string is URI-safe.
113///
114/// ```rust
115/// # #[macro_use] extern crate rocket;
116/// use std::fmt::{self, Write};
117///
118/// use rocket::http::uri::fmt::{UriDisplay, Formatter, Part, Path, Query};
119///
120/// pub struct Complex(u8, u8);
121///
122/// impl<P: Part> UriDisplay<P> for Complex {
123///     fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result {
124///         write!(f, "{}+{}", self.0, self.1)
125///     }
126/// }
127///
128/// let uri_string = format!("{}", &Complex(42, 231) as &dyn UriDisplay<Path>);
129/// assert_eq!(uri_string, "42+231");
130///
131/// #[derive(UriDisplayQuery)]
132/// struct Message {
133///     number: Complex,
134/// }
135///
136/// let message = Message { number: Complex(42, 47) };
137/// let uri_string = format!("{}", &message as &dyn UriDisplay<Query>);
138/// assert_eq!(uri_string, "number=42+47");
139/// ```
140///
141/// [`write_named_value()`]: Formatter::write_value()
142/// [`write_value()`]: Formatter::write_value()
143/// [`write_raw()`]: Formatter::write_raw()
144/// [`refresh()`]: Formatter::refresh()
145pub struct Formatter<'i, P: Part> {
146    prefixes: SmallVec<[&'static str; 3]>,
147    inner: &'i mut (dyn Write + 'i),
148    previous: bool,
149    fresh: bool,
150    _marker: PhantomData<P>,
151}
152
153impl<'i, P: Part> Formatter<'i, P> {
154    #[inline(always)]
155    pub(crate) fn new(inner: &'i mut (dyn Write + 'i)) -> Self {
156        Formatter {
157            inner,
158            prefixes: SmallVec::new(),
159            previous: false,
160            fresh: true,
161            _marker: PhantomData,
162        }
163    }
164
165    #[inline(always)]
166    fn refreshed<F: FnOnce(&mut Self) -> fmt::Result>(&mut self, f: F) -> fmt::Result {
167        self.refresh();
168        let result = f(self);
169        self.refresh();
170        result
171    }
172
173    /// Writes `string` to `self`.
174    ///
175    /// If `self` is _fresh_ (after a call to other `write_` methods or
176    /// [`refresh()`]), prefixes any names and adds separators as necessary.
177    ///
178    /// This method is called by the `write!` macro.
179    ///
180    /// [`refresh()`]: Formatter::refresh()
181    ///
182    /// # Example
183    ///
184    /// ```rust
185    /// # extern crate rocket;
186    /// use std::fmt;
187    ///
188    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Part, Path};
189    ///
190    /// struct Foo;
191    ///
192    /// impl<P: Part> UriDisplay<P> for Foo {
193    ///     fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result {
194    ///         f.write_raw("f")?;
195    ///         f.write_raw("o")?;
196    ///         f.write_raw("o")
197    ///     }
198    /// }
199    ///
200    /// let foo = Foo;
201    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Path>);
202    /// assert_eq!(uri_string, "foo");
203    /// ```
204    pub fn write_raw<S: AsRef<str>>(&mut self, string: S) -> fmt::Result {
205        // This implementation is a bit of a lie to the type system. Instead of
206        // implementing this twice, one for <Path> and again for <Query>, we do
207        // this once here. This is okay since we know that this handles the
208        // cases for both Path and Query, and doing it this way allows us to
209        // keep the uri part generic _generic_ in other implementations that use
210        // `write_raw`.
211        if self.fresh {
212            if self.previous {
213                self.inner.write_char(P::DELIMITER)?;
214            }
215
216            if P::KIND == Kind::Query && !self.prefixes.is_empty() {
217                for (i, prefix) in self.prefixes.iter().enumerate() {
218                    if i != 0 { self.inner.write_char('.')? }
219                    self.inner.write_str(prefix)?;
220                }
221
222                self.inner.write_str("=")?;
223            }
224        }
225
226        self.fresh = false;
227        self.previous = true;
228        self.inner.write_str(string.as_ref())
229    }
230
231    /// Writes the unnamed value `value`. Any nested names are prefixed as
232    /// necessary.
233    ///
234    /// Refreshes `self` before and after the value is written.
235    ///
236    /// # Example
237    ///
238    /// ```rust
239    /// # extern crate rocket;
240    /// use std::fmt;
241    ///
242    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Part, Path, Query};
243    ///
244    /// struct Foo(usize);
245    ///
246    /// impl<P: Part> UriDisplay<P> for Foo {
247    ///     fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result {
248    ///         f.write_value(&self.0)
249    ///     }
250    /// }
251    ///
252    /// let foo = Foo(123);
253    ///
254    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Path>);
255    /// assert_eq!(uri_string, "123");
256    ///
257    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Query>);
258    /// assert_eq!(uri_string, "123");
259    /// ```
260    #[inline]
261    pub fn write_value<T: UriDisplay<P>>(&mut self, value: T) -> fmt::Result {
262        self.refreshed(|f| UriDisplay::fmt(&value, f))
263    }
264
265    /// Refreshes the formatter.
266    ///
267    /// After refreshing, [`write_raw()`] will prefix any nested names as well
268    /// as insert a separator.
269    ///
270    /// [`write_raw()`]: Formatter::write_raw()
271    ///
272    /// # Example
273    ///
274    /// ```rust
275    /// # #[macro_use] extern crate rocket;
276    /// use std::fmt;
277    ///
278    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Query, Path};
279    ///
280    /// struct Foo;
281    ///
282    /// impl UriDisplay<Query> for Foo {
283    ///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
284    ///         f.write_raw("a")?;
285    ///         f.write_raw("raw")?;
286    ///         f.refresh();
287    ///         f.write_raw("format")
288    ///     }
289    /// }
290    ///
291    /// let uri_string = format!("{}", &Foo as &dyn UriDisplay<Query>);
292    /// assert_eq!(uri_string, "araw&format");
293    ///
294    /// impl UriDisplay<Path> for Foo {
295    ///     fn fmt(&self, f: &mut Formatter<Path>) -> fmt::Result {
296    ///         f.write_raw("a")?;
297    ///         f.write_raw("raw")?;
298    ///         f.refresh();
299    ///         f.write_raw("format")
300    ///     }
301    /// }
302    ///
303    /// let uri_string = format!("{}", &Foo as &dyn UriDisplay<Path>);
304    /// assert_eq!(uri_string, "araw/format");
305    ///
306    /// #[derive(UriDisplayQuery)]
307    /// struct Message {
308    ///     inner: Foo,
309    /// }
310    ///
311    /// let msg = Message { inner: Foo };
312    /// let uri_string = format!("{}", &msg as &dyn UriDisplay<Query>);
313    /// assert_eq!(uri_string, "inner=araw&inner=format");
314    /// ```
315    #[inline(always)]
316    pub fn refresh(&mut self) {
317        self.fresh = true;
318    }
319}
320
321impl Formatter<'_, Query> {
322    fn with_prefix<F>(&mut self, prefix: &str, f: F) -> fmt::Result
323        where F: FnOnce(&mut Self) -> fmt::Result
324    {
325
326        struct PrefixGuard<'f, 'i>(&'f mut Formatter<'i, Query>);
327
328        impl<'f, 'i> PrefixGuard<'f, 'i> {
329            fn new(prefix: &str, f: &'f mut Formatter<'i, Query>) -> Self {
330                // SAFETY: The `prefix` string is pushed in a `StackVec` for use
331                // by recursive (nested) calls to `write_raw`. The string is
332                // pushed in `PrefixGuard` here and then popped in `Drop`.
333                // `prefixes` is modified nowhere else, and no concrete-lifetime
334                // strings leak from the the vector. As a result, it is
335                // impossible for a `prefix` to be accessed incorrectly as:
336                //
337                //   * Rust _guarantees_ `prefix` is valid for this method
338                //   * `prefix` is only reachable while this method's stack is
339                //     active because it is unconditionally popped before this
340                //     method returns via `PrefixGuard::drop()`.
341                //   * should a panic occur in `f()`, `PrefixGuard::drop()` is
342                //     still called (or the program aborts), ensuring `prefix`
343                //     is no longer in `prefixes` and thus inaccessible.
344                //   * thus, at any point `prefix` is reachable, it is valid
345                //
346                // Said succinctly: `prefixes` shadows a subset of the
347                // `with_prefix` stack, making it reachable to other code.
348                let prefix = unsafe { std::mem::transmute(prefix) };
349                f.prefixes.push(prefix);
350                PrefixGuard(f)
351            }
352        }
353
354        impl Drop for PrefixGuard<'_, '_> {
355            fn drop(&mut self) {
356                self.0.prefixes.pop();
357            }
358        }
359
360        f(&mut PrefixGuard::new(prefix, self).0)
361    }
362
363    /// Writes the named value `value` by prefixing `name` followed by `=` to
364    /// the value. Any nested names are also prefixed as necessary.
365    ///
366    /// Refreshes `self` before the name is written and after the value is
367    /// written.
368    ///
369    /// # Example
370    ///
371    /// ```rust
372    /// # extern crate rocket;
373    /// use std::fmt;
374    ///
375    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Query};
376    ///
377    /// struct Foo {
378    ///     name: usize
379    /// }
380    ///
381    /// // Note: This is identical to what #[derive(UriDisplayQuery)] would
382    /// // generate! In practice, _always_ use the derive.
383    /// impl UriDisplay<Query> for Foo {
384    ///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
385    ///         f.write_named_value("name", &self.name)
386    ///     }
387    /// }
388    ///
389    /// let foo = Foo { name: 123 };
390    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Query>);
391    /// assert_eq!(uri_string, "name=123");
392    /// ```
393    #[inline]
394    pub fn write_named_value<T: UriDisplay<Query>>(&mut self, name: &str, value: T) -> fmt::Result {
395        self.refreshed(|f| f.with_prefix(name, |f| f.write_value(value)))
396    }
397}
398
399impl<P: Part> fmt::Write for Formatter<'_, P> {
400    fn write_str(&mut self, s: &str) -> fmt::Result {
401        self.write_raw(s)
402    }
403}
404
405// Used by code generation.
406#[doc(hidden)]
407pub enum UriArgumentsKind<A> {
408    Static(&'static str),
409    Dynamic(A)
410}
411
412// Used by code generation.
413#[doc(hidden)]
414pub enum UriQueryArgument<'a> {
415    Raw(&'a str),
416    NameValue(&'a str, &'a dyn UriDisplay<Query>),
417    Value(&'a dyn UriDisplay<Query>)
418}
419
420/// No prefix at all.
421#[doc(hidden)]
422pub struct Void;
423
424// Used by code generation.
425#[doc(hidden)]
426pub trait ValidRoutePrefix {
427    type Output;
428
429    fn append(self, path: Cow<'static, str>, query: Option<Cow<'static, str>>) -> Self::Output;
430}
431
432impl<'a> ValidRoutePrefix for Origin<'a> {
433    type Output = Self;
434
435    fn append(self, path: Cow<'static, str>, query: Option<Cow<'static, str>>) -> Self::Output {
436        // No-op if `self` is already normalized.
437        let mut prefix = self.into_normalized();
438        prefix.clear_query();
439
440        if prefix.path() == "/" {
441            // Avoid a double `//` to start.
442            return Origin::new(path, query);
443        } else if path == "/" {
444            // Appending path to `/` is a no-op, but append any query.
445            prefix.set_query(query);
446            return prefix;
447        }
448
449        Origin::new(format!("{}{}", prefix.path(), path), query)
450    }
451}
452
453impl<'a> ValidRoutePrefix for Absolute<'a> {
454    type Output = Self;
455
456    fn append(self, path: Cow<'static, str>, query: Option<Cow<'static, str>>) -> Self::Output {
457        // No-op if `self` is already normalized.
458        let mut prefix = self.into_normalized();
459        prefix.clear_query();
460
461        if prefix.authority().is_some() {
462            // The prefix is normalized. Appending a `/` is a no-op.
463            if path == "/" {
464                prefix.set_query(query);
465                return prefix;
466            }
467        }
468
469        // In these cases, appending `path` would be a no-op or worse.
470        if prefix.path().is_empty() || prefix.path() == "/" {
471            prefix.set_path(path);
472            prefix.set_query(query);
473            return prefix;
474        }
475
476        if path == "/" {
477            prefix.set_query(query);
478            return prefix;
479        }
480
481        prefix.set_path(format!("{}{}", prefix.path(), path));
482        prefix.set_query(query);
483        prefix
484    }
485}
486
487// `Self` is a valid suffix for `T`.
488#[doc(hidden)]
489pub trait ValidRouteSuffix<T> {
490    type Output;
491
492    fn prepend(self, prefix: T) -> Self::Output;
493}
494
495impl<'a> ValidRouteSuffix<Origin<'a>> for Reference<'a> {
496    type Output = Self;
497
498    fn prepend(self, prefix: Origin<'a>) -> Self::Output {
499        Reference::from(prefix).with_query_fragment_of(self)
500    }
501}
502
503impl<'a> ValidRouteSuffix<Absolute<'a>> for Reference<'a> {
504    type Output = Self;
505
506    fn prepend(self, prefix: Absolute<'a>) -> Self::Output {
507        Reference::from(prefix).with_query_fragment_of(self)
508    }
509}
510
511impl<'a> ValidRouteSuffix<Origin<'a>> for Absolute<'a> {
512    type Output = Origin<'a>;
513
514    fn prepend(self, mut prefix: Origin<'a>) -> Self::Output {
515        if let Some(query) = self.query {
516            if prefix.query().is_none() {
517                prefix.set_query(query.value.into_concrete(&self.source));
518            }
519        }
520
521        prefix
522    }
523}
524
525impl<'a> ValidRouteSuffix<Absolute<'a>> for Absolute<'a> {
526    type Output = Self;
527
528    fn prepend(self, mut prefix: Absolute<'a>) -> Self::Output {
529        if let Some(query) = self.query {
530            if prefix.query().is_none() {
531                prefix.set_query(query.value.into_concrete(&self.source));
532            }
533        }
534
535        prefix
536    }
537}
538
539// Used by code generation.
540#[doc(hidden)]
541pub struct RouteUriBuilder {
542    pub path: Cow<'static, str>,
543    pub query: Option<Cow<'static, str>>,
544}
545
546// Used by code generation.
547#[doc(hidden)]
548pub struct PrefixedRouteUri<T>(T);
549
550// Used by code generation.
551#[doc(hidden)]
552pub struct SuffixedRouteUri<T>(T);
553
554// Used by code generation.
555#[doc(hidden)]
556impl RouteUriBuilder {
557    /// Create a new `RouteUriBuilder` with the given path/query args.
558    pub fn new(
559        path_args: UriArgumentsKind<&[&dyn UriDisplay<Path>]>,
560        query_args: Option<UriArgumentsKind<&[UriQueryArgument<'_>]>>,
561    ) -> Self {
562        use self::{UriArgumentsKind::*, UriQueryArgument::*};
563
564        let path: Cow<'static, str> = match path_args {
565            Static(path) => path.into(),
566            Dynamic(args) => {
567                let mut string = String::from("/");
568                let mut formatter = Formatter::<Path>::new(&mut string);
569                for value in args {
570                    let _ = formatter.write_value(value);
571                }
572
573                string.into()
574            }
575        };
576
577        let query: Option<Cow<'_, str>> = match query_args {
578            None => None,
579            Some(Static(query)) => Some(query.into()),
580            Some(Dynamic(args)) => {
581                let mut string = String::new();
582                let mut f = Formatter::<Query>::new(&mut string);
583                for arg in args {
584                    let _ = match arg {
585                        Raw(v) => f.write_raw(v),
586                        NameValue(n, v) => f.write_named_value(n, v),
587                        Value(v) => f.write_value(v),
588                    };
589                }
590
591                (!string.is_empty()).then(|| string.into())
592            }
593        };
594
595        RouteUriBuilder { path, query }
596    }
597
598    pub fn with_prefix<P: ValidRoutePrefix>(self, p: P) -> PrefixedRouteUri<P::Output> {
599        PrefixedRouteUri(p.append(self.path, self.query))
600    }
601
602    pub fn with_suffix<S>(self, suffix: S) -> SuffixedRouteUri<S::Output>
603        where S: ValidRouteSuffix<Origin<'static>>
604    {
605        SuffixedRouteUri(suffix.prepend(self.render()))
606    }
607
608    pub fn render(self) -> Origin<'static> {
609        Origin::new(self.path, self.query)
610    }
611}
612
613#[doc(hidden)]
614impl<T> PrefixedRouteUri<T> {
615    pub fn with_suffix<S: ValidRouteSuffix<T>>(self, suffix: S) -> SuffixedRouteUri<S::Output> {
616        SuffixedRouteUri(suffix.prepend(self.0))
617    }
618
619    pub fn render(self) -> T {
620        self.0
621    }
622}
623
624#[doc(hidden)]
625impl<T> SuffixedRouteUri<T> {
626    pub fn render(self) -> T {
627        self.0
628    }
629}
630
631// See https://github.com/rwf2/Rocket/issues/1534.
632#[cfg(test)]
633mod prefix_soundness_test {
634    use crate::uri::fmt::{Formatter, UriDisplay, Query};
635
636    struct MyValue;
637
638    impl UriDisplay<Query> for MyValue {
639        fn fmt(&self, _f: &mut Formatter<'_, Query>) -> std::fmt::Result {
640            panic!()
641        }
642    }
643
644    struct MyDisplay;
645
646    impl UriDisplay<Query> for MyDisplay {
647        fn fmt(&self, formatter: &mut Formatter<'_, Query>) -> std::fmt::Result {
648            struct Wrapper<'a, 'b>(&'a mut Formatter<'b, Query>);
649
650            impl<'a, 'b> Drop for Wrapper<'a, 'b> {
651                fn drop(&mut self) {
652                    let _overlap = String::from("12345");
653                    self.0.write_raw("world").ok();
654                    assert!(self.0.prefixes.is_empty());
655                }
656            }
657
658            let wrapper = Wrapper(formatter);
659            let temporary_string = String::from("hello");
660
661            // `write_named_value` will push `temp_string` into a buffer and
662            // call the formatter for `MyValue`, which panics. At the panic
663            // point, `formatter` contains an (illegal) static reference to
664            // `temp_string` in its `prefixes` stack. When unwinding occurs,
665            // `Wrapper` will be dropped. `Wrapper` holds a reference to
666            // `Formatter`, thus `Formatter` must be consistent at this point.
667            let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
668                wrapper.0.write_named_value(&temporary_string, MyValue)
669            }));
670
671            Ok(())
672        }
673    }
674
675    #[test]
676    fn check_consistency() {
677        let string = format!("{}", &MyDisplay as &dyn UriDisplay<Query>);
678        assert_eq!(string, "world");
679    }
680}