oauth1_request/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.6", package = "oauth1-request" }
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 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::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 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 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/0.6.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 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::Request;
210}
211#[doc(no_inline)]
212pub use oauth_credentials::{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 = "rsa-sha1-06")]
221 pub use self::signature_method::RsaSha1;
222 #[cfg(feature = "rsa-sha1-09")]
223 pub use self::signature_method::Rsa09Sha1;
224 #[cfg(feature = "hmac-sha1")]
225 pub use self::signature_method::HMAC_SHA1;
226 #[cfg(feature = "alloc")]
227 pub use self::signature_method::PLAINTEXT;
228}
229
230#[cfg(feature = "alloc")]
231use alloc::string::String;
232use core::fmt::Debug;
233use core::fmt::{Display, Write};
234use core::num::NonZeroU64;
235use core::str;
236
237use self::serializer::auth;
238use self::signature_method::SignatureMethod;
239
240cfg_type_param_hack! {
241 /// A builder for OAuth `Authorization` header string.
242 #[derive(Clone, Debug)]
243 pub struct Builder<
244 'a,
245 SM,
246 #[cfg(feature = "alloc")] C = String,
247 #[cfg(not(feature = "alloc"))] C,
248 T = C,
249 > {
250 signature_method: SM,
251 client: Credentials<C>,
252 token: Option<Credentials<T>>,
253 options: auth::Options<'a>,
254 }
255}
256
257macro_rules! builder_authorize_shorthand {
258 ($($name:ident($method:expr);)*) => {doc_auto_cfg! {$(
259 #[doc = concat!("Authorizes a `", $method, "` request to `uri`,")]
260 /// returning an HTTP `Authorization` header value.
261 ///
262 /// `uri` must not contain a query part, which would result in a wrong signature.
263 #[cfg(feature = "alloc")]
264 pub fn $name<U, R>(&self, uri: U, request: &R) -> String
265 where
266 U: Display,
267 R: Request + ?Sized,
268 SM: Clone,
269 {
270 self.authorize($method, uri, request)
271 }
272 )*}};
273}
274
275macro_rules! builder_to_form_shorthand {
276 ($($name:ident($method:expr);)*) => {doc_auto_cfg! {$(
277 #[doc = concat!("Authorizes a `", $method, "` request to `uri`,")]
278 /// writing the OAuth protocol parameters to an `x-www-form-urlencoded` string
279 /// along with the other request parameters.
280 ///
281 /// `uri` must not contain a query part, which would result in a wrong signature.
282 #[cfg(feature = "alloc")]
283 pub fn $name<U, R>(&self, uri: U, request: &R) -> String
284 where
285 U: Display,
286 R: Request + ?Sized,
287 SM: Clone,
288 {
289 self.to_form($method, uri, request)
290 }
291 )*}};
292}
293
294macro_rules! builder_to_query_shorthand {
295 ($($name:ident($method:expr);)*) => {$(
296 doc_coerce_expr! {
297 #[doc = concat!("Authorizes a `", $method, "` request to `uri`, appending")]
298 /// the OAuth protocol parameters to `uri` along with the other request parameters.
299 ///
300 /// `uri` must not contain a query part, which would result in a wrong signature.
301 pub fn $name<W, R>(&self, uri: W, request: &R) -> W
302 where
303 W: Display + Write,
304 R: Request + ?Sized,
305 SM: Clone,
306 {
307 self.to_query($method, uri, request)
308 }
309 }
310 )*};
311}
312
313impl<'a, SM: SignatureMethod, C: AsRef<str>, T: AsRef<str>> Builder<'a, SM, C, T> {
314 /// Creates a `Builder` that signs requests using the specified client credentials
315 /// and signature method.
316 pub fn new(client: Credentials<C>, signature_method: SM) -> Self {
317 Builder {
318 signature_method,
319 client,
320 token: None,
321 options: auth::Options::new(),
322 }
323 }
324
325 /// Creates a `Builder` that uses the token credentials from `token`.
326 pub fn with_token(token: Token<C, T>, signature_method: SM) -> Self {
327 let mut ret = Builder::new(token.client, signature_method);
328 ret.token(token.token);
329 ret
330 }
331
332 /// Sets/unsets the token credentials pair to sign requests with.
333 pub fn token(&mut self, token: impl Into<Option<Credentials<T>>>) -> &mut Self {
334 self.token = token.into();
335 self
336 }
337
338 /// Sets/unsets the `oauth_callback` URI.
339 pub fn callback(&mut self, callback: impl Into<Option<&'a str>>) -> &mut Self {
340 self.options.callback(callback);
341 self
342 }
343
344 /// Sets/unsets the `oauth_verifier` value.
345 pub fn verifier(&mut self, verifier: impl Into<Option<&'a str>>) -> &mut Self {
346 self.options.verifier(verifier);
347 self
348 }
349
350 /// Sets/unsets the `oauth_nonce` value.
351 ///
352 /// By default, `Builder` generates a random nonce for each request.
353 /// This method overrides that behavior and forces the `Builder` to use the specified nonce.
354 ///
355 /// This method is for debugging/testing purpose only and should not be used in production.
356 pub fn nonce(&mut self, nonce: impl Into<Option<&'a str>>) -> &mut Self {
357 self.options.nonce(nonce);
358 self
359 }
360
361 /// Sets/unsets the `oauth_timestamp` value.
362 ///
363 /// By default, `Builder` uses the timestamp of the time when `authorize`-like method is called.
364 /// This method overrides that behavior and forces the `Builder` to use the specified timestamp.
365 ///
366 /// This method is for debugging/testing purpose only and should not be used in production.
367 pub fn timestamp(&mut self, timestamp: impl Into<Option<NonZeroU64>>) -> &mut Self {
368 self.options.timestamp(timestamp);
369 self
370 }
371
372 /// Sets whether to include the `oauth_version` value in requests.
373 pub fn version(&mut self, version: bool) -> &mut Self {
374 self.options.version(version);
375 self
376 }
377
378 builder_authorize_shorthand! {
379 get("GET");
380 put("PUT");
381 post("POST");
382 delete("DELETE");
383 options("OPTIONS");
384 head("HEAD");
385 connect("CONNECT");
386 patch("PATCH");
387 trace("TRACE");
388 }
389
390 builder_to_form_shorthand! {
391 put_form("PUT");
392 post_form("POST");
393 options_form("OPTIONS");
394 patch_form("PATCH");
395 }
396
397 builder_to_query_shorthand! {
398 get_query("GET");
399 put_query("PUT");
400 post_query("POST");
401 delete_query("DELETE");
402 options_query("OPTIONS");
403 head_query("HEAD");
404 connect_query("CONNECT");
405 patch_query("PATCH");
406 trace_query("TRACE");
407 }
408
409 doc_auto_cfg! {
410 /// Authorizes a request to `uri` with a custom HTTP request method,
411 /// returning an HTTP `Authorization` header value.
412 ///
413 /// `uri` must not contain a query part, which would result in a wrong signature.
414 #[cfg(feature = "alloc")]
415 pub fn authorize<U, R>(&self, method: &str, uri: U, request: &R) -> String
416 where
417 U: Display,
418 R: Request + ?Sized,
419 SM: Clone,
420 {
421 let serializer = serializer::auth::Authorizer::authorization(
422 method,
423 uri,
424 self.client.as_ref(),
425 self.token.as_ref().map(Credentials::as_ref),
426 &self.options,
427 self.signature_method.clone(),
428 );
429
430 request.serialize(serializer)
431 }
432
433 /// Authorizes a request to `uri` with a custom HTTP request method, writing the OAuth protocol
434 /// parameters to an `x-www-form-urlencoded` string along with the other request parameters.
435 ///
436 /// `uri` must not contain a query part, which would result in a wrong signature.
437 #[cfg(feature = "alloc")]
438 pub fn to_form<U, R>(&self, method: &str, uri: U, request: &R) -> String
439 where
440 U: Display,
441 R: Request + ?Sized,
442 SM: Clone,
443 {
444 let serializer = serializer::auth::Authorizer::form(
445 method,
446 uri,
447 self.client.as_ref(),
448 self.token.as_ref().map(Credentials::as_ref),
449 &self.options,
450 self.signature_method.clone(),
451 );
452
453 request.serialize(serializer)
454 }
455 }
456
457 /// Authorizes a request to `uri` with a custom HTTP request method, appending the OAuth
458 /// protocol parameters to `uri` along with the other request parameters.
459 ///
460 /// `uri` must not contain a query part, which would result in a wrong signature.
461 pub fn to_query<W, R>(&self, method: &str, uri: W, request: &R) -> W
462 where
463 W: Display + Write,
464 R: Request + ?Sized,
465 SM: Clone,
466 {
467 let serializer = serializer::auth::Authorizer::query(
468 method,
469 uri,
470 self.client.as_ref(),
471 self.token.as_ref().map(Credentials::as_ref),
472 &self.options,
473 self.signature_method.clone(),
474 );
475
476 request.serialize(serializer)
477 }
478
479 /// Same as `authorize` except that this writes the resulting `Authorization` header value
480 /// into `buf`.
481 pub fn authorize_with_buf<W, U, R>(&self, buf: W, method: &str, uri: U, request: &R) -> W
482 where
483 W: Write,
484 U: Display,
485 R: Request + ?Sized,
486 SM: Clone,
487 {
488 let serializer = serializer::auth::Authorizer::authorization_with_buf(
489 buf,
490 method,
491 uri,
492 self.client.as_ref(),
493 self.token.as_ref().map(Credentials::as_ref),
494 &self.options,
495 self.signature_method.clone(),
496 );
497
498 request.serialize(serializer)
499 }
500
501 doc_auto_cfg! {
502 /// Same as `to_form` except that this writes the resulting `x-www-form-urlencoded` string
503 /// into `buf`.
504 #[cfg(feature = "alloc")]
505 pub fn to_form_with_buf<W, U, R>(&self, buf: W, method: &str, uri: U, request: &R) -> W
506 where
507 W: Write,
508 U: Display,
509 R: Request + ?Sized,
510 SM: Clone,
511 {
512 let serializer = serializer::auth::Authorizer::form_with_buf(
513 buf,
514 method,
515 uri,
516 self.client.as_ref(),
517 self.token.as_ref().map(Credentials::as_ref),
518 &self.options,
519 self.signature_method.clone(),
520 );
521
522 request.serialize(serializer)
523 }
524
525 /// Authorizes a request and consumes `self`, returning an HTTP `Authorization` header value.
526 ///
527 /// Unlike `authorize`, this does not clone the signature method and may be more efficient for
528 /// non-`Copy` signature methods like `RsaSha1`.
529 ///
530 /// For `HmacSha1`, `&RsaSha1` and `Plaintext`, cloning is no-op or very cheap so you should
531 /// use `authorize` instead.
532 #[cfg(feature = "alloc")]
533 pub fn into_authorization<U, R>(self, method: &str, uri: U, request: &R) -> String
534 where
535 U: Display,
536 R: Request + ?Sized,
537 {
538 let serializer = serializer::auth::Authorizer::authorization(
539 method,
540 uri,
541 self.client.as_ref(),
542 self.token.as_ref().map(Credentials::as_ref),
543 &self.options,
544 self.signature_method,
545 );
546
547 request.serialize(serializer)
548 }
549
550 /// Authorizes a request and consumes `self`, writing the OAuth protocol parameters to
551 /// an `x-www-form-urlencoded` string along with the other request parameters.
552 ///
553 /// Unlike `to_form`, this does not clone the signature method and may be more efficient for
554 /// non-`Copy` signature methods like `RsaSha1`.
555 ///
556 /// For `HmacSha1`, `&RsaSha1` and `Plaintext`, cloning is no-op or very cheap so you should
557 /// use `to_form` instead.
558 #[cfg(feature = "alloc")]
559 pub fn into_form<U, R>(self, method: &str, uri: U, request: &R) -> String
560 where
561 U: Display,
562 R: Request + ?Sized,
563 {
564 let serializer = serializer::auth::Authorizer::form(
565 method,
566 uri,
567 self.client.as_ref(),
568 self.token.as_ref().map(Credentials::as_ref),
569 &self.options,
570 self.signature_method,
571 );
572
573 request.serialize(serializer)
574 }
575 }
576
577 /// Authorizes a request and consumes `self`, appending the OAuth protocol parameters to
578 /// `uri` along with the other request parameters.
579 ///
580 /// Unlike `to_query`, this does not clone the signature method and may be more efficient for
581 /// non-`Copy` signature methods like `RsaSha1`.
582 ///
583 /// For `HmacSha1`, `&RsaSha1` and `Plaintext`, cloning is no-op or very cheap so you should
584 /// use `to_query` instead.
585 pub fn into_query<W, R>(self, method: &str, uri: W, request: &R) -> W
586 where
587 W: Display + Write,
588 R: Request + ?Sized,
589 {
590 let serializer = serializer::auth::Authorizer::query(
591 method,
592 uri,
593 self.client.as_ref(),
594 self.token.as_ref().map(Credentials::as_ref),
595 &self.options,
596 self.signature_method,
597 );
598
599 request.serialize(serializer)
600 }
601
602 /// Same as `into_authorization` except that this writes the resulting `Authorization` header
603 /// value into `buf`.
604 pub fn into_authorization_with_buf<W, U, R>(
605 self,
606 buf: W,
607 method: &str,
608 uri: U,
609 request: &R,
610 ) -> W
611 where
612 W: Write,
613 U: Display,
614 R: Request + ?Sized,
615 SM: Clone,
616 {
617 let serializer = serializer::auth::Authorizer::authorization_with_buf(
618 buf,
619 method,
620 uri,
621 self.client.as_ref(),
622 self.token.as_ref().map(Credentials::as_ref),
623 &self.options,
624 self.signature_method,
625 );
626
627 request.serialize(serializer)
628 }
629
630 /// Same as `into_form` except that this writes the resulting `x-www-form-urlencoded` string
631 /// into `buf`.
632 pub fn into_form_with_buf<W, U, R>(self, buf: W, method: &str, uri: U, request: &R) -> W
633 where
634 W: Write,
635 U: Display,
636 R: Request + ?Sized,
637 {
638 let serializer = serializer::auth::Authorizer::form_with_buf(
639 buf,
640 method,
641 uri,
642 self.client.as_ref(),
643 self.token.as_ref().map(Credentials::as_ref),
644 &self.options,
645 self.signature_method,
646 );
647
648 request.serialize(serializer)
649 }
650}
651
652macro_rules! authorize_shorthand {
653 ($($name:ident($method:expr);)*) => {doc_auto_cfg! {$(
654 #[doc = concat!("Authorizes a `", $method, "` request to `uri` with the given credentials.")]
655 ///
656 /// This returns an HTTP `Authorization` header value.
657 ///
658 /// `uri` must not contain a query part, which would result in a wrong signature.
659 #[cfg(feature = "alloc")]
660 pub fn $name<U, R, C, T, SM>(
661 uri: U,
662 request: &R,
663 token: &Token<C, T>,
664 signature_method: SM,
665 ) -> String
666 where
667 U: Display,
668 R: Request + ?Sized,
669 C: AsRef<str>,
670 T: AsRef<str>,
671 SM: SignatureMethod,
672 {
673 authorize($method, uri, request, token, signature_method)
674 }
675 )*}};
676}
677
678authorize_shorthand! {
679 get("GET");
680 put("PUT");
681 post("POST");
682 delete("DELETE");
683 options("OPTIONS");
684 head("HEAD");
685 connect("CONNECT");
686 patch("PATCH");
687 trace("TRACE");
688}
689
690doc_auto_cfg! {
691 /// Authorizes a request to `uri` with the given credentials.
692 ///
693 /// This returns an HTTP `Authorization` header value.
694 ///
695 /// `uri` must not contain a query part, which would result in a wrong signature.
696 #[cfg(feature = "alloc")]
697 pub fn authorize<U, R, C, T, SM>(
698 method: &str,
699 uri: U,
700 request: &R,
701 token: &Token<C, T>,
702 signature_method: SM,
703 ) -> String
704 where
705 U: Display,
706 R: Request + ?Sized,
707 C: AsRef<str>,
708 T: AsRef<str>,
709 SM: SignatureMethod,
710 {
711 fn inner<U, R, SM>(
712 method: &str,
713 uri: U,
714 request: &R,
715 token: Token<&str, &str>,
716 signature_method: SM,
717 ) -> String
718 where
719 U: Display,
720 R: Request + ?Sized,
721 SM: SignatureMethod,
722 {
723 Builder::with_token(token, signature_method).into_authorization(method, uri, request)
724 }
725 inner(method, uri, request, token.as_ref(), signature_method)
726 }
727
728 /// Serializes a `Request` to an `x-www-form-urlencoded` string.
729 #[cfg(feature = "alloc")]
730 pub fn to_form<R>(request: &R) -> String
731 where
732 R: Request + ?Sized,
733 {
734 request.serialize(serializer::Urlencoder::form())
735 }
736
737 /// Serializes a `Request` to a query string and appends it to the given URI.
738 ///
739 /// This function naively concatenates a query string to `uri` and if `uri` already has
740 /// a query part, it will have a duplicate query part like `?foo=bar?baz=qux`.
741 #[cfg(feature = "alloc")]
742 pub fn to_query<R>(uri: String, request: &R) -> String
743 where
744 R: Request + ?Sized,
745 {
746 request.serialize(serializer::Urlencoder::query(uri))
747 }
748}