4545#include "cfg/cfg_int.h"
4646#include "cfg/provider.h"
4747#include "helper.h"
48+ #include "http.h"
49+ #include <curl/curl.h>
4850
4951START_TEST (test_http_accept ) {
5052 request_rec * r = oidc_test_request_get ();
@@ -105,14 +107,218 @@ START_TEST(test_http_accept) {
105107}
106108END_TEST
107109
110+ START_TEST (test_url_encode_decode ) {
111+ request_rec * r = oidc_test_request_get ();
112+ const char * in = "a b+c%/&=~" ;
113+ char * enc = oidc_http_url_encode (r , in );
114+ ck_assert_ptr_nonnull (enc );
115+ char * dec = oidc_http_url_decode (r , enc );
116+ ck_assert_ptr_nonnull (dec );
117+ ck_assert_msg (_oidc_strcmp (dec , in ) == 0 , "decoded value matches original" );
118+ }
119+ END_TEST
120+
121+ START_TEST (test_hdr_getters_and_forwarded ) {
122+ request_rec * r = oidc_test_request_get ();
123+ apr_table_set (r -> headers_in , "User-Agent" , "MyAgent/1.0" );
124+ apr_table_set (r -> headers_in , "Content-Type" , "text/plain" );
125+ apr_table_set (r -> headers_in , "Content-Length" , "123" );
126+ apr_table_set (r -> headers_in , "X-Forwarded-For" , "192.0.2.1, 10.0.0.1" );
127+ apr_table_set (r -> headers_in , "X-Forwarded-Host" , "host1, host2" );
128+ apr_table_set (r -> headers_in , "Forwarded" , "for=192.0.2.60; proto=http; by=203.0.113.43" );
129+
130+ ck_assert_ptr_nonnull (oidc_http_hdr_in_user_agent_get (r ));
131+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_user_agent_get (r ), "MyAgent/1.0" ) == 0 , "user-agent matches" );
132+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_content_type_get (r ), "text/plain" ) == 0 , "content-type matches" );
133+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_content_length_get (r ), "123" ) == 0 , "content-length matches" );
134+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_x_forwarded_for_get (r ), "192.0.2.1" ) == 0 ,
135+ "left-most X-Forwarded-For returned" );
136+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_x_forwarded_host_get (r ), "host1" ) == 0 ,
137+ "left-most X-Forwarded-Host returned" );
138+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_forwarded_get (r , "proto" ), "http" ) == 0 , "forwarded proto parsed" );
139+ }
140+ END_TEST
141+
142+ START_TEST (test_hdr_normalize_query_form ) {
143+ request_rec * r = oidc_test_request_get ();
144+ const char * name = "X(Invalid):Header/Name\t" ;
145+ char * norm = oidc_http_hdr_normalize_name (r , name );
146+ ck_assert_ptr_nonnull (norm );
147+ // ensure separators replaced by '-'
148+ ck_assert_msg (_oidc_strstr (norm , "-" ) != NULL , "normalized contains '-' character" );
149+
150+ apr_table_t * params = apr_table_make (r -> pool , 3 );
151+ apr_table_set (params , "a" , "1" );
152+ apr_table_set (params , "b c" , "d/e" );
153+ char * qurl = oidc_http_query_encoded_url (r , "https://example.com/path" , params );
154+ ck_assert_ptr_nonnull (qurl );
155+ // should contain 'a=1' and encoded b+c
156+ ck_assert_msg (_oidc_strstr (qurl , "a=1" ) != NULL , "query contains a=1" );
157+ ck_assert_msg (_oidc_strstr (qurl , "b+c=" ) != NULL || _oidc_strstr (qurl , "b%20c=" ) != NULL ,
158+ "query contains encoded b c key" );
159+
160+ char * form = oidc_http_form_encoded_data (r , params );
161+ ck_assert_ptr_nonnull (form );
162+ ck_assert_msg (_oidc_strstr (form , "a=1" ) != NULL , "form contains a=1" );
163+ }
164+ END_TEST
165+
166+ START_TEST (test_cookies_and_chunking ) {
167+ request_rec * r = oidc_test_request_get ();
168+ // existing cookie from helper: foo=bar; mod_auth_openidc_session=0123456789abcdef; baz=zot
169+ char * v = oidc_http_get_cookie (r , "foo" );
170+ ck_assert_ptr_nonnull (v );
171+ ck_assert_msg (_oidc_strcmp (v , "bar" ) == 0 , "foo cookie value is bar" );
172+
173+ // set up chunked cookies in headers_in to simulate browser
174+ const char * cookie_header = "big=; big_chunks=3; big_0=AAA; big_1=BBB; big_2=CCC" ;
175+ apr_table_set (r -> headers_in , "Cookie" , cookie_header );
176+ char * big = oidc_http_get_chunked_cookie (r , "big" , 5 );
177+ ck_assert_ptr_nonnull (big );
178+ ck_assert_msg (_oidc_strcmp (big , "AAABBBCCC" ) == 0 , "chunked cookie reconstructed" );
179+ }
180+ END_TEST
181+
182+ START_TEST (test_proxy_options_and_s2auth ) {
183+ const char * * opts = oidc_http_proxy_auth_options ();
184+ ck_assert_ptr_nonnull (opts );
185+ int found_basic = 0 , found_digest = 0 , found_ntlm = 0 , found_any = 0 ;
186+ for (int i = 0 ; opts [i ] != NULL ; i ++ ) {
187+ if (_oidc_strcmp (opts [i ], OIDC_HTTP_PROXY_AUTH_BASIC ) == 0 )
188+ found_basic = 1 ;
189+ if (_oidc_strcmp (opts [i ], OIDC_HTTP_PROXY_AUTH_DIGEST ) == 0 )
190+ found_digest = 1 ;
191+ if (_oidc_strcmp (opts [i ], OIDC_HTTP_PROXY_AUTH_NTLM ) == 0 )
192+ found_ntlm = 1 ;
193+ if (_oidc_strcmp (opts [i ], OIDC_HTTP_PROXY_AUTH_ANY ) == 0 )
194+ found_any = 1 ;
195+ }
196+ ck_assert_msg (found_basic && found_digest && found_ntlm && found_any , "proxy options include expected values" );
197+
198+ unsigned long v ;
199+ v = oidc_http_proxy_s2auth (OIDC_HTTP_PROXY_AUTH_BASIC );
200+ ck_assert_msg (v == CURLAUTH_BASIC , "basic maps to CURLAUTH_BASIC" );
201+ v = oidc_http_proxy_s2auth (OIDC_HTTP_PROXY_AUTH_DIGEST );
202+ ck_assert_msg (v == CURLAUTH_DIGEST , "digest maps to CURLAUTH_DIGEST" );
203+ v = oidc_http_proxy_s2auth (OIDC_HTTP_PROXY_AUTH_NTLM );
204+ ck_assert_msg (v == CURLAUTH_NTLM , "ntlm maps to CURLAUTH_NTLM" );
205+ v = oidc_http_proxy_s2auth ("no-such" );
206+ ck_assert_msg (v == CURLAUTH_NONE , "unknown maps to CURLAUTH_NONE" );
207+ }
208+ END_TEST
209+
210+ START_TEST (test_hdr_setters_and_cookie_set ) {
211+ request_rec * r = oidc_test_request_get ();
212+ oidc_http_hdr_in_set (r , "X-Test-Header" , "test-val" );
213+ ck_assert_msg (_oidc_strcmp (apr_table_get (r -> headers_in , "X-Test-Header" ), "test-val" ) == 0 ,
214+ "header in set/get works" );
215+
216+ oidc_http_hdr_in_cookie_set (r , "a=b;c=d" );
217+ ck_assert_ptr_nonnull (oidc_http_hdr_in_cookie_get (r ));
218+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_cookie_get (r ), "a=b;c=d" ) == 0 , "cookie header set/get works" );
219+ }
220+ END_TEST
221+
222+ START_TEST (test_hdr_out_location_and_traceparent ) {
223+ request_rec * r = oidc_test_request_get ();
224+ oidc_http_hdr_out_location_set (r , "https://example.com/redirect" );
225+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_out_location_get (r ), "https://example.com/redirect" ) == 0 ,
226+ "location out set/get works" );
227+
228+ apr_table_set (r -> headers_in , "traceparent" , "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" );
229+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_traceparent_get (r ),
230+ "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" ) == 0 ,
231+ "traceparent get works" );
232+ }
233+ END_TEST
234+
235+ START_TEST (test_set_cookie_and_chunked_set ) {
236+ request_rec * r = oidc_test_request_get ();
237+ apr_time_t expires = apr_time_now () + apr_time_from_sec (3600 );
238+
239+ oidc_http_set_cookie (r , "sname" , "svalue" , expires , "SameSite=Lax" );
240+ const apr_array_header_t * h = apr_table_elts (r -> err_headers_out );
241+ apr_table_entry_t * elts = (apr_table_entry_t * )h -> elts ;
242+ int found = 0 ;
243+ for (int i = 0 ; i < h -> nelts ; i ++ ) {
244+ if (_oidc_strstr (elts [i ].key , "Set-Cookie" ) || _oidc_strstr (elts [i ].val , "sname=svalue" )) {
245+ if (_oidc_strstr (elts [i ].val , "sname=svalue" )) {
246+ found = 1 ;
247+ break ;
248+ }
249+ }
250+ }
251+ ck_assert_msg (found == 1 , "Set-Cookie header contains our cookie" );
252+
253+ /* test chunked cookie */
254+ char large [1024 ];
255+ for (int i = 0 ; i < 1000 ; i ++ )
256+ large [i ] = 'A' + (i % 26 );
257+ large [1000 ] = '\0' ;
258+ oidc_http_set_chunked_cookie (r , "chunked" , large , expires , 100 , "SameSite=Lax" );
259+ /* ensure chunk counter cookie present in err_headers_out */
260+ h = apr_table_elts (r -> err_headers_out );
261+ elts = (apr_table_entry_t * )h -> elts ;
262+ int found_cnt = 0 ;
263+ for (int i = 0 ; i < h -> nelts ; i ++ ) {
264+ if (_oidc_strstr (elts [i ].val , "chunked_chunks=" )) {
265+ found_cnt = 1 ;
266+ break ;
267+ }
268+ }
269+ ck_assert_msg (found_cnt == 1 , "chunked counter cookie set" );
270+ }
271+ END_TEST
272+
273+ START_TEST (test_other_header_getters ) {
274+ request_rec * r = oidc_test_request_get ();
275+ apr_table_set (r -> headers_in , "X-Requested-With" , "XMLHttpRequest" );
276+ apr_table_set (r -> headers_in , "Sec-Fetch-Mode" , "navigate" );
277+ apr_table_set (r -> headers_in , "Sec-Fetch-Dest" , "document" );
278+ apr_table_set (r -> headers_in , "Authorization" , "Bearer tok123" );
279+ apr_table_set (r -> headers_in , "X-Forwarded-Proto" , "https, http" );
280+ apr_table_set (r -> headers_in , "X-Forwarded-Port" , "443, 80" );
281+ apr_table_set (r -> headers_in , "Host" , "host.example.com" );
282+
283+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_x_requested_with_get (r ), "XMLHttpRequest" ) == 0 ,
284+ "X-Requested-With matches" );
285+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_sec_fetch_mode_get (r ), "navigate" ) == 0 , "Sec-Fetch-Mode matches" );
286+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_sec_fetch_dest_get (r ), "document" ) == 0 , "Sec-Fetch-Dest matches" );
287+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_authorization_get (r ), "Bearer tok123" ) == 0 ,
288+ "Authorization matches" );
289+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_x_forwarded_proto_get (r ), "https" ) == 0 ,
290+ "X-Forwarded-Proto left-most matches" );
291+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_x_forwarded_port_get (r ), "443" ) == 0 ,
292+ "X-Forwarded-Port left-most matches" );
293+ ck_assert_msg (_oidc_strcmp (oidc_http_hdr_in_host_get (r ), "host.example.com" ) == 0 , "Host header matches" );
294+ }
295+ END_TEST
296+
297+ START_TEST (test_init_and_cleanup_noop ) {
298+ oidc_http_init ();
299+ oidc_http_cleanup ();
300+ ck_assert_msg (1 == 1 , "init/cleanup execute without crash" );
301+ }
302+ END_TEST
303+
108304int main (void ) {
109305 TCase * accept = tcase_create ("accept" );
110306 tcase_add_checked_fixture (accept , oidc_test_setup , oidc_test_teardown );
111307
112308 tcase_add_test (accept , test_http_accept );
309+ tcase_add_test (accept , test_url_encode_decode );
310+ tcase_add_test (accept , test_hdr_getters_and_forwarded );
311+ tcase_add_test (accept , test_hdr_normalize_query_form );
312+ tcase_add_test (accept , test_cookies_and_chunking );
313+ tcase_add_test (accept , test_proxy_options_and_s2auth );
314+ tcase_add_test (accept , test_hdr_setters_and_cookie_set );
315+ tcase_add_test (accept , test_hdr_out_location_and_traceparent );
316+ tcase_add_test (accept , test_set_cookie_and_chunked_set );
317+ tcase_add_test (accept , test_other_header_getters );
318+ tcase_add_test (accept , test_init_and_cleanup_noop );
113319
114320 Suite * s = suite_create ("http" );
115321 suite_add_tcase (s , accept );
116322
117323 return oidc_test_suite_run (s );
118- }
324+ }
0 commit comments