@@ -49,4 +49,75 @@ public void Generates_correct_signature_base() {
4949 "POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&include_entities%3Dtrue%26oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26oauth_version%3D1.0%26status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521"
5050 ) ;
5151 }
52+
53+ [ Fact ]
54+ public void Handles_path_with_exclamation_mark ( ) {
55+ // Test that a path segment with ! is encoded correctly in the signature base
56+ var client = new RestClient ( "https://api.example.com" ) ;
57+ var request = new RestRequest ( "path/with!exclamation/resource" , Method . Get ) ;
58+
59+ const string method = "GET" ;
60+ var url = client . BuildUri ( request ) . ToString ( ) ;
61+ var parameters = new WebPairCollection ( ) ;
62+
63+ _workflow . RequestUrl = url ;
64+ var oauthParameters = _workflow . BuildProtectedResourceSignature ( method , parameters ) ;
65+
66+ var signatureBase = OAuthTools . ConcatenateRequestElements ( method , url , oauthParameters . Parameters ) ;
67+
68+ // The URL should be encoded with ! as %21 in the signature base
69+ signatureBase . Should ( ) . Contain ( "path%2Fwith%21exclamation%2Fresource" ) ;
70+ }
71+
72+ [ Theory ]
73+ [ InlineData ( "path/with!exclamation" , "%21" ) ]
74+ [ InlineData ( "path/with*asterisk" , "%2A" ) ]
75+ [ InlineData ( "path/with'apostrophe" , "%27" ) ]
76+ [ InlineData ( "path/with(paren" , "%28" ) ]
77+ [ InlineData ( "path/with)paren" , "%29" ) ]
78+ public void Encodes_RFC3986_special_chars_in_path ( string path , string encodedChar ) {
79+ // Test that RFC 3986 special characters are properly encoded in path segments
80+ var client = new RestClient ( "https://api.example.com" ) ;
81+ var request = new RestRequest ( path , Method . Get ) ;
82+
83+ const string method = "GET" ;
84+ var url = client . BuildUri ( request ) . ToString ( ) ;
85+ var parameters = new WebPairCollection ( ) ;
86+
87+ _workflow . RequestUrl = url ;
88+ var oauthParameters = _workflow . BuildProtectedResourceSignature ( method , parameters ) ;
89+
90+ var signatureBase = OAuthTools . ConcatenateRequestElements ( method , url , oauthParameters . Parameters ) ;
91+
92+ // The URL should contain the encoded character in the signature base
93+ signatureBase . Should ( ) . Contain ( encodedChar ) ;
94+ }
95+
96+ [ Theory ]
97+ [ InlineData ( "with!exclamation" ) ]
98+ [ InlineData ( "with*asterisk" ) ]
99+ [ InlineData ( "with'apostrophe" ) ]
100+ [ InlineData ( "with(paren" ) ]
101+ [ InlineData ( "with)paren" ) ]
102+ public void Handles_url_segment_with_RFC3986_special_chars ( string segmentValue ) {
103+ // Test that URL segment parameters with RFC 3986 special characters don't get double-encoded
104+ var client = new RestClient ( "https://api.example.com" ) ;
105+ var request = new RestRequest ( "path/{segment}/resource" , Method . Get ) ;
106+ request . AddUrlSegment ( "segment" , segmentValue ) ;
107+
108+ const string method = "GET" ;
109+ var url = client . BuildUri ( request ) . ToString ( ) ;
110+ var parameters = new WebPairCollection ( ) ;
111+
112+ _workflow . RequestUrl = url ;
113+ var oauthParameters = _workflow . BuildProtectedResourceSignature ( method , parameters ) ;
114+
115+ var signatureBase = OAuthTools . ConcatenateRequestElements ( method , url , oauthParameters . Parameters ) ;
116+
117+ // The signature base should NOT contain double-encoded characters like %2521 (which is %25 + 21)
118+ signatureBase . Should ( ) . NotContain ( "%25" ) ;
119+
120+ // But it should contain properly encoded special chars
121+ signatureBase . Should ( ) . MatchRegex ( "%2[0-9A-F]" ) ;
122+ }
52123}
0 commit comments