1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * =========================================================================== */
24
25 #include "KStableHttpFile.hpp" // InnerKFileFromKStableHttpFile
26
27 #include "HttpFixture.hpp"
28
29 #include <ktst/unit_test.hpp>
30
31 #include <kfg/kfg-priv.h>
32 #include <kns/kns-mgr-priv.h>
33 #include <kfs/file.h>
34 #include <klib/time.h>
35 #include <kproc/timeout.h>
36 #include <cloud/manager.h>
37 #include <cloud/impl.h>
38
39 #include "../../libs/kns/http-file-priv.h"
40 #include "../../libs/kns/mgr-priv.h"
41
42 #include <cassert>
43 #include <sstream>
44
45 using namespace std;
46 using namespace ncbi::NK;
47
48 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
49 if (rc2 != 0 && rc == 0) { rc = rc2; } obj = NULL; } while (false)
50
51 KConfig * kfg = NULL;
52
53 static rc_t argsHandler ( int argc, char * argv [] );
54 TEST_SUITE_WITH_ARGS_HANDLER ( HttpRefreshTestSuite, argsHandler );
55
56 class CloudFixture : public HttpFixture
57 {
58 public:
CloudFixture()59 CloudFixture()
60 : m_cloud ( nullptr )
61 {
62 CloudMgr * cloudMgr;
63 THROW_ON_RC ( CloudMgrMake ( & cloudMgr, nullptr, m_mgr ) );
64 THROW_ON_RC ( CloudMgrCurrentProvider ( cloudMgr, & m_cloudProviderId ) );
65 if ( m_cloudProviderId != cloud_provider_none )
66 {
67 THROW_ON_RC ( CloudMgrGetCurrentCloud ( cloudMgr, & m_cloud ) );
68 }
69 THROW_ON_RC ( CloudMgrRelease ( cloudMgr ) );
70 }
71
~CloudFixture()72 ~CloudFixture()
73 {
74 CloudRelease ( m_cloud );
75 }
76
77 public:
78 // fake responses.
79 // Call these methods in the exact order oif intended responses since they do not check the requests
RespondWithRedirect(const string & url,KTime_t expTime)80 void RespondWithRedirect( const string & url, KTime_t expTime )
81 {
82 char expirationStr[100];
83 KTimeIso8601 ( expTime, expirationStr, sizeof expirationStr );
84 TestStream::AddResponse( string ( "HTTP/1.1 307 Temporary Redirect\r\n" ) +
85 "Location: " + url + "\r\n" +
86 "Expires: " + expirationStr + "\r\n" );
87 }
RespondToHEAD()88 void RespondToHEAD()
89 {
90 ostringstream ostr;
91 ostr << "HTTP/1.1 200 OK\r\nAccept-Ranges: bytes\r\nContent-Length: " << sizeof m_buf << "\r\n";
92 TestStream::AddResponse( ostr.str() );
93 }
RespondToHEAD(const string & data)94 void RespondToHEAD( const string & data )
95 { /* in cases when HEAD is converted into a POST or a GET, we actually read up to 256 bytes from the beginning */
96 ostringstream ostr;
97 ostr << "HTTP/1.1 206 Partial Content\r\n" <<
98 "Content-Range: bytes 0-" << ( data.size() - 1 ) << "/" << data.size() << "\r\n" <<
99 "Content-Length: " << data.size() << "\r\n" <<
100 "Accept-Ranges: bytes" << "\r\n" <<
101 "\r\n" <<
102 data <<
103 "\r\n";
104 TestStream::AddResponse( ostr.str() );
105 }
106
RespondToGET()107 void RespondToGET()
108 {
109 ostringstream ostr;
110 ostr << "HTTP/1.1 206 Partial Content\r\n" <<
111 "Content-Range: bytes 0-" << ( sizeof m_buf - 1 ) << "/" << sizeof m_buf << "\r\n" <<
112 "Content-Length: " << sizeof m_buf << "\r\n" <<
113 "\r\n" <<
114 string(sizeof m_buf, 'z') <<
115 "\r\n";
116 TestStream::AddResponse( ostr.str() );
117 }
RespondToGET_Full(const string & data)118 void RespondToGET_Full( const string & data )
119 {
120 ostringstream ostr;
121 ostr << "HTTP/1.1 200 \r\n" <<
122 "Content-Length: " << data.size() << "\r\n" <<
123 "\r\n" <<
124 data <<
125 "\r\n";
126 TestStream::AddResponse( ostr.str() );
127 }
128
EnvironmentTokenPresent(const string & url)129 bool EnvironmentTokenPresent( const string & url )
130 {
131 return url.find("&ident=") != string::npos;
132 }
StringPresent(const string & url,const string & header)133 bool StringPresent( const string & url, const string & header )
134 {
135 return url.find(header) != string::npos;
136 }
137
138 const bool EnvTokenRequired = true;
139 const bool PayRequired = true;
MakeHttpFile(const string & url,bool ce_required,bool payer_required)140 const struct KHttpFile& MakeHttpFile ( const string & url, bool ce_required, bool payer_required )
141 {
142 THROW_ON_RC ( KNSManagerMakeReliableHttpFile( m_mgr, ( const KFile** ) & m_file, & m_stream, 0x01010000, true, ce_required, payer_required, url . c_str () ) );
143 THROW_ON_FALSE ( m_file != NULL ) ;
144 if (getenv("NCBI_VDB_HTTP_FILE_NO_RETRY") != NULL)
145 return * reinterpret_cast < const struct KHttpFile* > ( m_file );
146 else {
147 const struct KFile* f = InnerKFileFromKStableHttpFile(m_file);
148 const struct KHttpFile* hf =
149 reinterpret_cast <const struct KHttpFile*> (f);
150 return *hf;
151 }
152 }
153
SetUpForExpiration(const string & url,bool ce_required,bool payer_required)154 const struct KHttpFile& SetUpForExpiration( const string & url, bool ce_required, bool payer_required )
155 {
156 KTime_t expTime = KTimeStamp () + 65;
157 RespondWithRedirect ( AwsUrl, expTime );
158 RespondToHEAD();
159
160 const struct KHttpFile& httpFile = MakeHttpFile( url, ce_required, payer_required );
161
162 // read a portion of the file
163 RespondToGET();
164 THROW_ON_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
165
166 // wait 6s to cross the refresh threshold, read again, see the URL refreshed and the expiration updated
167 cout << "Sleep 6 sec" << endl;
168 KSleep(6);
169 return httpFile;
170 }
171
VerifyRequest(const string & method,const string & url,bool tokenPresent,bool autorizationPresent,bool payerPresent)172 void VerifyRequest ( const string & method, const string & url, bool tokenPresent, bool autorizationPresent, bool payerPresent )
173 {
174 // make sure there is no environment token added to the original URL
175 THROW_ON_FALSE ( ! EnvironmentTokenPresent ( TestStream::m_requests.front() ) );
176 // make sure there are no cloud-related headers added to the redirect URL
177 string redirReq = TestStream::m_requests.back();
178 THROW_ON_FALSE ( ! StringPresent ( redirReq, "Authorization" ) );
179 THROW_ON_FALSE ( ! StringPresent ( redirReq, "Date" ) );
180 THROW_ON_FALSE ( ! StringPresent ( redirReq, "x-amz-request-payer" ) );
181 }
182
SetEnv()183 void SetEnv()
184 {
185 putenv ( (char*)"AWS_ACCESS_KEY_ID=access_key_id" );
186 putenv ( (char*)"AWS_SECRET_ACCESS_KEY=secret_access_key" );
187 }
188
189 char m_buf[1024];
190 size_t num_read;
191 static constexpr const char * AwsUrl = "https://amazonaws.com/accession";
192 static constexpr const char * NonCloudUrl = "https://ncbi.nlm.nih.gov/accession";
193
194 CloudProviderId m_cloudProviderId;
195 Cloud * m_cloud;
196 };
197
FIXTURE_TEST_CASE(HttpRefreshTestSuite_RedirectSignedURL_NotCloud,CloudFixture)198 FIXTURE_TEST_CASE( HttpRefreshTestSuite_RedirectSignedURL_NotCloud, CloudFixture )
199 {
200 //make sure not in a cloud
201 if ( m_cloudProviderId != cloud_provider_none )
202 {
203 return;
204 }
205
206 //TestEnv::verbosity = LogLevel::e_message;
207 string url = MakeURL(GetName());
208
209 // simulates a 2-stage (redirect, real) response to a HEAD request from the "signer" service.
210 // Pretend this is the object we need expiring 65 seconds in the future; the refresh timer will be set to 60 seconds before that
211 KTime_t expTime = KTimeStamp () + 65;
212 RespondWithRedirect ( NonCloudUrl, expTime );
213 RespondToHEAD ();
214
215 const struct KHttpFile& httpFile = MakeHttpFile( url, ! EnvTokenRequired, ! PayRequired );
216
217 // make sure both original and redirection URLs and the expiration time are reflected on the HttpFile object
218 REQUIRE_EQ ( url, string ( (const char*) httpFile . orig_url_buffer . base ) );
219 REQUIRE_EQ ( string ( NonCloudUrl ), string ( (const char*) httpFile . url_buffer . base ) );
220 REQUIRE ( httpFile . url_is_temporary );
221 REQUIRE_EQ ( expTime, KTimeMakeTime ( & httpFile . url_expiration ) );
222
223 // make sure there is no environment token added to the original URL
224 REQUIRE ( ! EnvironmentTokenPresent ( TestStream::m_requests.front() ) );
225 // make sure there are no cloud-related headers added to the redirect URL
226 string redirReq = TestStream::m_requests.back();
227 REQUIRE ( ! StringPresent ( redirReq, "Authorization" ) );
228 REQUIRE ( ! StringPresent ( redirReq, "Date" ) );
229 REQUIRE ( ! StringPresent ( redirReq, "x-amz-request-payer" ) );
230 }
231
232 // for AWS, autorization is only added with the payer info
FIXTURE_TEST_CASE(HttpRefreshTestSuite_RedirectSignedURL_AWS_NoAuth_NoPayer,CloudFixture)233 FIXTURE_TEST_CASE( HttpRefreshTestSuite_RedirectSignedURL_AWS_NoAuth_NoPayer, CloudFixture )
234 {
235 //make sure not in a cloud
236 if ( m_cloudProviderId != cloud_provider_aws )
237 {
238 return;
239 }
240
241 SetEnv();
242
243 RespondWithRedirect ( AwsUrl, KTimeStamp () + 65 );
244 RespondToHEAD ( string( 256, 'q' ) );
245
246 MakeHttpFile( MakeURL(GetName()), EnvTokenRequired, ! PayRequired );
247
248 // make sure AWS autorization headers but no payer info header are added to the redirect URL
249 string redirReq = TestStream::m_requests.back();
250 REQUIRE ( ! StringPresent ( redirReq, "Authorization: AWS access_key_id:" ) );
251 REQUIRE ( ! StringPresent ( redirReq, "x-amz-request-payer: requester" ) );
252 }
253
FIXTURE_TEST_CASE(HttpRefreshTestSuite_RedirectSignedURL_AWS_Token_NoPayer,CloudFixture)254 FIXTURE_TEST_CASE( HttpRefreshTestSuite_RedirectSignedURL_AWS_Token_NoPayer, CloudFixture )
255 {
256 //make sure not in a cloud
257 if ( m_cloudProviderId != cloud_provider_aws )
258 {
259 return;
260 }
261
262 SetEnv();
263
264 m_mgr -> accept_aws_charges = false;
265
266 RespondWithRedirect ( AwsUrl, KTimeStamp () + 65 );
267 RespondToHEAD ( string( 256, 'q' ) );
268
269 MakeHttpFile( MakeURL(GetName()), EnvTokenRequired, ! PayRequired );
270
271 // make sure there is an environment token added to the original URL
272 string origReq = TestStream::m_requests.front();
273 REQUIRE ( EnvironmentTokenPresent ( origReq ) );
274 // make sure HEAD was converted into POST 0..255, with User-agent header appended "-head" to, for analytics purposes
275 REQUIRE ( ! StringPresent ( origReq, "HEAD" ) );
276 REQUIRE ( StringPresent ( origReq, "POST" ) );
277 REQUIRE ( StringPresent ( origReq, "0-255" ) );
278 REQUIRE ( StringPresent ( origReq, "-head" ) );
279
280 // make sure there is no payer info added to the redirect URL
281 string lastReq = TestStream::m_requests.back();
282 REQUIRE ( ! StringPresent ( lastReq, "x-amz-request-payer" ) );
283 // User-agent header restored for future requests
284 const char * suff;
285 REQUIRE_RC ( KNSManagerGetUserAgent ( & suff ) );
286 REQUIRE ( ! StringPresent ( string(suff), "-head" ) );
287 }
288
289 #if UNIMPLEMENTED
FIXTURE_TEST_CASE(HttpRefreshTestSuite_RedirectSignedURL_AWS_NoToken_Payer,CloudFixture)290 FIXTURE_TEST_CASE( HttpRefreshTestSuite_RedirectSignedURL_AWS_NoToken_Payer, CloudFixture )
291 {
292 if ( m_cloudProviderId != cloud_provider_aws )
293 {
294 return;
295 }
296
297 //TestEnv::verbosity = LogLevel::e_message;
298 string url = MakeURL(GetName());
299
300 SetEnv();
301
302 KTime_t expTime = KTimeStamp () + 65;
303 RespondWithRedirect ( AwsUrl, expTime );
304 // HEAD will be converted to GET and return the initial portion of the target file
305 RespondToHEAD(string(2048, 'a'));
306
307 MakeHttpFile( url, ! EnvTokenRequired, PayRequired );
308
309 // make sure there is no environment token added to the original URL
310 string origReq = TestStream::m_requests.front();
311 REQUIRE ( ! EnvironmentTokenPresent ( origReq ) );
312 // payment info is required and no token present, HEAD is converted into GET 0..255,
313 // User-Agent appended -head to
314 REQUIRE ( ! StringPresent ( origReq, "HEAD" ) );
315 REQUIRE ( StringPresent ( origReq, "GET" ) );
316 REQUIRE ( StringPresent ( origReq, "-head" ) );
317
318 // make sure there are authorization and payer info added to the redirect URL
319 string redirReq = TestStream::m_requests.back();
320 cout<<redirReq<<endl;
321 REQUIRE ( StringPresent ( redirReq, "Authorization: AWS access_key_id:" ) );
322 REQUIRE ( StringPresent ( redirReq, "Date: " ) );
323 REQUIRE ( StringPresent ( redirReq, "x-amz-request-payer" ) );
324 }
325 //TODO: user does not agree to pay
326 #endif
327
328 #if UNIMPLEMENTED
FIXTURE_TEST_CASE(HttpRefreshTestSuite_RedirectSignedURL_AWS_Token_Payer,CloudFixture)329 FIXTURE_TEST_CASE( HttpRefreshTestSuite_RedirectSignedURL_AWS_Token_Payer, CloudFixture )
330 {
331 if ( m_cloudProviderId != cloud_provider_aws )
332 {
333 return;
334 }
335
336 //TestEnv::verbosity = LogLevel::e_message;
337 string url = MakeURL(GetName());
338
339 SetEnv();
340
341 m_mgr -> accept_aws_charges = true;
342
343 KTime_t expTime = KTimeStamp () + 65;
344 RespondWithRedirect ( AwsUrl, expTime );
345 // HEAD will be converted to POST and return the initial portion of the target file
346 RespondToHEAD(string(2048, 'a'));
347
348 MakeHttpFile( url, EnvTokenRequired, PayRequired );
349
350 // make sure there is an environment token added to the original URL
351 string origReq = TestStream::m_requests.front();
352 REQUIRE ( EnvironmentTokenPresent ( origReq ) );
353 // when token is required, HEAD is converted to POST
354 REQUIRE ( ! StringPresent ( origReq, "HEAD" ) );
355 REQUIRE ( StringPresent ( origReq, "POST" ) );
356
357 // make sure there is authorization and payer info added to the redirect URL
358 string redirReq = TestStream::m_requests.back();
359 REQUIRE ( StringPresent ( redirReq, "Authorization: AWS access_key_id:" ) );
360 REQUIRE ( StringPresent ( redirReq, "Date: " ) );
361 REQUIRE ( StringPresent ( redirReq, "x-amz-request-payer" ) );
362 }
363 #endif
364
365 // Refresh temporary URL on a read within 1 min of expiration
366
FIXTURE_TEST_CASE(HttpRefreshTestSuite_ReadCloseToExpiration_AWS_NoToken_NoPayer,CloudFixture)367 FIXTURE_TEST_CASE( HttpRefreshTestSuite_ReadCloseToExpiration_AWS_NoToken_NoPayer, CloudFixture )
368 {
369 if ( m_cloudProviderId != cloud_provider_aws )
370 {
371 return;
372 }
373
374 string url = MakeURL(GetName());
375
376 const struct KHttpFile& httpFile = SetUpForExpiration ( url, ! EnvTokenRequired, ! PayRequired );
377
378 // another simulated response from the "signer" service. The URL is now different, with new expiration
379 KTime_t newExpTime = KTimeStamp () + 65;
380 string newAwsHost = "ELSEWHERE.in.the.cloud";
381 RespondWithRedirect ( MakeURL( newAwsHost ), newExpTime );
382 RespondToGET();
383
384 // this Read will notice that the expiration time is nigh, re-issue GET with the original URL
385 // and get redirected by the "signer" to a new temporary URL
386 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
387 REQUIRE_EQ ( newExpTime, KTimeMakeTime ( & httpFile . url_expiration ) );
388
389 { // verify that the second to last request (refresh the temporary URL)
390 // was done on the original URL with a GET
391 string req = * ( ++ TestStream::m_requests . rbegin() );
392 REQUIRE ( StringPresent ( req, "GET" ) );
393 REQUIRE ( StringPresent ( req, GetName() ) );
394 REQUIRE ( ! EnvironmentTokenPresent ( req ) );
395 }
396 { // verify that the last request (read the data) was done on the new redirected URL
397 // with a GET, no token
398 string req = TestStream::m_requests . back();
399 REQUIRE ( StringPresent ( req, "GET" ) );
400 REQUIRE ( StringPresent ( req, newAwsHost ) );
401 REQUIRE ( ! EnvironmentTokenPresent ( req ) );
402 }
403
404 // the next Read (right away) will not refresh the URL or expiration
405 RespondToGET();
406 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
407 REQUIRE_EQ ( newExpTime, KTimeMakeTime ( & httpFile . url_expiration ) ); // expiration did not change
408
409 { // verify that the last request was done on the same redirected URL
410 string req = TestStream::m_requests . back();
411 REQUIRE ( StringPresent ( req, newAwsHost ) );
412 REQUIRE ( ! EnvironmentTokenPresent ( req ) );
413 REQUIRE ( ! StringPresent ( req, "x-amz-request-payer: requester" ) );
414 }
415 }
416
417 #if UNIMPLEMENTED
FIXTURE_TEST_CASE(HttpRefreshTestSuite_ReadCloseToExpiration_AWS_Token_NoPayer,CloudFixture)418 FIXTURE_TEST_CASE( HttpRefreshTestSuite_ReadCloseToExpiration_AWS_Token_NoPayer, CloudFixture )
419 {
420 if ( m_cloudProviderId != cloud_provider_aws )
421 {
422 return;
423 }
424
425 //TestEnv::verbosity = LogLevel::e_message;
426 string url = MakeURL(GetName());
427
428 const struct KHttpFile& httpFile = SetUpForExpiration ( url, EnvTokenRequired, ! PayRequired );
429
430 // another simulated response from the "signer" service. The URL is now different, with new expiration
431 KTime_t newExpTime = KTimeStamp () + 65;
432 string newAwsHost = "ELSEWHERE.in.the.cloud";
433 RespondWithRedirect ( MakeURL( newAwsHost ), newExpTime );
434 RespondToGET(); // will be converted to POST
435
436 // this Read will notice that the expiration time is nigh, use the original URL and get redirected to the "signer" for a new temporary URL
437 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
438 REQUIRE_EQ ( newExpTime, KTimeMakeTime ( & httpFile . url_expiration ) );
439
440 { // verify that the second to last request was done on the original URL,
441 // as a POST with a CE token
442 string req = * ( ++ TestStream::m_requests . rbegin() );
443 REQUIRE ( StringPresent ( req, GetName() ) );
444 REQUIRE ( EnvironmentTokenPresent ( req ) );
445 REQUIRE ( StringPresent ( req, "POST" ) );
446 }
447
448 { // verify that the last request was done on the new redirected URL with a GET
449 // without the token
450 string req = TestStream::m_requests . back();
451 REQUIRE ( StringPresent ( req, newAwsHost ) );
452 REQUIRE ( ! EnvironmentTokenPresent ( req ) );
453 REQUIRE ( StringPresent ( req, "GET" ) );
454 }
455
456 // the next Read (right away) will not refresh the URL or expiration
457 RespondToGET();
458 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
459 REQUIRE_EQ ( newExpTime, KTimeMakeTime ( & httpFile . url_expiration ) ); // expiration did not change
460 // verify that the last request was done on the same redirected URL
461 REQUIRE ( StringPresent ( TestStream::m_requests . back(), newAwsHost ) );
462 }
463 #endif
464
465 #if UNIMPLEMENTED
FIXTURE_TEST_CASE(HttpRefreshTestSuite_ReadCloseToExpiration_AWS_NoToken_Payer,CloudFixture)466 FIXTURE_TEST_CASE( HttpRefreshTestSuite_ReadCloseToExpiration_AWS_NoToken_Payer, CloudFixture )
467 {
468 if ( m_cloudProviderId != cloud_provider_aws )
469 {
470 return;
471 }
472
473 //TestEnv::verbosity = LogLevel::e_message;
474 string url = MakeURL(GetName());
475
476 const struct KHttpFile& httpFile = SetUpForExpiration ( url, ! EnvTokenRequired, PayRequired );
477
478 // another simulated response from the "signer" service. The URL is now different, with new expiration
479 KTime_t newExpTime = KTimeStamp () + 65;
480 string newAwsHost = "ELSEWHERE.in.the.cloud";
481 RespondWithRedirect ( MakeURL( newAwsHost ), newExpTime );
482 RespondToGET(); // will be converted to POST
483
484 // this Read will notice that the expiration time is nigh, use the original URL and get redirected to the "signer" for a new temporary URL
485 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
486 REQUIRE_EQ ( newExpTime, KTimeMakeTime ( & httpFile . url_expiration ) );
487
488 { // verify that the second to last request was done on the original URL,
489 // as a POST with a CE token
490 string req = * ( ++ TestStream::m_requests . rbegin() );
491 REQUIRE ( StringPresent ( req, GetName() ) );
492 REQUIRE ( ! EnvironmentTokenPresent ( req ) );
493 REQUIRE ( StringPresent ( req, "POST" ) );
494 }
495
496 { // verify that the last request was done on the new redirected URL with a GET
497 // without the token
498 string req = TestStream::m_requests . back();
499 REQUIRE ( StringPresent ( req, newAwsHost ) );
500 REQUIRE ( ! EnvironmentTokenPresent ( req ) );
501 REQUIRE ( StringPresent ( req, "GET" ) );
502 }
503
504 // the next Read (right away) will not refresh the URL or expiration
505 RespondToGET();
506 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
507 REQUIRE_EQ ( newExpTime, KTimeMakeTime ( & httpFile . url_expiration ) ); // expiration did not change
508 // verify that the last request was done on the same redirected URL
509 REQUIRE ( StringPresent ( TestStream::m_requests . back(), newAwsHost ) );
510 }
511 #endif
512
513 //TODO
514 //FIXTURE_TEST_CASE( HttpRefreshTestSuite_ReadCloseToExpiration_AWS_NoToken_NoPayer, CloudFixture )
515 //FIXTURE_TEST_CASE( HttpRefreshTestSuite_ReadCloseToExpiration_GCP_xxToken_xxPayer, CloudFixture )
516
FIXTURE_TEST_CASE(HttpRefreshTestSuite_HeadAsPost_ShortFile,CloudFixture)517 FIXTURE_TEST_CASE( HttpRefreshTestSuite_HeadAsPost_ShortFile, CloudFixture )
518 {
519 string url = MakeURL(GetName());
520
521 // HEAD will be converted to POST and return the initial portion of the target file
522 string data (10, 'a');// this is shorter than POST will request (256)
523 RespondToHEAD(data);
524
525 MakeHttpFile( url, EnvTokenRequired, ! PayRequired );
526
527 RespondToGET_Full(data); // return the complete file
528 REQUIRE_RC( KFileTimedRead ( m_file, 0, m_buf, sizeof m_buf, & num_read, NULL ) );
529 }
530
531 //////////////////////////////////////////// Main
532
533 #include <kapp/args.h> // Args
534 #include <klib/debug.h>
535 #include <kfg/config.h>
536
argsHandler(int argc,char * argv[])537 static rc_t argsHandler ( int argc, char * argv [] ) {
538 Args * args = NULL;
539 rc_t rc = ArgsMakeAndHandle ( & args, argc, argv, 0, NULL, 0 );
540 ArgsWhack ( args );
541 return rc;
542 }
543
544 extern "C" {
545 const char UsageDefaultName[] = "test-refresh-expired";
UsageSummary(const char * progname)546 rc_t CC UsageSummary ( const char * progname) { return 0; }
Usage(const struct Args * args)547 rc_t CC Usage ( const struct Args * args ) { return 0; }
KAppVersion(void)548 ver_t CC KAppVersion ( void ) { return 0; }
549
KMain(int argc,char * argv[])550 rc_t CC KMain ( int argc, char * argv [] )
551 {
552 //if ( 1 ) assert ( ! KDbgSetString ( "KNS-HTTP" ) );
553 KConfigDisableUserSettings ();
554
555 rc_t rc = KConfigMakeEmpty ( & kfg );
556 // turn off certificate validation to download from storage.googleapis.com
557 if ( rc == 0 )
558 rc = KConfigWriteString ( kfg, "/tls/allow-all-certs", "true" );
559
560 // in order to run in a cloud, give permission to submit computing environment
561 if (rc == 0)
562 rc = KConfigWriteString(kfg, "/libs/cloud/report_instance_identity", "true");
563
564 if ( rc == 0 )
565 rc = HttpRefreshTestSuite ( argc, argv );
566
567 RELEASE ( KConfig, kfg );
568
569 return rc;
570 }
571 }
572
573