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}