1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use crate::urlencode::BASE_SET;
use aws_smithy_types::date_time::{DateTimeFormatError, Format};
use aws_smithy_types::DateTime;
use percent_encoding::utf8_percent_encode;
pub fn fmt_string<T: AsRef<str>>(t: T) -> String {
utf8_percent_encode(t.as_ref(), BASE_SET).to_string()
}
pub fn fmt_timestamp(t: &DateTime, format: Format) -> Result<String, DateTimeFormatError> {
Ok(fmt_string(t.fmt(format)?))
}
pub struct Writer<'a> {
out: &'a mut String,
prefix: char,
}
impl<'a> Writer<'a> {
pub fn new(out: &'a mut String) -> Self {
Writer { out, prefix: '?' }
}
pub fn push_kv(&mut self, k: &str, v: &str) {
self.out.push(self.prefix);
self.out.push_str(k);
self.out.push('=');
self.out.push_str(v);
self.prefix = '&';
}
pub fn push_v(&mut self, v: &str) {
self.out.push(self.prefix);
self.out.push_str(v);
self.prefix = '&';
}
}
#[cfg(test)]
mod test {
use crate::query::{fmt_string, Writer};
use http::Uri;
use proptest::proptest;
#[test]
fn url_encode() {
assert_eq!(fmt_string("y̆").as_str(), "y%CC%86");
assert_eq!(fmt_string(" ").as_str(), "%20");
assert_eq!(fmt_string("foo/baz%20").as_str(), "foo%2Fbaz%2520");
assert_eq!(fmt_string("&=").as_str(), "%26%3D");
assert_eq!(fmt_string("🐱").as_str(), "%F0%9F%90%B1");
assert_eq!(fmt_string("a:b"), "a%3Ab")
}
#[test]
fn writer_sets_prefix_properly() {
let mut out = String::new();
let mut writer = Writer::new(&mut out);
writer.push_v("a");
writer.push_kv("b", "c");
assert_eq!(out, "?a&b=c");
}
proptest! {
#[test]
fn test_encode_request(s: String) {
let _: Uri = format!("http://host.example.com/?{}", fmt_string(&s)).parse().expect("all strings should be encoded properly");
}
}
}