8 #include "common/ceph_crypto.h"
11 #define S3_BUCKET_NAME "s3testgw.fcgi"
12 #define SWIFT_BUCKET_NAME "swift3testgw.fcgi"
14 ((g_test->get_key_type() == KEY_TYPE_S3)?(string("/" S3_BUCKET_NAME)):(string("/swift/v1/" SWIFT_BUCKET_NAME)))
15 #include <gtest/gtest.h>
16 #include "common/code_environment.h"
17 #include "common/ceph_argparse.h"
18 #include "common/Finisher.h"
19 #include "global/global_init.h"
21 #include "rgw_cors_s3.h"
25 #define CURL_VERBOSE 0
26 #define HTTP_RESPONSE_STR "RespCode"
27 #define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20
29 extern "C" int ceph_armor(char *dst
, const char *dst_end
,
30 const char *src
, const char *end
);
32 KEY_TYPE_UNDEFINED
= 0,
37 static void print_usage(char *exec
){
38 cout
<< "Usage: " << exec
<< " <Options>\n";
40 "-g <gw-ip> - The ip address of the gateway\n"
41 "-p <gw-port> - The port number of the gateway\n"
42 "-k <SWIFT|S3> - The key type, either SWIFT or S3\n"
43 "-s3 <AWSAccessKeyId:SecretAccessKeyID> - Only, if the key type is S3, gives S3 credentials\n"
44 "-swift <Auth-Token> - Only if the key type is SWIFT, and gives the SWIFT credentials\n";
46 class test_cors_helper
{
52 map
<string
, string
> response
;
53 list
<string
> extra_hdrs
;
58 test_cors_helper() : curl_inst(NULL
), resp_data(NULL
), resp_code(0), kt(KEY_TYPE_UNDEFINED
){
59 curl_global_init(CURL_GLOBAL_ALL
);
62 curl_global_cleanup();
64 int send_request(string method
, string uri
,
65 size_t (*function
)(void *,size_t,size_t,void *) = 0,
66 void *ud
= 0, size_t length
= 0);
67 int extract_input(unsigned argc
, char *argv
[]);
68 string
& get_response(string hdr
){
71 void set_extra_header(string hdr
){
72 extra_hdrs
.push_back(hdr
);
74 void set_response(char *val
);
75 void set_response_data(char *data
, size_t len
){
76 if(resp_data
) delete resp_data
;
77 resp_data
= new string(data
, len
);
78 /*cout << resp_data->c_str() << "\n";*/
80 const string
*get_response_data(){return resp_data
;}
81 unsigned get_resp_code(){return resp_code
;}
82 key_type
get_key_type(){return kt
;}
85 int test_cors_helper::extract_input(unsigned argc
, char *argv
[]){
86 #define ERR_CHECK_NEXT_PARAM(o) \
87 if((loop + 1) >= argc)return -1; \
88 else o = argv[loop+1];
90 for(unsigned loop
= 1;loop
< argc
; loop
+= 2){
91 if(strcmp(argv
[loop
], "-g") == 0){
92 ERR_CHECK_NEXT_PARAM(host
);
93 }else if(strcmp(argv
[loop
], "-k") == 0){
95 ERR_CHECK_NEXT_PARAM(type
);
96 if(type
.compare("S3") == 0)kt
= KEY_TYPE_S3
;
97 else if(type
.compare("SWIFT") == 0)kt
= KEY_TYPE_SWIFT
;
98 }else if(strcmp(argv
[loop
],"-s3") == 0){
99 ERR_CHECK_NEXT_PARAM(creds
);
100 }else if(strcmp(argv
[loop
],"-swift") == 0){
101 ERR_CHECK_NEXT_PARAM(creds
);
102 }else if(strcmp(argv
[loop
],"-p") == 0){
103 ERR_CHECK_NEXT_PARAM(port
);
106 if(host
.empty() || creds
.empty())
111 void test_cors_helper::set_response(char *r
){
113 size_t off
= sr
.find(": ");
114 if(off
!= string::npos
){
115 h
.assign(sr
, 0, off
);
116 v
.assign(sr
, off
+ 2, sr
.find("\r\n") - (off
+2));
118 /*Could be the status code*/
119 if(sr
.find("HTTP/") != string::npos
){
120 h
.assign(HTTP_RESPONSE_STR
);
122 v
.assign(sr
, off
+ 1, sr
.find("\r\n") - (off
+ 1));
123 resp_code
= atoi((v
.substr(0, 3)).c_str());
129 size_t write_header(void *ptr
, size_t size
, size_t nmemb
, void *ud
){
130 test_cors_helper
*h
= static_cast<test_cors_helper
*>(ud
);
131 h
->set_response((char *)ptr
);
135 size_t write_data(void *ptr
, size_t size
, size_t nmemb
, void *ud
){
136 test_cors_helper
*h
= static_cast<test_cors_helper
*>(ud
);
137 h
->set_response_data((char *)ptr
, size
*nmemb
);
140 static inline void buf_to_hex(const unsigned char *buf
, int len
, char *str
)
144 for (i
= 0; i
< len
; i
++) {
145 sprintf(&str
[i
*2], "%02x", (int)buf
[i
]);
149 static void calc_hmac_sha1(const char *key
, int key_len
,
150 const char *msg
, int msg_len
, char *dest
)
151 /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */
153 ceph::crypto::HMACSHA1
hmac((const unsigned char *)key
, key_len
);
154 hmac
.Update((const unsigned char *)msg
, msg_len
);
155 hmac
.Final((unsigned char *)dest
);
157 char hex_str
[(CEPH_CRYPTO_HMACSHA1_DIGESTSIZE
* 2) + 1];
158 buf_to_hex((unsigned char *)dest
, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE
, hex_str
);
161 static int get_s3_auth(const string
&method
, string creds
, const string
&date
, const string
&res
, string
& out
){
162 string aid
, secret
, auth_hdr
;
163 size_t off
= creds
.find(":");
165 if(off
!= string::npos
){
166 aid
.assign(creds
, 0, off
);
167 secret
.assign(creds
, off
+ 1, string::npos
);
169 /*sprintf(auth_hdr, "%s\n\n\n%s\n%s", req_type, date, res);*/
170 char hmac_sha1
[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE
];
171 char b64
[65]; /* 64 is really enough */
172 auth_hdr
.append(method
+ string("\n\n\n") + date
+ string("\n") + res
);
173 calc_hmac_sha1(secret
.c_str(), secret
.length(), auth_hdr
.c_str(), auth_hdr
.length(), hmac_sha1
);
174 int ret
= ceph_armor(b64
, b64
+ 64, hmac_sha1
,
175 hmac_sha1
+ CEPH_CRYPTO_HMACSHA1_DIGESTSIZE
);
177 cout
<< "ceph_armor failed\n";
181 out
.append(aid
+ string(":") + b64
);
186 void get_date(string
& d
){
190 char *days
[] = {(char *)"Sun", (char *)"Mon", (char *)"Tue",
191 (char *)"Wed", (char *)"Thu", (char *)"Fri",
193 char *months
[] = {(char *)"Jan", (char *)"Feb", (char *)"Mar",
194 (char *)"Apr", (char *)"May", (char *)"Jun",
195 (char *)"Jul",(char *) "Aug", (char *)"Sep",
196 (char *)"Oct", (char *)"Nov", (char *)"Dec"};
197 gettimeofday(&tv
, NULL
);
198 gmtime_r(&tv
.tv_sec
, &tm
);
199 sprintf(date
, "%s, %d %s %d %d:%d:%d GMT",
201 tm
.tm_mday
, months
[tm
.tm_mon
],
203 tm
.tm_hour
, tm
.tm_min
, 0 /*tm.tm_sec*/);
207 int test_cors_helper::send_request(string method
, string res
,
208 size_t (*read_function
)( void *,size_t,size_t,void *),
213 url
.append(string("http://") + host
);
214 if(port
.length() > 0)url
.append(string(":") + port
);
216 curl_inst
= curl_easy_init();
218 curl_easy_setopt(curl_inst
, CURLOPT_URL
, url
.c_str());
219 curl_easy_setopt(curl_inst
, CURLOPT_CUSTOMREQUEST
, method
.c_str());
220 curl_easy_setopt(curl_inst
, CURLOPT_VERBOSE
, CURL_VERBOSE
);
221 curl_easy_setopt(curl_inst
, CURLOPT_HEADERFUNCTION
, write_header
);
222 curl_easy_setopt(curl_inst
, CURLOPT_WRITEHEADER
, (void *)this);
223 curl_easy_setopt(curl_inst
, CURLOPT_WRITEFUNCTION
, write_data
);
224 curl_easy_setopt(curl_inst
, CURLOPT_WRITEDATA
, (void *)this);
226 curl_easy_setopt(curl_inst
, CURLOPT_READFUNCTION
, read_function
);
227 curl_easy_setopt(curl_inst
, CURLOPT_READDATA
, (void *)ud
);
228 curl_easy_setopt(curl_inst
, CURLOPT_UPLOAD
, 1L);
229 curl_easy_setopt(curl_inst
, CURLOPT_INFILESIZE_LARGE
, (curl_off_t
)length
);
234 http_date
.append(string("Date: ") + date
);
235 if(kt
== KEY_TYPE_S3
){
237 if(get_s3_auth(method
, creds
, date
, res
, s3auth
) < 0)return -1;
238 auth
.append(string("Authorization: AWS ") + s3auth
);
239 } else if(kt
== KEY_TYPE_SWIFT
){
240 auth
.append(string("X-Auth-Token: ") + creds
);
242 cout
<< "Unknown state (" << kt
<< ")\n";
246 struct curl_slist
*slist
= NULL
;
247 slist
= curl_slist_append(slist
, auth
.c_str());
248 slist
= curl_slist_append(slist
, http_date
.c_str());
249 for(list
<string
>::iterator it
= extra_hdrs
.begin();
250 it
!= extra_hdrs
.end(); ++it
){
251 slist
= curl_slist_append(slist
, (*it
).c_str());
254 curl_slist_append(slist
, "Expect:");
255 curl_easy_setopt(curl_inst
, CURLOPT_HTTPHEADER
, slist
);
257 response
.erase(response
.begin(), response
.end());
258 extra_hdrs
.erase(extra_hdrs
.begin(), extra_hdrs
.end());
259 CURLcode res
= curl_easy_perform(curl_inst
);
261 cout
<< "Curl perform failed for " << url
<< ", res: " <<
262 curl_easy_strerror(res
) << "\n";
265 curl_slist_free_all(slist
);
267 curl_easy_cleanup(curl_inst
);
271 test_cors_helper
*g_test
;
274 static int create_bucket(void){
275 if(g_test
->get_key_type() == KEY_TYPE_S3
){
276 g_test
->send_request(string("PUT"), string("/" S3_BUCKET_NAME
));
277 if(g_test
->get_resp_code() != 200U){
278 cout
<< "Error creating bucket, http code " << g_test
->get_resp_code();
281 }else if(g_test
->get_key_type() == KEY_TYPE_SWIFT
){
282 g_test
->send_request(string("PUT"), string("/swift/v1/" SWIFT_BUCKET_NAME
));
283 if(g_test
->get_resp_code() != 201U){
284 cout
<< "Error creating bucket, http code " << g_test
->get_resp_code();
291 static int delete_bucket(void){
292 if(g_test
->get_key_type() == KEY_TYPE_S3
){
293 g_test
->send_request(string("DELETE"), string("/" S3_BUCKET_NAME
));
294 if(g_test
->get_resp_code() != 204U){
295 cout
<< "Error deleting bucket, http code " << g_test
->get_resp_code();
298 }else if(g_test
->get_key_type() == KEY_TYPE_SWIFT
){
299 g_test
->send_request(string("DELETE"), string("/swift/v1/" SWIFT_BUCKET_NAME
));
300 if(g_test
->get_resp_code() != 204U){
301 cout
<< "Error deleting bucket, http code " << g_test
->get_resp_code();
308 RGWCORSRule
*xml_to_cors_rule(string s
){
309 RGWCORSConfiguration_S3
*cors_config
;
310 const DoutPrefix
dp(g_ceph_context
, 1, "test cors: ");
311 RGWCORSXMLParser_S3
parser(&dp
, g_ceph_context
);
312 const string
*data
= g_test
->get_response_data();
313 if (!parser
.init()) {
316 if (!parser
.parse(data
->c_str(), data
->length(), 1)) {
319 cors_config
= (RGWCORSConfiguration_S3
*)parser
.find_first("CORSConfiguration");
323 return cors_config
->host_name_rule(s
.c_str());
326 size_t cors_read_xml(void *ptr
, size_t s
, size_t n
, void *ud
){
327 stringstream
*ss
= (stringstream
*)ud
;
328 size_t len
= ss
->str().length();
330 cout
<< "Cannot copy xml data, as len is not enough\n";
333 memcpy(ptr
, (void *)ss
->str().c_str(), len
);
337 void send_cors(set
<string
> o
, set
<string
> h
,
338 list
<string
> e
, uint8_t flags
,
340 if(g_test
->get_key_type() == KEY_TYPE_S3
){
341 RGWCORSRule
rule(o
, h
, e
, flags
, max_age
);
342 RGWCORSConfiguration config
;
343 config
.stack_rule(rule
);
345 RGWCORSConfiguration_S3
*s3
;
346 s3
= static_cast<RGWCORSConfiguration_S3
*>(&config
);
349 g_test
->send_request(string("PUT"), string("/" S3_BUCKET_NAME
"?cors"), cors_read_xml
,
350 (void *)&ss
, ss
.str().length());
351 }else if(g_test
->get_key_type() == KEY_TYPE_SWIFT
){
352 set
<string
>::iterator it
;
354 for(it
= o
.begin(); it
!= o
.end(); ++it
){
355 if(a_o
.length() > 0)a_o
.append(" ");
358 g_test
->set_extra_header(string("X-Container-Meta-Access-Control-Allow-Origin: ") + a_o
);
362 for(it
= h
.begin(); it
!= h
.end(); ++it
){
363 if(a_h
.length() > 0)a_h
.append(" ");
366 g_test
->set_extra_header(string("X-Container-Meta-Access-Control-Allow-Headers: ") + a_h
);
370 for(list
<string
>::iterator lit
= e
.begin(); lit
!= e
.end(); ++lit
){
371 if(e_h
.length() > 0)e_h
.append(" ");
374 g_test
->set_extra_header(string("X-Container-Meta-Access-Control-Expose-Headers: ") + e_h
);
376 if(max_age
!= CORS_MAX_AGE_INVALID
){
378 sprintf(age
, "%u", max_age
);
379 g_test
->set_extra_header(string("X-Container-Meta-Access-Control-Max-Age: ") + string(age
));
381 //const char *data = "1";
384 g_test
->send_request(string("POST"), string("/swift/v1/" SWIFT_BUCKET_NAME
), cors_read_xml
,
389 TEST(TestCORS
, getcors_firsttime
){
390 if(g_test
->get_key_type() == KEY_TYPE_SWIFT
)return;
391 ASSERT_EQ(0, create_bucket());
392 g_test
->send_request(string("GET"), string("/" S3_BUCKET_NAME
"?cors"));
393 EXPECT_EQ(404U, g_test
->get_resp_code());
394 ASSERT_EQ(0, delete_bucket());
397 TEST(TestCORS
, putcors_firsttime
){
398 ASSERT_EQ(0, create_bucket());
399 set
<string
> origins
, h
;
402 origins
.insert(origins
.end(), "example.com");
403 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
405 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
406 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
408 /*Now get the CORS and check if its fine*/
409 if(g_test
->get_key_type() == KEY_TYPE_S3
){
410 g_test
->send_request(string("GET"), string("/" S3_BUCKET_NAME
"?cors"));
411 EXPECT_EQ(200U, g_test
->get_resp_code());
413 RGWCORSRule
*r
= xml_to_cors_rule(string("example.com"));
414 EXPECT_TRUE(r
!= NULL
);
417 EXPECT_TRUE((r
->get_allowed_methods() & (RGW_CORS_GET
| RGW_CORS_PUT
))
418 == (RGW_CORS_GET
| RGW_CORS_PUT
));
420 ASSERT_EQ(0, delete_bucket());
423 TEST(TestCORS
, putcors_invalid_hostname
){
424 ASSERT_EQ(0, create_bucket());
425 set
<string
> origins
, h
;
428 origins
.insert(origins
.end(), "*.example.*");
429 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
430 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
431 EXPECT_EQ((400U), g_test
->get_resp_code());
432 origins
.erase(origins
.begin(), origins
.end());
434 if((g_test
->get_key_type() != KEY_TYPE_SWIFT
)){
435 origins
.insert(origins
.end(), "");
436 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
437 EXPECT_EQ((400U), g_test
->get_resp_code());
438 origins
.erase(origins
.begin(), origins
.end());
440 ASSERT_EQ(0, delete_bucket());
443 TEST(TestCORS
, putcors_invalid_headers
){
444 ASSERT_EQ(0, create_bucket());
445 set
<string
> origins
, h
;
448 origins
.insert(origins
.end(), "www.example.com");
449 h
.insert(h
.end(), "*-Header-*");
450 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
451 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
452 EXPECT_EQ((400U), g_test
->get_resp_code());
453 h
.erase(h
.begin(), h
.end());
455 if((g_test
->get_key_type() != KEY_TYPE_SWIFT
)){
456 h
.insert(h
.end(), "");
457 flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
458 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
459 EXPECT_EQ((400U), g_test
->get_resp_code());
460 h
.erase(h
.begin(), h
.end());
462 ASSERT_EQ(0, delete_bucket());
465 TEST(TestCORS
, optionscors_test_options_1
){
466 ASSERT_EQ(0, create_bucket());
467 set
<string
> origins
, h
;
470 origins
.insert(origins
.end(), "*.example.com");
471 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
473 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
474 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
476 g_test
->set_extra_header(string("Origin: a.example.com"));
477 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
478 g_test
->set_extra_header(string("Access-Control-Allow-Headers: SomeHeader"));
479 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
480 EXPECT_EQ(200U, g_test
->get_resp_code());
481 if(g_test
->get_resp_code() == 200){
482 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
483 EXPECT_EQ(0, s
.compare("a.example.com"));
484 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
485 EXPECT_EQ(0, s
.compare("GET"));
486 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
487 EXPECT_EQ(0U, s
.length());
488 s
= g_test
->get_response(string("Access-Control-Max-Age"));
489 EXPECT_EQ(0U, s
.length());
490 s
= g_test
->get_response(string("Access-Control-Expose-Headers"));
491 EXPECT_EQ(0U, s
.length());
494 ASSERT_EQ(0, delete_bucket());
497 TEST(TestCORS
, optionscors_test_options_2
){
498 ASSERT_EQ(0, create_bucket());
499 set
<string
> origins
, h
;
502 origins
.insert(origins
.end(), "*.example.com");
503 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
| RGW_CORS_DELETE
| RGW_CORS_HEAD
;
505 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
506 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
508 g_test
->set_extra_header(string("Origin: a.example.com"));
509 g_test
->set_extra_header(string("Access-Control-Request-Method: HEAD"));
510 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
511 EXPECT_EQ(200U, g_test
->get_resp_code());
512 if(g_test
->get_resp_code() == 200){
513 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
514 EXPECT_EQ(0, s
.compare("a.example.com"));
515 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
516 EXPECT_EQ(0, s
.compare("HEAD"));
519 g_test
->set_extra_header(string("Origin: foo.bar.example.com"));
520 g_test
->set_extra_header(string("Access-Control-Request-Method: HEAD"));
521 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
522 EXPECT_EQ(200U, g_test
->get_resp_code());
523 if(g_test
->get_resp_code() == 200){
524 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
525 EXPECT_EQ(0, s
.compare("foo.bar.example.com"));
526 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
527 EXPECT_EQ(0, s
.compare("HEAD"));
529 ASSERT_EQ(0, delete_bucket());
532 TEST(TestCORS
, optionscors_test_options_3
){
533 ASSERT_EQ(0, create_bucket());
534 set
<string
> origins
, h
;
537 origins
.insert(origins
.end(), "*");
538 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
| RGW_CORS_DELETE
| RGW_CORS_HEAD
;
540 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
541 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
543 /*Check for HEAD in Access-Control-Allow-Methods*/
544 g_test
->set_extra_header(string("Origin: a.example.com"));
545 g_test
->set_extra_header(string("Access-Control-Request-Method: HEAD"));
546 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
547 EXPECT_EQ(200U, g_test
->get_resp_code());
548 if(g_test
->get_resp_code() == 200){
549 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
550 EXPECT_EQ(0, s
.compare("a.example.com"));
551 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
552 EXPECT_EQ(0, s
.compare("HEAD"));
555 /*Check for DELETE in Access-Control-Allow-Methods*/
556 g_test
->set_extra_header(string("Origin: foo.bar"));
557 g_test
->set_extra_header(string("Access-Control-Request-Method: DELETE"));
558 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
559 EXPECT_EQ(200U, g_test
->get_resp_code());
560 if(g_test
->get_resp_code() == 200){
561 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
562 EXPECT_EQ(0, s
.compare("foo.bar"));
563 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
564 EXPECT_EQ(0, s
.compare("DELETE"));
567 /*Check for PUT in Access-Control-Allow-Methods*/
568 g_test
->set_extra_header(string("Origin: foo.bar"));
569 g_test
->set_extra_header(string("Access-Control-Request-Method: PUT"));
570 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
571 EXPECT_EQ(200U, g_test
->get_resp_code());
572 if(g_test
->get_resp_code() == 200){
573 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
574 EXPECT_EQ(0, s
.compare("foo.bar"));
575 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
576 EXPECT_EQ(0, s
.compare("PUT"));
579 /*Check for POST in Access-Control-Allow-Methods*/
580 g_test
->set_extra_header(string("Origin: foo.bar"));
581 g_test
->set_extra_header(string("Access-Control-Request-Method: POST"));
582 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
583 EXPECT_EQ(200U, g_test
->get_resp_code());
584 if(g_test
->get_resp_code() == 200){
585 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
586 EXPECT_EQ(0, s
.compare("foo.bar"));
587 if(g_test
->get_key_type() == KEY_TYPE_S3
){
588 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
589 EXPECT_EQ(0U, s
.length());
591 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
592 EXPECT_EQ(0, s
.compare("POST"));
595 ASSERT_EQ(0, delete_bucket());
598 TEST(TestCORS
, optionscors_test_options_4
){
599 ASSERT_EQ(0, create_bucket());
600 set
<string
> origins
, h
;
603 origins
.insert(origins
.end(), "example.com");
604 h
.insert(h
.end(), "Header1");
605 h
.insert(h
.end(), "Header2");
606 h
.insert(h
.end(), "*");
607 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
609 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
610 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
612 g_test
->set_extra_header(string("Origin: example.com"));
613 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
614 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
615 EXPECT_EQ(200U, g_test
->get_resp_code());
616 if(g_test
->get_resp_code() == 200){
617 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
618 EXPECT_EQ(0, s
.compare("example.com"));
619 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
620 EXPECT_EQ(0, s
.compare("GET"));
621 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
622 EXPECT_EQ(0U, s
.length());
624 g_test
->set_extra_header(string("Origin: example.com"));
625 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
626 g_test
->set_extra_header(string("Access-Control-Allow-Headers: Header1"));
627 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
628 EXPECT_EQ(200U, g_test
->get_resp_code());
629 if(g_test
->get_resp_code() == 200){
630 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
631 EXPECT_EQ(0, s
.compare("example.com"));
632 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
633 EXPECT_EQ(0, s
.compare("GET"));
634 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
635 EXPECT_EQ(0, s
.compare("Header1"));
637 g_test
->set_extra_header(string("Origin: example.com"));
638 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
639 g_test
->set_extra_header(string("Access-Control-Allow-Headers: Header2"));
640 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
641 EXPECT_EQ(200U, g_test
->get_resp_code());
642 if(g_test
->get_resp_code() == 200){
643 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
644 EXPECT_EQ(0, s
.compare("example.com"));
645 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
646 EXPECT_EQ(0, s
.compare("GET"));
647 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
648 EXPECT_EQ(0, s
.compare("Header2"));
650 g_test
->set_extra_header(string("Origin: example.com"));
651 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
652 g_test
->set_extra_header(string("Access-Control-Allow-Headers: Header2, Header1"));
653 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
654 EXPECT_EQ(200U, g_test
->get_resp_code());
655 if(g_test
->get_resp_code() == 200){
656 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
657 EXPECT_EQ(0, s
.compare("example.com"));
658 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
659 EXPECT_EQ(0, s
.compare("GET"));
660 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
661 EXPECT_EQ(0, s
.compare("Header2,Header1"));
663 g_test
->set_extra_header(string("Origin: example.com"));
664 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
665 g_test
->set_extra_header(string("Access-Control-Allow-Headers: Header1, Header2"));
666 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
667 EXPECT_EQ(200U, g_test
->get_resp_code());
668 if(g_test
->get_resp_code() == 200){
669 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
670 EXPECT_EQ(0, s
.compare("example.com"));
671 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
672 EXPECT_EQ(0, s
.compare("GET"));
673 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
674 EXPECT_EQ(0, s
.compare("Header1,Header2"));
676 g_test
->set_extra_header(string("Origin: example.com"));
677 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
678 g_test
->set_extra_header(string("Access-Control-Allow-Headers: Header1, Header2, Header3"));
679 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
680 EXPECT_EQ(200U, g_test
->get_resp_code());
681 if(g_test
->get_resp_code() == 200){
682 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
683 EXPECT_EQ(0, s
.compare("example.com"));
684 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
685 EXPECT_EQ(0, s
.compare("GET"));
686 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
687 EXPECT_EQ(0, s
.compare("Header1,Header2,Header3"));
689 ASSERT_EQ(0, delete_bucket());
692 TEST(TestCORS
, optionscors_test_options_5
){
693 ASSERT_EQ(0, create_bucket());
694 set
<string
> origins
, h
;
697 origins
.insert(origins
.end(), "example.com");
698 e
.insert(e
.end(), "Expose1");
699 e
.insert(e
.end(), "Expose2");
700 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
702 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
703 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
705 g_test
->set_extra_header(string("Origin: example.com"));
706 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
707 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
708 EXPECT_EQ(200U, g_test
->get_resp_code());
709 if(g_test
->get_resp_code() == 200){
710 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
711 EXPECT_EQ(0, s
.compare("example.com"));
712 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
713 EXPECT_EQ(0, s
.compare("GET"));
714 s
= g_test
->get_response(string("Access-Control-Expose-Headers"));
715 EXPECT_EQ(0, s
.compare("Expose1,Expose2"));
717 ASSERT_EQ(0, delete_bucket());
720 TEST(TestCORS
, optionscors_test_options_6
){
721 ASSERT_EQ(0, create_bucket());
722 set
<string
> origins
, h
;
724 unsigned err
= (g_test
->get_key_type() == KEY_TYPE_SWIFT
)?401U:403U;
726 origins
.insert(origins
.end(), "http://www.example.com");
727 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
729 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
730 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
732 g_test
->set_extra_header(string("Origin: example.com"));
733 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
734 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
735 EXPECT_EQ(err
, g_test
->get_resp_code());
737 g_test
->set_extra_header(string("Origin: http://example.com"));
738 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
739 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
740 EXPECT_EQ(err
, g_test
->get_resp_code());
742 g_test
->set_extra_header(string("Origin: www.example.com"));
743 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
744 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
745 EXPECT_EQ(err
, g_test
->get_resp_code());
747 g_test
->set_extra_header(string("Origin: http://www.example.com"));
748 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
749 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
750 EXPECT_EQ(200U, g_test
->get_resp_code());
752 origins
.erase(origins
.begin(), origins
.end());
753 origins
.insert(origins
.end(), "*.example.com");
754 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
755 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
757 g_test
->set_extra_header(string("Origin: .example.com"));
758 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
759 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
760 EXPECT_EQ(200U, g_test
->get_resp_code());
762 g_test
->set_extra_header(string("Origin: http://example.com"));
763 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
764 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
765 EXPECT_EQ(err
, g_test
->get_resp_code());
767 g_test
->set_extra_header(string("Origin: www.example.com"));
768 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
769 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
770 EXPECT_EQ(200U, g_test
->get_resp_code());
772 g_test
->set_extra_header(string("Origin: http://www.example.com"));
773 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
774 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
775 EXPECT_EQ(200U, g_test
->get_resp_code());
777 g_test
->set_extra_header(string("Origin: https://www.example.com"));
778 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
779 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
780 EXPECT_EQ(200U, g_test
->get_resp_code());
782 origins
.erase(origins
.begin(), origins
.end());
783 origins
.insert(origins
.end(), "https://example*.com");
784 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
785 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
787 g_test
->set_extra_header(string("Origin: https://example.com"));
788 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
789 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
790 EXPECT_EQ(200U, g_test
->get_resp_code());
792 g_test
->set_extra_header(string("Origin: http://example.com"));
793 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
794 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
795 EXPECT_EQ(err
, g_test
->get_resp_code());
797 g_test
->set_extra_header(string("Origin: www.example.com"));
798 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
799 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
800 EXPECT_EQ(err
, g_test
->get_resp_code());
802 g_test
->set_extra_header(string("Origin: https://example.a.b.com"));
803 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
804 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
805 EXPECT_EQ(200U, g_test
->get_resp_code());
807 ASSERT_EQ(0, delete_bucket());
810 TEST(TestCORS
, optionscors_test_options_7
){
811 ASSERT_EQ(0, create_bucket());
812 set
<string
> origins
, h
;
815 origins
.insert(origins
.end(), "example.com");
816 h
.insert(h
.end(), "Header*");
817 h
.insert(h
.end(), "Hdr-*-Length");
818 h
.insert(h
.end(), "*-Length");
819 h
.insert(h
.end(), "foo*foo");
820 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
822 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
823 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
825 g_test
->set_extra_header(string("Origin: example.com"));
826 g_test
->set_extra_header(string("Access-Control-Request-Method: GET"));
827 g_test
->set_extra_header(string("Access-Control-Allow-Headers: Header1, Header2, Header3, "
828 "Hdr--Length, Hdr-1-Length, Header-Length, Content-Length, foofoofoo"));
829 g_test
->send_request(string("OPTIONS"), BUCKET_URL
);
830 EXPECT_EQ(200U, g_test
->get_resp_code());
831 if(g_test
->get_resp_code() == 200){
832 string s
= g_test
->get_response(string("Access-Control-Allow-Origin"));
833 EXPECT_EQ(0, s
.compare("example.com"));
834 s
= g_test
->get_response(string("Access-Control-Allow-Methods"));
835 EXPECT_EQ(0, s
.compare("GET"));
836 s
= g_test
->get_response(string("Access-Control-Allow-Headers"));
837 EXPECT_EQ(0, s
.compare("Header1,Header2,Header3,"
838 "Hdr--Length,Hdr-1-Length,Header-Length,Content-Length,foofoofoo"));
840 ASSERT_EQ(0, delete_bucket());
843 TEST(TestCORS
, deletecors_firsttime
){
844 if(g_test
->get_key_type() == KEY_TYPE_SWIFT
)return;
845 ASSERT_EQ(0, create_bucket());
846 g_test
->send_request("DELETE", "/" S3_BUCKET_NAME
"?cors");
847 EXPECT_EQ(204U, g_test
->get_resp_code());
848 ASSERT_EQ(0, delete_bucket());
851 TEST(TestCORS
, deletecors_test
){
852 set
<string
> origins
, h
;
854 if(g_test
->get_key_type() == KEY_TYPE_SWIFT
)return;
855 ASSERT_EQ(0, create_bucket());
856 origins
.insert(origins
.end(), "example.com");
857 uint8_t flags
= RGW_CORS_GET
| RGW_CORS_PUT
;
859 send_cors(origins
, h
, e
, flags
, CORS_MAX_AGE_INVALID
);
860 EXPECT_EQ(((g_test
->get_key_type() == KEY_TYPE_SWIFT
)?202U:200U), g_test
->get_resp_code());
862 g_test
->send_request("GET", "/" S3_BUCKET_NAME
"?cors");
863 EXPECT_EQ(200U, g_test
->get_resp_code());
864 g_test
->send_request("DELETE", "/" S3_BUCKET_NAME
"?cors");
865 EXPECT_EQ(204U, g_test
->get_resp_code());
866 g_test
->send_request("GET", "/" S3_BUCKET_NAME
"?cors");
867 EXPECT_EQ(404U, g_test
->get_resp_code());
868 ASSERT_EQ(0, delete_bucket());
871 int main(int argc
, char *argv
[]){
872 auto args
= argv_to_vec(argc
, argv
);
874 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
875 CODE_ENVIRONMENT_UTILITY
,
876 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
877 common_init_finish(g_ceph_context
);
878 g_test
= new test_cors_helper();
879 finisher
= new Finisher(g_ceph_context
);
881 ::testing::InitGoogleTest(&argc
, argv
);
885 if(g_test
->extract_input((unsigned)argc
, argv
) < 0){
886 print_usage(argv
[0]);
890 int r
= RUN_ALL_TESTS();
892 cout
<< "There are failures in the test case\n";