File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -66,8 +66,44 @@ impl<T> From<std::io::Error> for Error<T> {
6666 }
6767}
6868
69+ fn hex_digit ( b : u8 ) -> Option < u8 > {
70+ match b {
71+ b'0' ..=b'9' => Some ( b - b'0' ) ,
72+ b'a' ..=b'f' => Some ( b - b'a' + 10 ) ,
73+ b'A' ..=b'F' => Some ( b - b'A' + 10 ) ,
74+ _ => None ,
75+ }
76+ }
77+
78+ fn parse_percent_encoded ( bytes : & [ u8 ; 3 ] ) -> Option < u8 > {
79+ if bytes[ 0 ] != b'%' { return None ; }
80+ let hi = hex_digit ( bytes[ 1 ] ) ?;
81+ let lo = hex_digit ( bytes[ 2 ] ) ?;
82+ Some ( ( hi << 4 ) | lo)
83+ }
84+
6985pub fn urlencode < T : AsRef < str > > ( s : T ) -> String {
70- :: url:: form_urlencoded:: byte_serialize ( s. as_ref ( ) . as_bytes ( ) ) . collect ( )
86+ :: url:: form_urlencoded:: byte_serialize ( s. as_ref ( ) . as_bytes ( ) )
87+ . map ( |string| {
88+ debug_assert ! (
89+ !string. starts_with( '%' ) || string. len( ) == 3 ,
90+ "the iterator should yield percent-encoded strings of exactly 3 bytes, or unescaped strings"
91+ ) ;
92+
93+ let parsed = match string. as_bytes ( ) . try_into ( ) {
94+ Ok ( bytes) => parse_percent_encoded ( bytes) ,
95+ Err ( _) => None ,
96+ } ;
97+
98+ // The VRChat API deviates from the application/x-www-form-urlencoded percent-encode set, for values like the InstanceID.
99+ // The characters bellow should remain unchanged for URI parameters, or requests will be rejected as malformed.
100+ match parsed {
101+ Some ( b'(' ) => "(" ,
102+ Some ( b')' ) => ")" ,
103+ _ => string
104+ }
105+ } )
106+ . collect ( )
71107}
72108
73109pub fn parse_deep_object ( prefix : & str , value : & serde_json:: Value ) -> Vec < ( String , String ) > {
Original file line number Diff line number Diff line change @@ -95,8 +95,44 @@ impl <T> From<std::io::Error> for Error<T> {
9595 }
9696}
9797
98+ fn hex_digit(b: u8) -> Option<u8 > {
99+ match b {
100+ b' 0' ..=b' 9' => Some(b - b' 0' ),
101+ b' a' ..=b' f' => Some(b - b' a' + 10),
102+ b' A' ..=b' F' => Some(b - b' A' + 10),
103+ _ => None,
104+ }
105+ }
106+
107+ fn parse_percent_encoded(bytes: & [u8; 3]) -> Option<u8 > {
108+ if bytes[0] != b' %' { return None; }
109+ let hi = hex_digit(bytes[1])?;
110+ let lo = hex_digit(bytes[2])?;
111+ Some((hi << 4) | lo)
112+ }
113+
98114pub fn urlencode<T: AsRef <str >>(s: T) -> String {
99- ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect()
115+ ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes())
116+ .map(|string| {
117+ debug_assert! (
118+ ! string.starts_with(' %' ) || string.len() == 3,
119+ " the iterator should yield percent-encoded strings of exactly 3 bytes, or unescaped strings"
120+ );
121+
122+ let parsed = match string.as_bytes().try_into() {
123+ Ok(bytes) => parse_percent_encoded(bytes),
124+ Err(_) => None,
125+ } ;
126+
127+ // The VRChat API deviates from the application/x-www-form-urlencoded percent-encode set, for values like the InstanceID.
128+ // The characters bellow should remain unchanged for URI parameters, or requests will be rejected as malformed.
129+ match parsed {
130+ Some(b' (' ) => " (" ,
131+ Some(b' )' ) => " )" ,
132+ _ => string
133+ }
134+ })
135+ .collect()
100136}
101137
102138pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> {
Original file line number Diff line number Diff line change @@ -118,8 +118,44 @@ impl <T> From<std::io::Error> for Error<T> {
118118 }
119119}
120120
121+ fn hex_digit(b: u8) -> Option<u8 > {
122+ match b {
123+ b' 0' ..=b' 9' => Some(b - b' 0' ),
124+ b' a' ..=b' f' => Some(b - b' a' + 10),
125+ b' A' ..=b' F' => Some(b - b' A' + 10),
126+ _ => None,
127+ }
128+ }
129+
130+ fn parse_percent_encoded(bytes: & [u8; 3]) -> Option<u8 > {
131+ if bytes[0] != b' %' { return None; }
132+ let hi = hex_digit(bytes[1])?;
133+ let lo = hex_digit(bytes[2])?;
134+ Some((hi << 4) | lo)
135+ }
136+
121137pub fn urlencode<T: AsRef <str >>(s: T) -> String {
122- ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect()
138+ ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes())
139+ .map(|string| {
140+ debug_assert! (
141+ ! string.starts_with(' %' ) || string.len() == 3,
142+ " the iterator should yield percent-encoded strings of exactly 3 bytes, or unescaped strings"
143+ );
144+
145+ let parsed = match string.as_bytes().try_into() {
146+ Ok(bytes) => parse_percent_encoded(bytes),
147+ Err(_) => None,
148+ } ;
149+
150+ // The VRChat API deviates from the application/x-www-form-urlencoded percent-encode set, for values like the InstanceID.
151+ // The characters bellow should remain unchanged for URI parameters, or requests will be rejected as malformed.
152+ match parsed {
153+ Some(b' (' ) => " (" ,
154+ Some(b' )' ) => " )" ,
155+ _ => string
156+ }
157+ })
158+ .collect()
123159}
124160
125161pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> {
You can’t perform that action at this time.
0 commit comments