oauth1_request_ios/lib.rs
1//! Yet yet yet another OAuth 1.0 client library.
2//!
3//! # Usage
4//!
5//! Add this to your `Cargo.toml`:
6//!
7//! ```toml
8//! [dependencies]
9//! oauth = { version = "0.0.1", package = "oauth1-request-ios" }
10//! ```
11//!
12//! For brevity, we refer to the crate name as `oauth` throughout the documentation,
13//! since the API is designed in favor of qualified paths like `oauth::get`.
14//!
15//! ## Create a request
16//!
17//! A typical authorization flow looks like this:
18//!
19#![cfg_attr(all(feature = "derive", feature = "hmac-sha1"), doc = " ```")]
20#![cfg_attr(
21 not(all(feature = "derive", feature = "hmac-sha1")),
22 doc = " ```ignore"
23)]
24//! # extern crate oauth1_request_ios as oauth;
25//! #
26//! // Define a type to represent your request.
27//! #[derive(oauth::Request)]
28//! struct CreateComment<'a> {
29//! article_id: u64,
30//! text: &'a str,
31//! }
32//!
33//! let uri = "https://example.com/api/v1/comments/create.json";
34//!
35//! let request = CreateComment {
36//! article_id: 123456789,
37//! text: "A request signed with OAuth & Rust 🦀 🔏",
38//! };
39//!
40//! // Prepare your credentials.
41//! let token =
42//! oauth::Token::from_parts("consumer_key", "consumer_secret", "token", "token_secret");
43//!
44//! // Create the `Authorization` header.
45//! let authorization_header = oauth::post(uri, &request, &token, oauth::HMAC_SHA1);
46//! # // Override the above value to pin the nonce and timestamp value.
47//! # let mut builder = oauth::Builder::new(token.client, oauth::HMAC_SHA1);
48//! # builder.token(token.token);
49//! # builder.nonce("Dk-OGluFEQ4f").timestamp(std::num::NonZeroU64::new(1234567890));
50//! # let authorization_header = builder.post(uri, &request);
51//! // `oauth_nonce` and `oauth_timestamp` vary on each execution.
52//! assert_eq!(
53//! authorization_header,
54//! "OAuth \
55//! oauth_consumer_key=\"consumer_key\",\
56//! oauth_nonce=\"Dk-OGluFEQ4f\",\
57//! oauth_signature_method=\"HMAC-SHA1\",\
58//! oauth_timestamp=\"1234567890\",\
59//! oauth_token=\"token\",\
60//! oauth_signature=\"n%2FrUgos4CFFZbZK8Z8wFR7drU4c%3D\"",
61//! );
62//!
63//! // You can create an `x-www-form-urlencoded` string or a URI with query pairs from the request.
64//!
65//! let form = oauth::to_form(&request);
66//! assert_eq!(
67//! form,
68//! "article_id=123456789&text=A%20request%20signed%20with%20OAuth%20%26%20Rust%20%F0%9F%A6%80%20%F0%9F%94%8F",
69//! );
70//!
71//! let uri = oauth::to_query(uri.to_owned(), &request);
72//! assert_eq!(
73//! uri,
74//! "https://example.com/api/v1/comments/create.json?article_id=123456789&text=A%20request%20signed%20with%20OAuth%20%26%20Rust%20%F0%9F%A6%80%20%F0%9F%94%8F",
75//! );
76//! ```
77//!
78//! See [`Request`][oauth1_request_derive_ios::Request] for more details on the derive macro.
79//!
80//! If you want to authorize a request with dynamic keys, use
81//! [`oauth::ParameterList`][ParameterList].
82//!
83#![cfg_attr(feature = "alloc", doc = " ```")]
84#![cfg_attr(not(feature = "alloc"), doc = " ```ignore")]
85//! # extern crate oauth1_request_ios as oauth;
86//! #
87//! use std::fmt::Display;
88//!
89//! let request = oauth::ParameterList::new([
90//! ("article_id", &123456789 as &dyn Display),
91//! ("text", &"A request signed with OAuth & Rust 🦀 🔏"),
92//! ]);
93//!
94//! let form = oauth::to_form(&request);
95//! assert_eq!(
96//! form,
97//! "article_id=123456789&text=A%20request%20signed%20with%20OAuth%20%26%20Rust%20%F0%9F%A6%80%20%F0%9F%94%8F",
98//! );
99//! ```
100//!
101//! Use [`oauth::Builder`][Builder] if you need to specify a callback URI or verifier:
102//!
103#![cfg_attr(all(feature = "alloc", feature = "hmac-sha1"), doc = " ```")]
104#![cfg_attr(not(all(feature = "alloc", feature = "hmac-sha1")), doc = " ```ignore")]
105//! # extern crate oauth1_request_ios as oauth;
106//! #
107//! let uri = "https://example.com/oauth/request_temp_credentials";
108//! let callback = "https://client.example.net/oauth/callback";
109//!
110//! let client = oauth::Credentials::new("consumer_key", "consumer_secret");
111//!
112//! let authorization_header = oauth::Builder::<_, _>::new(client, oauth::HmacSha1::new())
113//! .callback(callback)
114//! .post(uri, &());
115//! ```
116
117#![cfg_attr(docsrs, feature(doc_cfg))]
118#![doc(html_root_url = "https://docs.rs/oauth1-request-ios/0.0.1")]
119#![warn(missing_docs, rust_2018_idioms)]
120#![cfg_attr(not(feature = "std"), no_std)]
121
122#[cfg(feature = "alloc")]
123extern crate alloc;
124
125#[macro_use]
126mod util;
127
128pub mod request;
129pub mod serializer;
130pub mod signature_method;
131
132doc_auto_cfg! {
133 /// A derive macro for [`Request`] trait.
134 ///
135 /// The derive macro uses the struct's field names and `Display` implementation of the values as
136 /// the keys and values of the parameter pairs of the `Request`.
137 ///
138 /// ## Example
139 ///
140 #[cfg_attr(feature = "alloc", doc = " ```")]
141 #[cfg_attr(not(feature = "alloc"), doc = " ```ignore")]
142 /// # extern crate oauth1_request_ios as oauth;
143 /// #
144 /// #[derive(oauth::Request)]
145 /// struct CreateItem<'a> {
146 /// name: &'a str,
147 /// #[oauth1(rename = "type")]
148 /// kind: Option<u32>,
149 /// #[oauth1(skip_if = str::is_empty)]
150 /// note: &'a str,
151 /// }
152 ///
153 /// let request = CreateItem {
154 /// name: "test",
155 /// kind: Some(42),
156 /// note: "",
157 /// };
158 ///
159 /// assert_eq!(oauth::to_form(&request), "name=test&type=42");
160 /// ```
161 ///
162 /// ## Field attributes
163 ///
164 /// You can customize the behavior of the derive macro with the following field attributes:
165 ///
166 /// - `#[oauth1(encoded)]`
167 ///
168 /// Do not percent encode the value when serializing it.
169 ///
170 /// - `#[oauth1(fmt = path)]`
171 ///
172 /// Use the formatting function at `path` instead of `Display::fmt` when serializing the value.
173 /// The function must be callable as `fn(&T, &mut Formatter<'_>) -> fmt::Result`
174 /// (same as `Display::fmt`).
175 ///
176 /// - `#[oauth1(option = true)]` (or `#[oauth1(option = false)]`)
177 ///
178 /// If set to `true`, skip the field when the value is `None` or use the unwrapped value otherwise.
179 /// The value's type must be `Option<T>` in this case.
180 ///
181 /// When the field's type name is `Option<_>`, the attribute is implicitly set to `true`.
182 /// Use `#[oauth1(option = false)]` if you need to opt out of that behavior.
183 ///
184 /// - `#[oauth1(rename = "name")]`
185 ///
186 /// Use the given string as the parameter's key. The given string must be URI-safe.
187 ///
188 /// - `#[oauth1(skip)]`
189 ///
190 /// Do not serialize the field.
191 ///
192 /// - `#[oauth1(skip_if = path)]`
193 ///
194 /// Call the function at `path` and do not serialize the field if the function returns `true`.
195 /// The function must be callable as `fn(&T) -> bool`.
196 ///
197 /// ## Container attributes
198 ///
199 /// - `#[oauth1(crate = "name")]`
200 ///
201 /// Specify the path of `oauth1_request` crate. The path is automatically determined by the
202 /// derive macro by default, even if the crate is renamed with the [`[package]`][package] key of
203 /// `Cargo.toml`, so you usually don't need this attribute. It may be useful if you are using an
204 /// exotic build tool where the crate name cannot be determined reliably.
205 ///
206 /// [package]: <https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml>
207 #[cfg(feature = "derive")]
208 #[doc(inline)]
209 pub use oauth1_request_derive_ios::Request;
210}
211#[doc(no_inline)]
212pub use oauth_credentials_ios::{Credentials, Token};
213
214doc_auto_cfg! {
215 pub use self::request::ParameterList;
216 pub use self::request::Request;
217 #[cfg(feature = "hmac-sha1")]
218 pub use self::signature_method::HmacSha1;
219 pub use self::signature_method::Plaintext;
220 #[cfg(feature = "hmac-sha256")]
221 pub use self::signature_method::HmacSha256;
222 #[cfg(feature = "rsa-sha1-06")]
223 pub use self::signature_method::RsaSha1;
224 #[cfg(feature = "rsa-sha1-09")]
225 pub use self::signature_method::Rsa09Sha1;
226 #[cfg(feature = "hmac-sha1")]
227 pub use self::signature_method::HMAC_SHA1;
228 #[cfg(feature = "hmac-sha256")]
229 pub use self::signature_method::HMAC_SHA256;
230 #[cfg(feature = "alloc")]
231 pub use self::signature_method::PLAINTEXT;
232}
233
234#[cfg(feature = "alloc")]
235use alloc::string::String;
236use core::fmt::Debug;
237use core::fmt::{Display, Write};
238use core::num::NonZeroU64;
239use core::str;
240
241use self::serializer::auth;
242use self::signature_method::SignatureMethod;
243
244cfg_type_param_hack! {
245 /// A builder for OAuth `Authorization` header string.
246 #[derive(Clone, Debug)]
247 pub struct Builder<
248 'a,
249 SM,
250 #[cfg(feature = "alloc")] C = String,
251 #[cfg(not(feature = "alloc"))] C,
252 T = C,
253 > {
254 signature_method: SM,
255 client: Credentials<C>,
256 token: Option<Credentials<T>>,
257 options: auth::Options<'a>,
258 }
259}
260
261macro_rules! builder_authorize_shorthand {
262 ($($name:ident($method:expr);)*) => {doc_auto_cfg! {$(
263 #[doc = concat!("Authorizes a `", $method, "` request to `uri`,")]
264 /// returning an HTTP `Authorization` header value.
265 ///
266 /// `uri` must not contain a query part, which would result in a wrong signature.
267 #[cfg(feature = "alloc")]
268 pub fn $name<U, R>(&self, uri: U, request: &R) -> String
269 where
270 U: Display,
271 R: Request + ?Sized,
272 SM: Clone,
273 {
274 self.authorize($method, uri, request)
275 }
276 )*}};
277}
278
279macro_rules! builder_to_form_shorthand {
280 ($($name:ident($method:expr);)*) => {doc_auto_cfg! {$(
281 #[doc = concat!("Authorizes a `", $method, "` request to `uri`,")]
282 /// writing the OAuth protocol parameters to an `x-www-form-urlencoded` string
283 /// along with the other request parameters.
284 ///
285 /// `uri` must not contain a query part, which would result in a wrong signature.
286 #[cfg(feature = "alloc")]
287 pub fn $name<U, R>(&self, uri: U, request: &R) -> String
288 where
289 U: Display,
290 R: Request + ?Sized,
291 SM: Clone,
292 {
293 self.to_form($method, uri, request)
294 }
295 )*}};
296}
297
298macro_rules! builder_to_query_shorthand {
299 ($($name:ident($method:expr);)*) => {$(
300 doc_coerce_expr! {
301 #[doc = concat!("Authorizes a `", $method, "` request to `uri`, appending")]
302 /// the OAuth protocol parameters to `uri` along with the other request parameters.
303 ///
304 /// `uri` must not contain a query part, which would result in a wrong signature.
305 pub fn $name<W, R>(&self, uri: W, request: &R) -> W
306 where
307 W: Display + Write,
308 R: Request + ?Sized,
309 SM: Clone,
310 {
311 self.to_query($method, uri, request)
312 }
313 }
314 )*};
315}
316
317impl<'a, SM: SignatureMethod, C: AsRef<str>, T: AsRef<str>> Builder<'a, SM, C, T> {
318 /// Creates a `Builder` that signs requests using the specified client credentials
319 /// and signature method.
320 pub fn new(client: Credentials<C>, signature_method: SM) -> Self {
321 Builder {
322 signature_method,
323 client,
324 token: None,
325 options: auth::Options::new(),
326 }
327 }
328
329 /// Creates a `Builder` that uses the token credentials from `token`.
330 pub fn with_token(token: Token<C, T>, signature_method: SM) -> Self {
331 let mut ret = Builder::new(token.client, signature_method);
332 ret.token(token.token);
333 ret
334 }
335
336 /// Sets/unsets the token credentials pair to sign requests with.
337 pub fn token(&mut self, token: impl Into<Option<Credentials<T>>>) -> &mut Self {
338 self.token = token.into();
339 self
340 }
341
342 /// Sets/unsets the `oauth_callback` URI.
343 pub fn callback(&mut self, callback: impl Into<Option<&'a str>>) -> &mut Self {
344 self.options.callback(callback);
345 self
346 }
347
348 /// Sets/unsets the `oauth_verifier` value.
349 pub fn verifier(&mut self, verifier: impl Into<Option<&'a str>>) -> &mut Self {
350 self.options.verifier(verifier);
351 self
352 }
353
354 /// Sets/unsets the `oauth_nonce` value.
355 ///
356 /// By default, `Builder` generates a random nonce for each request.
357 /// This method overrides that behavior and forces the `Builder` to use the specified nonce.
358 ///
359 /// This method is for debugging/testing purpose only and should not be used in production.
360 pub fn nonce(&mut self, nonce: impl Into<Option<&'a str>>) -> &mut Self {
361 self.options.nonce(nonce);
362 self
363 }
364
365 /// Sets/unsets the `oauth_timestamp` value.
366 ///
367 /// By default, `Builder` uses the timestamp of the time when `authorize`-like method is called.
368 /// This method overrides that behavior and forces the `Builder` to use the specified timestamp.
369 ///
370 /// This method is for debugging/testing purpose only and should not be used in production.
371 pub fn timestamp(&mut self, timestamp: impl Into<Option<NonZeroU64>>) -> &mut Self {
372 self.options.timestamp(timestamp);
373 self
374 }
375
376 /// Sets whether to include the `oauth_version` value in requests.
377 pub fn version(&mut self, version: bool) -> &mut Self {
378 self.options.version(version);
379 self
380 }
381
382 builder_authorize_shorthand! {
383 get("GET");
384 put("PUT");
385 post("POST");
386 delete("DELETE");
387 options("OPTIONS");
388 head("HEAD");
389 connect("CONNECT");
390 patch("PATCH");
391 trace("TRACE");
392 }
393
394 builder_to_form_shorthand! {
395 put_form("PUT");
396 post_form("POST");
397 options_form("OPTIONS");
398 patch_form("PATCH");
399 }
400
401 builder_to_query_shorthand! {
402 get_query("GET");
403 put_query("PUT");
404 post_query("POST");
405 delete_query("DELETE");
406 options_query("OPTIONS");
407 head_query("HEAD");
408 connect_query("CONNECT");
409 patch_query("PATCH");
410 trace_query("TRACE");
411 }
412
413 doc_auto_cfg! {
414 /// Authorizes a request to `uri` with a custom HTTP request method,
415 /// returning an HTTP `Authorization` header value.
416 ///
417 /// `uri` must not contain a query part, which would result in a wrong signature.
418 #[cfg(feature = "alloc")]
419 pub fn authorize<U, R>(&self, method: &str, uri: U, request: &R) -> String
420 where
421 U: Display,
422 R: Request + ?Sized,
423 SM: Clone,
424 {
425 let serializer = serializer::auth::Authorizer::authorization(
426 method,
427 uri,
428 self.client.as_ref(),
429 self.token.as_ref().map(Credentials::as_ref),
430 &self.options,
431 self.signature_method.clone(),
432 );
433
434 request.serialize(serializer)
435 }
436
437 /// Authorizes a request to `uri` with a custom HTTP request method, writing the OAuth protocol
438 /// parameters to an `x-www-form-urlencoded` string along with the other request parameters.
439 ///
440 /// `uri` must not contain a query part, which would result in a wrong signature.
441 #[cfg(feature = "alloc")]
442 pub fn to_form<U, R>(&self, method: &str, uri: U, request: &R) -> String
443 where
444 U: Display,
445 R: Request + ?Sized,
446 SM: Clone,
447 {
448 let serializer = serializer::auth::Authorizer::form(
449 method,
450 uri,
451 self.client.as_ref(),
452 self.token.as_ref().map(Credentials::as_ref),
453 &self.options,
454 self.signature_method.clone(),
455 );
456
457 request.serialize(serializer)
458 }
459 }
460
461 /// Authorizes a request to `uri` with a custom HTTP request method, appending the OAuth
462 /// protocol parameters to `uri` along with the other request parameters.
463 ///
464 /// `uri` must not contain a query part, which would result in a wrong signature.
465 pub fn to_query<W, R>(&self, method: &str, uri: W, request: &R) -> W
466 where
467 W: Display + Write,
468 R: Request + ?Sized,
469 SM: Clone,
470 {
471 let serializer = serializer::auth::Authorizer::query(
472 method,
473 uri,
474 self.client.as_ref(),
475 self.token.as_ref().map(Credentials::as_ref),
476 &self.options,
477 self.signature_method.clone(),
478 );
479
480 request.serialize(serializer)
481 }
482
483 /// Same as `authorize` except that this writes the resulting `Authorization` header value
484 /// into `buf`.
485 pub fn authorize_with_buf<W, U, R>(&self, buf: W, method: &str, uri: U, request: &R) -> W
486 where
487 W: Write,
488 U: Display,
489 R: Request + ?Sized,
490 SM: Clone,
491 {
492 let serializer = serializer::auth::Authorizer::authorization_with_buf(
493 buf,
494 method,
495 uri,
496 self.client.as_ref(),
497 self.token.as_ref().map(Credentials::as_ref),
498 &self.options,
499 self.signature_method.clone(),
500 );
501
502 request.serialize(serializer)
503 }
504
505 doc_auto_cfg! {
506 /// Same as `to_form` except that this writes the resulting `x-www-form-urlencoded` string
507 /// into `buf`.
508 #[cfg(feature = "alloc")]
509 pub fn to_form_with_buf<W, U, R>(&self, buf: W, method: &str, uri: U, request: &R) -> W
510 where
511 W: Write,
512 U: Display,
513 R: Request + ?Sized,
514 SM: Clone,
515 {
516 let serializer = serializer::auth::Authorizer::form_with_buf(
517 buf,
518 method,
519 uri,
520 self.client.as_ref(),
521 self.token.as_ref().map(Credentials::as_ref),
522 &self.options,
523 self.signature_method.clone(),
524 );
525
526 request.serialize(serializer)
527 }
528
529 /// Authorizes a request and consumes `self`, returning an HTTP `Authorization` header value.
530 ///
531 /// Unlike `authorize`, this does not clone the signature method and may be more efficient for
532 /// non-`Copy` signature methods like `RsaSha1`.
533 ///
534 /// For `HmacSha1`, `&RsaSha1` and `Plaintext`, cloning is no-op or very cheap so you should
535 /// use `authorize` instead.
536 #[cfg(feature = "alloc")]
537 pub fn into_authorization<U, R>(self, method: &str, uri: U, request: &R) -> String
538 where
539 U: Display,
540 R: Request + ?Sized,
541 {
542 let serializer = serializer::auth::Authorizer::authorization(
543 method,
544 uri,
545 self.client.as_ref(),
546 self.token.as_ref().map(Credentials::as_ref),
547 &self.options,
548 self.signature_method,
549 );
550
551 request.serialize(serializer)
552 }
553
554 /// Authorizes a request and consumes `self`, writing the OAuth protocol parameters to
555 /// an `x-www-form-urlencoded` string along with the other request parameters.
556 ///
557 /// Unlike `to_form`, this does not clone the signature method and may be more efficient for
558 /// non-`Copy` signature methods like `RsaSha1`.
559 ///
560 /// For `HmacSha1`, `&RsaSha1` and `Plaintext`, cloning is no-op or very cheap so you should
561 /// use `to_form` instead.
562 #[cfg(feature = "alloc")]
563 pub fn into_form<U, R>(self, method: &str, uri: U, request: &R) -> String
564 where
565 U: Display,
566 R: Request + ?Sized,
567 {
568 let serializer = serializer::auth::Authorizer::form(
569 method,
570 uri,
571 self.client.as_ref(),
572 self.token.as_ref().map(Credentials::as_ref),
573 &self.options,
574 self.signature_method,
575 );
576
577 request.serialize(serializer)
578 }
579 }
580
581 /// Authorizes a request and consumes `self`, appending the OAuth protocol parameters to
582 /// `uri` along with the other request parameters.
583 ///
584 /// Unlike `to_query`, this does not clone the signature method and may be more efficient for
585 /// non-`Copy` signature methods like `RsaSha1`.
586 ///
587 /// For `HmacSha1`, `&RsaSha1` and `Plaintext`, cloning is no-op or very cheap so you should
588 /// use `to_query` instead.
589 pub fn into_query<W, R>(self, method: &str, uri: W, request: &R) -> W
590 where
591 W: Display + Write,
592 R: Request + ?Sized,
593 {
594 let serializer = serializer::auth::Authorizer::query(
595 method,
596 uri,
597 self.client.as_ref(),
598 self.token.as_ref().map(Credentials::as_ref),
599 &self.options,
600 self.signature_method,
601 );
602
603 request.serialize(serializer)
604 }
605
606 /// Same as `into_authorization` except that this writes the resulting `Authorization` header
607 /// value into `buf`.
608 pub fn into_authorization_with_buf<W, U, R>(
609 self,
610 buf: W,
611 method: &str,
612 uri: U,
613 request: &R,
614 ) -> W
615 where
616 W: Write,
617 U: Display,
618 R: Request + ?Sized,
619 SM: Clone,
620 {
621 let serializer = serializer::auth::Authorizer::authorization_with_buf(
622 buf,
623 method,
624 uri,
625 self.client.as_ref(),
626 self.token.as_ref().map(Credentials::as_ref),
627 &self.options,
628 self.signature_method,
629 );
630
631 request.serialize(serializer)
632 }
633
634 /// Same as `into_form` except that this writes the resulting `x-www-form-urlencoded` string
635 /// into `buf`.
636 pub fn into_form_with_buf<W, U, R>(self, buf: W, method: &str, uri: U, request: &R) -> W
637 where
638 W: Write,
639 U: Display,
640 R: Request + ?Sized,
641 {
642 let serializer = serializer::auth::Authorizer::form_with_buf(
643 buf,
644 method,
645 uri,
646 self.client.as_ref(),
647 self.token.as_ref().map(Credentials::as_ref),
648 &self.options,
649 self.signature_method,
650 );
651
652 request.serialize(serializer)
653 }
654}
655
656macro_rules! authorize_shorthand {
657 ($($name:ident($method:expr);)*) => {doc_auto_cfg! {$(
658 #[doc = concat!("Authorizes a `", $method, "` request to `uri` with the given credentials.")]
659 ///
660 /// This returns an HTTP `Authorization` header value.
661 ///
662 /// `uri` must not contain a query part, which would result in a wrong signature.
663 #[cfg(feature = "alloc")]
664 pub fn $name<U, R, C, T, SM>(
665 uri: U,
666 request: &R,
667 token: &Token<C, T>,
668 signature_method: SM,
669 ) -> String
670 where
671 U: Display,
672 R: Request + ?Sized,
673 C: AsRef<str>,
674 T: AsRef<str>,
675 SM: SignatureMethod,
676 {
677 authorize($method, uri, request, token, signature_method)
678 }
679 )*}};
680}
681
682authorize_shorthand! {
683 get("GET");
684 put("PUT");
685 post("POST");
686 delete("DELETE");
687 options("OPTIONS");
688 head("HEAD");
689 connect("CONNECT");
690 patch("PATCH");
691 trace("TRACE");
692}
693
694doc_auto_cfg! {
695 /// Authorizes a request to `uri` with the given credentials.
696 ///
697 /// This returns an HTTP `Authorization` header value.
698 ///
699 /// `uri` must not contain a query part, which would result in a wrong signature.
700 #[cfg(feature = "alloc")]
701 pub fn authorize<U, R, C, T, SM>(
702 method: &str,
703 uri: U,
704 request: &R,
705 token: &Token<C, T>,
706 signature_method: SM,
707 ) -> String
708 where
709 U: Display,
710 R: Request + ?Sized,
711 C: AsRef<str>,
712 T: AsRef<str>,
713 SM: SignatureMethod,
714 {
715 fn inner<U, R, SM>(
716 method: &str,
717 uri: U,
718 request: &R,
719 token: Token<&str, &str>,
720 signature_method: SM,
721 ) -> String
722 where
723 U: Display,
724 R: Request + ?Sized,
725 SM: SignatureMethod,
726 {
727 Builder::with_token(token, signature_method).into_authorization(method, uri, request)
728 }
729 inner(method, uri, request, token.as_ref(), signature_method)
730 }
731
732 /// Serializes a `Request` to an `x-www-form-urlencoded` string.
733 #[cfg(feature = "alloc")]
734 pub fn to_form<R>(request: &R) -> String
735 where
736 R: Request + ?Sized,
737 {
738 request.serialize(serializer::Urlencoder::form())
739 }
740
741 /// Serializes a `Request` to a query string and appends it to the given URI.
742 ///
743 /// This function naively concatenates a query string to `uri` and if `uri` already has
744 /// a query part, it will have a duplicate query part like `?foo=bar?baz=qux`.
745 #[cfg(feature = "alloc")]
746 pub fn to_query<R>(uri: String, request: &R) -> String
747 where
748 R: Request + ?Sized,
749 {
750 request.serialize(serializer::Urlencoder::query(uri))
751 }
752}