oauth1_request/
request.rs

1//! Requests to be authorized with OAuth.
2
3pub mod parameter_list;
4
5pub use self::parameter_list::ParameterList;
6
7use core::fmt::Display;
8
9use crate::serializer::{Serializer, SerializerExt};
10use crate::util::OAuthParameter;
11
12/// Types that represent an HTTP request to be authorized with OAuth.
13///
14/// `Request` is an abstraction of a sequence of key-value pairs of a query part of a URI
15/// and `x-www-form-urlencoded` string.
16///
17/// This trait can be implemented automatically by
18/// [`#[derive(Request)]`][oauth1_request_derive::Request] derive macro.
19/// In most cases, you won't need to implement it manually.
20pub trait Request {
21    /// Feeds a [`Serializer`] implementation with the key-value pairs of the request
22    /// and returns the serializer's output.
23    fn serialize<S>(&self, serializer: S) -> S::Output
24    where
25        S: Serializer;
26}
27
28/// A wrapper type that implements [`Request`] with key-value pairs returned by the wrapped
29/// iterator.
30///
31/// The key-value pairs must be sorted as required by the [`Serializer`] trait. Otherwise, the
32/// behavior of this wrapper is unspecified.
33///
34/// Note that the required ordering is alphabetical ordering of `AsRef<str>` value of the key and
35/// `Display` representation of the value and does not necessarily match that of the one provided by
36/// the [`Ord`] trait, which may provide, for example, numerical ordering instead.
37///
38/// If you have a slice instead of an iterator, consider using [`ParameterList`], which guarantees
39/// the correct ordering.
40///
41/// ## Example
42///
43#[cfg_attr(feature = "alloc", doc = " ```edition2021")]
44#[cfg_attr(not(feature = "alloc"), doc = " ```edition2021,ignore")]
45/// # extern crate oauth1_request as oauth;
46/// #
47/// use std::collections::BTreeMap;
48///
49/// let request = BTreeMap::from_iter([
50///     ("article_id", "123456789"),
51///     ("text", "A request signed with OAuth & Rust 🦀 🔏"),
52/// ]);
53/// let request = oauth::request::AssertSorted::new(&request);
54///
55/// let form = oauth::to_form(&request);
56/// assert_eq!(
57///     form,
58///     "article_id=123456789&text=A%20request%20signed%20with%20OAuth%20%26%20Rust%20%F0%9F%A6%80%20%F0%9F%94%8F",
59/// );
60/// ```
61#[derive(Debug, Clone, Copy, Default)]
62pub struct AssertSorted<I> {
63    inner: I,
64}
65
66impl<'a, R> Request for &'a R
67where
68    R: Request + ?Sized,
69{
70    fn serialize<S>(&self, serializer: S) -> S::Output
71    where
72        S: Serializer,
73    {
74        (**self).serialize(serializer)
75    }
76}
77
78impl<'a, R> Request for &'a mut R
79where
80    R: Request + ?Sized,
81{
82    fn serialize<S>(&self, serializer: S) -> S::Output
83    where
84        S: Serializer,
85    {
86        (**self).serialize(serializer)
87    }
88}
89
90/// Authorizes a request with no query pairs.
91impl Request for () {
92    fn serialize<S>(&self, mut serializer: S) -> S::Output
93    where
94        S: Serializer,
95    {
96        serializer.serialize_oauth_parameters();
97        serializer.end()
98    }
99}
100
101impl<R: Request> Request for Option<R> {
102    fn serialize<S>(&self, mut serializer: S) -> S::Output
103    where
104        S: Serializer,
105    {
106        if let Some(ref this) = *self {
107            this.serialize(serializer)
108        } else {
109            serializer.serialize_oauth_parameters();
110            serializer.end()
111        }
112    }
113}
114
115impl<I, K, V> AssertSorted<I>
116where
117    I: Clone + Iterator<Item = (K, V)>,
118    K: AsRef<str>,
119    V: Display,
120{
121    /// Creates a new `AssertSorted`.
122    pub fn new<J>(iterator: J) -> Self
123    where
124        J: IntoIterator<Item = (K, V), IntoIter = I>,
125    {
126        AssertSorted {
127            inner: iterator.into_iter(),
128        }
129    }
130}
131
132impl<I, K, V> Request for AssertSorted<I>
133where
134    I: Clone + Iterator<Item = (K, V)>,
135    K: AsRef<str>,
136    V: Display,
137{
138    fn serialize<S>(&self, mut serializer: S) -> S::Output
139    where
140        S: Serializer,
141    {
142        let mut next_param = OAuthParameter::default();
143
144        for (k, v) in self.inner.clone() {
145            let k = k.as_ref();
146            while next_param < *k {
147                next_param.serialize(&mut serializer);
148                next_param = next_param.next();
149            }
150            serializer.serialize_parameter(k, v);
151        }
152
153        while next_param != OAuthParameter::None {
154            next_param.serialize(&mut serializer);
155            next_param = next_param.next();
156        }
157
158        serializer.end()
159    }
160}