2022-09-13 15:13:11 +02:00
< ? php
// RouterTest.php
// Created: 2022-01-20
2025-03-23 03:38:11 +00:00
// Updated: 2025-03-23
2022-09-13 15:13:11 +02:00
declare ( strict_types = 1 );
use PHPUnit\Framework\TestCase ;
2024-07-31 18:12:46 +00:00
use PHPUnit\Framework\Attributes\CoversClass ;
2025-03-12 20:56:48 +00:00
use Index\Http\ { HttpHeaders , HttpResponseBuilder , HttpRequest , HttpUri };
2025-03-15 02:10:16 +00:00
use Index\Http\Content\ { FormContent , MultipartFormContent , UrlEncodedFormContent };
2025-03-07 23:39:15 +00:00
use Index\Http\Routing\ { HandlerContext , RouteHandler , RouteHandlerCommon , Router };
2025-03-19 21:24:52 +00:00
use Index\Http\Routing\AccessControl\ { AccessControl };
2025-03-07 23:39:15 +00:00
use Index\Http\Routing\Filters\ { FilterInfo , PrefixFilter };
use Index\Http\Routing\Processors\ { After , Before , Postprocessor , Preprocessor , ProcessorInfo };
use Index\Http\Routing\Routes\ { ExactRoute , PatternRoute , RouteInfo };
2025-03-15 02:10:16 +00:00
use Index\Http\Streams\Stream ;
2022-09-13 15:13:11 +02:00
/**
2024-03-30 16:24:34 +00:00
* This test isn ' t super representative of the current functionality
* it mostly just does the same tests that were done against the previous implementation
2022-09-13 15:13:11 +02:00
*/
2025-02-28 22:44:56 +00:00
#[CoversClass(Router::class)]
2025-03-07 00:25:00 +00:00
#[CoversClass(RouteInfo::class)]
#[CoversClass(PrefixFilter::class)]
#[CoversClass(ExactRoute::class)]
2024-07-31 18:12:46 +00:00
#[CoversClass(RouteHandler::class)]
2025-01-18 21:57:27 +00:00
#[CoversClass(RouteHandlerCommon::class)]
2025-03-07 00:25:00 +00:00
#[CoversClass(PatternRoute::class)]
#[CoversClass(FilterInfo::class)]
2025-03-19 21:24:52 +00:00
#[CoversClass(AccessControl::class)]
2022-09-13 15:13:11 +02:00
final class RouterTest extends TestCase {
public function testRouter () : void {
2025-02-28 22:44:56 +00:00
$router1 = new Router ;
2024-03-30 16:24:34 +00:00
2025-03-07 00:25:00 +00:00
$router1 -> route ( RouteInfo :: exact ( 'GET' , '/' , fn () => 'get' ));
$router1 -> route ( RouteInfo :: exact ( 'POST' , '/' , fn () => 'post' ));
$router1 -> route ( RouteInfo :: exact ( 'DELETE' , '/' , fn () => 'delete' ));
$router1 -> route ( RouteInfo :: exact ( 'PATCH' , '/' , fn () => 'patch' ));
$router1 -> route ( RouteInfo :: exact ( 'PUT' , '/' , fn () => 'put' ));
$router1 -> route ( RouteInfo :: exact ( 'CUSTOM' , '/' , fn () => 'wacky' ));
2024-03-30 16:24:34 +00:00
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'get' , ( string ) $router1 -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/' )) -> getBody ());
$this -> assertSame ( 'wacky' , ( string ) $router1 -> handle ( HttpRequest :: createRequestWithoutBody ( 'CUSTOM' , '/' )) -> getBody ());
2024-03-30 16:24:34 +00:00
2025-03-07 00:25:00 +00:00
$router1 -> filter ( FilterInfo :: prefix ( '/' , function () { /* this one intentionally does nothing */ }));
2024-03-30 16:24:34 +00:00
// registration order should matter
2025-03-07 00:25:00 +00:00
$router1 -> filter ( FilterInfo :: prefix ( '/deep' , fn () => 'deep' ));
2024-03-30 16:24:34 +00:00
2025-03-07 00:25:00 +00:00
$router1 -> filter ( FilterInfo :: pattern ( '#^/user/([A-Za-z0-9]+)/below#u' , fn ( string $user ) => 'warioware below ' . $user ));
2024-03-30 16:24:34 +00:00
2025-03-07 00:25:00 +00:00
$router1 -> route ( RouteInfo :: exact ( 'GET' , '/user/static' , fn () => 'the static one' ));
$router1 -> route ( RouteInfo :: exact ( 'GET' , '/user/static/below' , fn () => 'below the static one' ));
$router1 -> route ( RouteInfo :: pattern ( 'GET' , '#^/user/([A-Za-z0-9]+)$#uD' , fn ( string $user ) => $user ));
$router1 -> route ( RouteInfo :: pattern ( 'GET' , '#^/user/([A-Za-z0-9]+)/below$#uD' , fn ( string $user ) => 'below ' . $user ));
2024-03-30 16:24:34 +00:00
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'warioware below static' , ( string ) $router1 -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/user/static/below' )) -> getBody ());
2024-03-30 16:24:34 +00:00
2025-02-28 22:44:56 +00:00
$router2 = new Router ;
2025-03-07 00:25:00 +00:00
$router2 -> filter ( FilterInfo :: prefix ( '/' , fn () => 'meow' ));
$router2 -> route ( RouteInfo :: exact ( 'GET' , '/rules' , fn () => 'rules page' ));
$router2 -> route ( RouteInfo :: exact ( 'GET' , '/contact' , fn () => 'contact page' ));
$router2 -> route ( RouteInfo :: exact ( 'GET' , '/25252' , fn () => 'numeric test' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'meow' , ( string ) $router2 -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/rules' )) -> getBody ());
2022-09-13 15:13:11 +02:00
}
2023-09-07 22:08:31 +00:00
public function testAttribute () : void {
2025-02-28 22:44:56 +00:00
$router = new Router ;
2024-10-02 02:09:21 +00:00
$handler = new class implements RouteHandler {
2025-01-18 21:57:27 +00:00
use RouteHandlerCommon ;
2024-10-02 02:09:21 +00:00
2025-03-07 00:25:00 +00:00
#[ExactRoute('GET', '/')]
2024-12-02 01:30:36 +00:00
public function getIndex () : string {
2023-09-07 22:08:31 +00:00
return 'index' ;
}
2025-03-07 00:25:00 +00:00
#[ExactRoute('POST', '/avatar')]
2024-12-02 01:30:36 +00:00
public function postAvatar () : string {
2023-09-07 22:08:31 +00:00
return 'avatar' ;
}
2025-03-07 00:25:00 +00:00
#[ExactRoute('PUT', '/static')]
2024-12-02 01:30:36 +00:00
public static function putStatic () : string {
2023-09-07 22:08:31 +00:00
return 'static' ;
}
2025-03-07 00:25:00 +00:00
#[ExactRoute('GET', '/meow')]
#[ExactRoute('POST', '/meow')]
2024-12-02 01:30:36 +00:00
public function multiple () : string {
2023-09-07 22:08:31 +00:00
return 'meow' ;
}
2023-09-07 22:37:04 +00:00
2025-03-07 00:25:00 +00:00
#[PrefixFilter('/filter')]
2025-03-02 02:08:45 +00:00
public function useFilter () : string {
2023-09-08 00:09:23 +00:00
return 'this intercepts' ;
}
2025-03-07 00:25:00 +00:00
#[ExactRoute('GET', '/filter')]
2025-03-02 02:08:45 +00:00
public function getFilter () : string {
2023-09-08 00:09:23 +00:00
return 'this is intercepted' ;
}
2025-03-07 00:25:00 +00:00
#[PatternRoute('GET', '/profile/([A-Za-z0-9]+)')]
public function getPattern ( string $beans ) : string {
return sprintf ( 'profile of %s' , $beans );
}
#[PatternRoute('GET', '#^/profile-but-raw/([A-Za-z0-9]+)$#uD', raw: true)]
public function getPatternRaw ( string $beans ) : string {
return sprintf ( 'still the profile of %s' , $beans );
}
2025-03-21 18:19:04 +00:00
#[ExactRoute('GET', '/announce')]
#[ExactRoute('GET', '/announce.php')]
#[PatternRoute('GET', '/announce/([A-Za-z0-9]+)')]
#[PatternRoute('GET', '/announce.php/([A-Za-z0-9]+)')]
public function getMultipleTestWithDefault ( string $key = 'empty' ) : string {
return $key ;
}
2025-03-22 19:59:44 +00:00
#[PatternRoute('GET', '/uploads/([A-Za-z0-9]+|[A-Za-z0-9\-_]{32})(?:-([a-z0-9]+))?(?:\.([A-Za-z0-9\-_]+))?')]
public function getEepromEdgeCase (
string $uploadId ,
string $variant = '' ,
string $extension = ''
) : string {
return sprintf ( '%s//%s//%s' , $uploadId , $variant , $extension );
}
2025-03-23 03:38:11 +00:00
#[ExactRoute('GET', '/messages/stats')]
public function getStats () : string {
return 'hit exact' ;
}
#[PatternRoute('GET', '/messages/([A-Za-z0-9]+)')]
public function getView () : string {
return 'hit pattern' ;
}
2025-03-23 03:45:47 +00:00
#[ExactRoute('GET', '/assets/avatar')]
#[PatternRoute('GET', '/assets/avatar/([0-9]+)(?:\.[a-z]+)?')]
public function getTrailingSlash () : string {
return 'hit' ;
}
2024-12-02 01:30:36 +00:00
public function hasNoAttr () : string {
2023-09-07 22:37:04 +00:00
return 'not a route' ;
}
2023-09-07 22:08:31 +00:00
};
$router -> register ( $handler );
2025-03-07 00:25:00 +00:00
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'index' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/' )) -> getBody ());
$this -> assertSame ( 'avatar' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'POST' , '/avatar' )) -> getBody ());
$this -> assertSame ( 'static' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'PUT' , '/static' )) -> getBody ());
$this -> assertSame ( 'meow' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/meow' )) -> getBody ());
$this -> assertSame ( 'meow' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'POST' , '/meow' )) -> getBody ());
$this -> assertSame ( 'profile of Cool134' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/profile/Cool134' )) -> getBody ());
$this -> assertSame ( 'still the profile of Cool134' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/profile-but-raw/Cool134' )) -> getBody ());
2025-03-21 18:19:04 +00:00
$this -> assertSame ( 'empty' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/announce' )) -> getBody ());
$this -> assertSame ( 'empty' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/announce.php' )) -> getBody ());
$this -> assertSame ( 'Z643QANLgGNkF4D4h4qvFpyeXjx4TcDE' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/announce/Z643QANLgGNkF4D4h4qvFpyeXjx4TcDE' )) -> getBody ());
$this -> assertSame ( '1aKq8VaGyHohNUUR7RzU1W57Z3hQ6m0YMazAkr2IoiSPsvQJ6QoQutywwiOBlNka' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/announce.php/1aKq8VaGyHohNUUR7RzU1W57Z3hQ6m0YMazAkr2IoiSPsvQJ6QoQutywwiOBlNka' )) -> getBody ());
2025-03-22 19:59:44 +00:00
$this -> assertSame ( '1RJNSRYmxrvXUr////' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/uploads/1RJNSRYmxrvXUr' )) -> getBody ());
$this -> assertSame ( '1RJNSRYmxrvXUr//thumb//' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/uploads/1RJNSRYmxrvXUr-thumb' )) -> getBody ());
$this -> assertSame ( '1RJNSRYmxrvXUr//thumb//jpg' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/uploads/1RJNSRYmxrvXUr-thumb.jpg' )) -> getBody ());
$this -> assertSame ( '1RJNSRYmxrvXUr////jpg' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/uploads/1RJNSRYmxrvXUr.jpg' )) -> getBody ());
2025-03-23 03:38:11 +00:00
$this -> assertSame ( 'hit exact' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/messages/stats' )) -> getBody ());
$this -> assertSame ( 'hit pattern' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/messages/soaps' )) -> getBody ());
2025-03-23 03:45:47 +00:00
$this -> assertSame ( 'hit' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/assets/avatar/' )) -> getBody ());
$this -> assertSame ( 'hit' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/assets/avatar/123/' )) -> getBody ());
2023-09-07 22:08:31 +00:00
}
2024-04-02 17:27:06 +00:00
public function testEEPROMSituation () : void {
2025-02-28 22:44:56 +00:00
$router = new Router ;
2025-03-07 00:25:00 +00:00
$router -> route ( RouteInfo :: pattern ( 'GET' , '#^/uploads/([A-Za-z0-9\-_]+)(?:\.(t|json))?$#uD' , fn ( string $id ) => " Get { $id } " ));
$router -> route ( RouteInfo :: pattern ( 'DELETE' , '#^/uploads/([A-Za-z0-9\-_]+)$#uD' , fn ( string $id ) => " Delete { $id } " ));
2024-04-02 17:27:06 +00:00
2025-03-07 00:25:00 +00:00
// make sure both GET and DELETE are able to execute with a different pattern
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'Get AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/uploads/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' )) -> getBody ());
$this -> assertSame ( 'Delete BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'DELETE' , '/uploads/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' )) -> getBody ());
2024-04-02 17:27:06 +00:00
}
2024-08-18 16:41:02 +00:00
2025-03-02 02:08:45 +00:00
public function testFilterInterceptionOnRoot () : void {
2025-02-28 22:44:56 +00:00
$router = new Router ;
2025-03-07 00:25:00 +00:00
$router -> filter ( FilterInfo :: prefix ( '/' , fn () => 'expected' ));
$router -> route ( RouteInfo :: exact ( 'GET' , '/' , fn () => 'unexpected' ));
$router -> route ( RouteInfo :: exact ( 'GET' , '/test' , fn () => 'also unexpected' ));
2024-08-18 16:41:02 +00:00
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'expected' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/' )) -> getBody ());
$this -> assertSame ( 'expected' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/test' )) -> getBody ());
$this -> assertSame ( 'expected' , ( string ) $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/error' )) -> getBody ());
2025-03-07 00:25:00 +00:00
}
2024-08-18 16:41:02 +00:00
2025-03-07 00:25:00 +00:00
public function testDefaultOptionsImplementation () : void {
$router = new Router ;
$router -> route ( RouteInfo :: exact ( 'GET' , '/test' , fn () => 'get' ));
$router -> route ( RouteInfo :: exact ( 'POST' , '/test' , fn () => 'post' ));
$router -> route ( RouteInfo :: exact ( 'PATCH' , '/test' , fn () => 'patch' ));
2024-08-18 16:41:02 +00:00
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'OPTIONS' , '/test' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'OK' , $response -> getReasonPhrase ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertSame ( 'GET, HEAD, OPTIONS, PATCH, POST' , $response -> getHeaderLine ( 'Allow' ));
2024-08-18 16:41:02 +00:00
}
2025-03-07 23:39:15 +00:00
2025-03-15 02:10:16 +00:00
public function testDefaultProcessorsNoRegister () : void {
$this -> expectException ( RuntimeException :: class );
$this -> expectExceptionMessage ( sprintf ( 'preprocessor "%s" was not found' , 'input:urlencoded:required' ));
$router = new Router ( registerDefaultProcessors : false );
$router -> route ( RouteInfo :: exact (
'GET' , '/soap' ,
#[Before('input:urlencoded:required')]
function () {
return 'test' ;
},
));
$router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/soap' ));
}
public function testDefaultProcessors () : void {
$router = new Router ;
$router -> register ( new class implements RouteHandler {
use RouteHandlerCommon ;
#[Before('input:urlencoded', required: false)]
#[Before('input:multipart', required: false)]
#[ExactRoute('POST', '/optional-form')]
public function formOptional ( ? FormContent $content = null ) : string {
if ( $content instanceof MultipartFormContent )
return 'multipart:' . ( string ) $content -> getParam ( 'test' );
if ( $content instanceof UrlEncodedFormContent )
return 'urlencoded:' . ( string ) $content -> getParam ( 'test' );
return 'none' ;
}
#[Before('input:multipart')]
#[ExactRoute('POST', '/required-multipart')]
public function multipartRequired ( MultipartFormContent $content ) : string {
return ( string ) $content -> getParam ( 'test' );
}
#[Before('input:urlencoded')]
#[ExactRoute('POST', '/required-urlencoded')]
public function urlencodedRequired ( UrlEncodedFormContent $content ) : string {
return ( string ) $content -> getParam ( 'test' );
}
2025-03-15 02:41:14 +00:00
#[After('output:stream')]
#[ExactRoute('GET', '/output/stream')]
public function testOutputStream () : string {
return '<!doctype html><h1>ensuring autodetect gets skipped</h1>' ;
}
#[After('output:plain', charset: 'utf-8')]
#[ExactRoute('GET', '/output/plain')]
public function testOutputPlain () : string {
return '<!doctype html><h1>ensuring autodetect gets skipped</h1>' ;
}
#[After('output:html', charset: 'us-ascii')]
#[ExactRoute('GET', '/output/html')]
public function testOutputHtml () : string {
return '<?xml idk how xml opens the prefix is enough><beans></beans>' ;
}
#[After('output:xml')]
#[ExactRoute('GET', '/output/xml')]
public function testOutputXml () : string {
return 'soup' ;
}
#[After('output:css')]
#[ExactRoute('GET', '/output/css')]
public function testOutputCss () : string {
return '<!doctype html><h1>ensuring autodetect gets skipped</h1>' ;
}
#[After('output:js')]
#[ExactRoute('GET', '/output/js')]
public function testOutputJs () : string {
return '<!doctype html><h1>ensuring autodetect gets skipped</h1>' ;
}
2025-03-19 21:24:52 +00:00
/** @return array{wow: string} */
2025-03-15 02:41:14 +00:00
#[After('output:json', flags: 0)]
#[ExactRoute('GET', '/output/json')]
public function testOutputJson () : array {
return [ 'wow' => 'objects?? / epic!!' ];
}
2025-03-19 21:24:52 +00:00
/** @return array{benben: int} */
2025-03-15 02:41:14 +00:00
#[After('output:bencode')]
#[ExactRoute('GET', '/output/bencode')]
public function testOutputBencode () : array {
return [ 'benben' => 12345 ];
}
2025-03-21 00:04:27 +00:00
#[After('output:bencode')]
#[ExactRoute('GET', '/output/bencode/object')]
public function testOutputBencodeObject () : object {
return new class implements \Index\Bencode\BencodeSerializable {
use \Index\Bencode\BencodeSerializableCommon ;
public function __construct (
#[\Index\Bencode\BencodeProperty('failure reason')]
public private ( set ) string $reason = 'Invalid info hash.'
) {}
};
}
2025-03-15 02:10:16 +00:00
});
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/stream' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'application/octet-stream' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( '<!doctype html><h1>ensuring autodetect gets skipped</h1>' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/plain' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'text/plain;charset=utf-8' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( '<!doctype html><h1>ensuring autodetect gets skipped</h1>' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/html' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'text/html;charset=us-ascii' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( '<?xml idk how xml opens the prefix is enough><beans></beans>' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/xml' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'application/xml' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( 'soup' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/css' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'text/css' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( '<!doctype html><h1>ensuring autodetect gets skipped</h1>' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/js' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'application/javascript' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( '<!doctype html><h1>ensuring autodetect gets skipped</h1>' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/json' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'application/json' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( '{"wow":"objects?? \/ epic!!"}' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/bencode' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 'application/x-bittorrent' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( 'd6:benbeni12345ee' , ( string ) $response -> getBody ());
2025-03-15 02:41:14 +00:00
2025-03-21 00:04:27 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/output/bencode/object' ));
$this -> assertSame ( 'application/x-bittorrent' , $response -> getHeaderLine ( 'Content-Type' ));
$this -> assertSame ( 'd14:failure reason18:Invalid info hash.e' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'POST' , '/optional-form' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'none' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/optional-form' , [], Stream :: createStream ( 'test=mewow' )));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'none' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/optional-form' , [ 'Content-Type' => [ 'application/x-www-form-urlencoded' ]], Stream :: createStream ( 'test=mewow' )));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'urlencoded:mewow' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
2025-03-15 02:48:59 +00:00
// an empty string is valid too
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/optional-form' , [ 'Content-Type' => [ 'application/x-www-form-urlencoded' ]], Stream :: createStream ( '' )));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'urlencoded:' , ( string ) $response -> getBody ());
2025-03-15 02:48:59 +00:00
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/optional-form' , [ 'Content-Type' => [ 'multipart/form-data; boundary="--soap12345"' ]], Stream :: createStream ( implode ( " \r \n " , [
'----soap12345' ,
'Content-Disposition: form-data; name="test"' ,
'' ,
'wowof' ,
'----soap12345--' ,
'' ,
]))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'multipart:wowof' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
2025-03-15 02:48:59 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/optional-form' , [ 'Content-Type' => [ 'multipart/form-data; boundary="--soap12345"' ]], Stream :: createStream ( implode ( " \r \n " , [
'----soap12345--' ,
'' ,
]))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'multipart:' , ( string ) $response -> getBody ());
2025-03-15 02:48:59 +00:00
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'POST' , '/required-urlencoded' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 400 , $response -> getStatusCode ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'POST' , '/required-multipart' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 400 , $response -> getStatusCode ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/required-urlencoded' , [ 'Content-Type' => [ 'application/x-www-form-urlencoded' ]], Stream :: createStream ( 'test=meow' )));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'meow' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/required-multipart' , [ 'Content-Type' => [ 'multipart/form-data; boundary="--soap56789"' ]], Stream :: createStream ( implode ( " \r \n " , [
'----soap56789' ,
'Content-Disposition: form-data; name="test"' ,
'' ,
'woof' ,
'----soap56789--' ,
'' ,
]))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( 'woof' , ( string ) $response -> getBody ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/required-urlencoded' , [ 'Content-Type' => [ 'multipart/form-data; boundary="--soap56789"' ]], Stream :: createStream ( 'test=meow' )));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 400 , $response -> getStatusCode ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/required-multipart' , [ 'Content-Type' => [ 'application/x-www-form-urlencoded' ]], Stream :: createStream ( implode ( " \r \n " , [
'----soap56789' ,
'Content-Disposition: form-data; name="test"' ,
'' ,
'woof' ,
'----soap56789--' ,
'' ,
]))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 400 , $response -> getStatusCode ());
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/required-multipart' , [ 'Content-Type' => [ 'multipart/form-data' ]], Stream :: createStream ( implode ( " \r \n " , [
'----aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ,
'Content-Disposition: form-data; name="test"' ,
'' ,
'the' ,
'----aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--' ,
'' ,
]))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 400 , $response -> getStatusCode ());
2025-03-15 02:10:16 +00:00
}
2025-03-07 23:39:15 +00:00
public function testProcessors () : void {
$router = new Router ;
$router -> register ( new class implements RouteHandler {
use RouteHandlerCommon ;
#[Preprocessor('base64-decode-body')]
public function decodePre ( HandlerContext $context , HttpRequest $request ) : void {
$context -> addArgument ( base64_decode (( string ) $request -> getBody ()));
}
#[Postprocessor('crash')]
public function crashPost () : void {
throw new RuntimeException ( 'this shouldnt run!' );
}
#[Postprocessor('json-encode')]
public function encodePost ( HandlerContext $context , int $flags ) : void {
$context -> halt ();
$context -> response -> setTypeJson ();
2025-03-12 20:56:48 +00:00
$context -> response -> body = Stream :: createStream (
2025-03-07 23:39:15 +00:00
json_encode ( $context -> result , JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR | $flags )
);
}
/** @return array{data: string} */
#[ExactRoute('POST', '/test')]
#[Before('base64-decode-body')]
#[After('json-encode', flags: JSON_PRETTY_PRINT)]
#[After('crash')]
public function route ( string $decoded ) : array {
return [ 'data' => $decoded ];
}
});
$router -> preprocessor ( ProcessorInfo :: pre ( 'intercept' , function ( HttpResponseBuilder $response ) {
$response -> statusCode = 403 ;
return 'it can work like a filter too' ;
}));
$router -> route ( RouteInfo :: exact (
'PUT' , '/alternate' ,
#[Before('base64-decode-body')]
#[After('json-encode', flags: JSON_PRETTY_PRINT)]
function ( HttpRequest $request , string $decoded ) : array {
return [ 'path' => $request -> uri -> path , 'data' => $decoded ];
}
));
$router -> route ( RouteInfo :: exact (
'GET' , '/filtered' ,
#[Before('intercept')]
#[Before('base64-decode-body')]
function () : string {
return 'should not get here' ;
}
));
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'POST' , '/test' , [], Stream :: createStream ( base64_encode ( 'mewow' ))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( " { \n \" data \" : \" mewow \" \n } " , ( string ) $response -> getBody ());
2025-03-07 23:39:15 +00:00
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithBody ( 'PUT' , '/alternate' , [], Stream :: createStream ( base64_encode ( 'soap' ))));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( " { \n \" path \" : \" /alternate \" , \n \" data \" : \" soap \" \n } " , ( string ) $response -> getBody ());
2025-03-07 23:39:15 +00:00
2025-03-15 02:10:16 +00:00
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'GET' , '/filtered' ));
2025-03-19 21:24:52 +00:00
$this -> assertSame ( 403 , $response -> getStatusCode ());
$this -> assertSame ( 'it can work like a filter too' , ( string ) $response -> getBody ());
}
public function testAccessControl () : void {
$router = new Router ;
$router -> register ( new class implements RouteHandler {
use RouteHandlerCommon ;
#[ExactRoute('GET', '/nothing')]
public function nothing () : void {}
#[AccessControl]
#[ExactRoute('GET', '/acld')]
public function getAccessControlDifferent () : void {}
#[ExactRoute('POST', '/acld')]
public function postAccessControlDifferent () : void {}
#[AccessControl]
#[ExactRoute('GET', '/copdodnop')]
public function getCredentialsOnPostDenyOnDeleteNothingOnPut () : void {}
#[AccessControl(credentials: true)]
#[ExactRoute('POST', '/copdodnop')]
public function postCredentialsOnPostDenyOnDeleteNothingOnPut () : void {}
#[AccessControl(allow: false)]
#[ExactRoute('DELETE', '/copdodnop')]
public function deleteCredentialsOnPostDenyOnDeleteNothingOnPut () : void {}
#[ExactRoute('PUT', '/copdodnop')]
public function putCredentialsOnPostDenyOnDeleteNothingOnPut () : void {}
#[AccessControl(allowMethods: ['HEAD'])]
#[ExactRoute('GET', '/methods/extra')]
public function getMethodsExtra () : void {}
#[AccessControl(allowHeaders: true)]
#[ExactRoute('GET', '/headers/allow-all')]
public function getHeadersAllowAll () : void {}
#[AccessControl(allowHeaders: ['Authorization', 'X-Content-Index', 'Content-Type'])]
#[ExactRoute('GET', '/headers/allow-specific')]
public function getHeadersAllowSpecific () : void {}
#[AccessControl]
#[ExactRoute('GET', '/headers/expose-safe')]
public function getHeadersExposeSafe () : void {}
#[AccessControl(exposeHeaders: true)]
#[ExactRoute('GET', '/headers/expose-all')]
public function getHeadersExposeAll () : void {}
#[AccessControl(exposeHeaders: ['X-EEPROM-Max-Size', 'Vary'])]
#[ExactRoute('GET', '/headers/expose-specific')]
public function getHeadersExposeSpecific () : void {}
// including a little curveball! i'm sure this won't lead to confusion
#[AccessControl(allow: true, credentials: true, allowMethods: ['POST', 'HEAD'], allowHeaders: ['Content-Length', 'X-Content-Index'], exposeHeaders: ['X-Satori-Time', 'X-Satori-Hash'])]
#[ExactRoute('GET', '/all-together-now')]
public function getAllTogetherNow () : void {}
#[ExactRoute('POST', '/all-together-now')]
public function postAllTogetherNow () : void {}
});
$routeWithNo = RouteInfo :: exact (
'PUT' , '/no-override' ,
#[AccessControl(allow: false)]
function () : void {}
);
$routeWithNo -> accessControl = new AccessControl ; // allow: true
$router -> route ( $routeWithNo );
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody ( 'OPTIONS' , '/nothing' ));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertSame ( 'GET, HEAD, OPTIONS' , $response -> getHeaderLine ( 'Allow' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/nothing' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/nothing' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/no-override' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'PUT' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'PUT' , '/no-override' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/acld' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/acld' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'POST' , '/acld' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'POST' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertSame ( 'true' , $response -> getHeaderLine ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( 'https://railgun.sh' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'POST' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertSame ( 'true' , $response -> getHeaderLine ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( 'https://railgun.sh' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'DELETE' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'DELETE' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'PUT' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'PUT' , '/copdodnop' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/methods/extra' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'HEAD' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, HEAD' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/methods/extra' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'HEAD' , '/methods/extra' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/allow-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/allow-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
'Access-Control-Request-Headers' => [ 'X-Soap' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/headers/allow-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/allow-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
'Access-Control-Request-Headers' => [ '' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/headers/allow-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/allow-specific' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/allow-specific' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
'Access-Control-Request-Headers' => [ 'X-Content-Index' , 'Authorization' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertSame ( 'Authorization, X-Content-Index' , $response -> getHeaderLine ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/allow-specific' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
'Access-Control-Request-Headers' => [ 'X-Beans' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/headers/allow-specific' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/expose-safe' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/headers/expose-safe' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/expose-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/headers/expose-all' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertTrue ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/headers/expose-specific' ,
[
'Origin' => [ 'https://railgun.sh' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/headers/expose-specific' ,
[
'Origin' => [ 'https://railgun.sh' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertTrue ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( 'Vary, X-EEPROM-Max-Size' , $response -> getHeaderLine ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/all-together-now' ,
[
'Origin' => [ 'https://flash.moe:8443' ],
'Access-Control-Request-Method' => [ 'GET' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertSame ( 'true' , $response -> getHeaderLine ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, HEAD, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( 'https://flash.moe:8443' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/all-together-now' ,
[
'Origin' => [ 'https://flash.moe:8443' ],
'Access-Control-Request-Method' => [ 'GET' ],
'Access-Control-Request-Headers' => [ '' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertSame ( 'true' , $response -> getHeaderLine ( 'Access-Control-Allow-Credentials' ));
$this -> assertTrue ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( '' , $response -> getHeaderLine ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, HEAD, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( 'https://flash.moe:8443' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/all-together-now' ,
[
'Origin' => [ 'https://flash.moe:8443' ],
'Access-Control-Request-Method' => [ 'GET' ],
'Access-Control-Request-Headers' => [ 'x-content-index' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertSame ( 'true' , $response -> getHeaderLine ( 'Access-Control-Allow-Credentials' ));
$this -> assertSame ( 'x-content-index' , $response -> getHeaderLine ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, HEAD, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( 'https://flash.moe:8443' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'GET' , '/all-together-now' ,
[
'Origin' => [ 'https://flash.moe:8443' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertSame ( 'true' , $response -> getHeaderLine ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( 'https://flash.moe:8443' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertSame ( 'X-Satori-Hash, X-Satori-Time' , $response -> getHeaderLine ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
// although routes can declare other methods than their own as CORS supported,
// allow credentials and headers ONLY apply to their own method
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'OPTIONS' , '/all-together-now' ,
[
'Origin' => [ 'https://flash.moe:8443' ],
'Access-Control-Request-Method' => [ 'POST' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertSame ( '0' , $response -> getHeaderLine ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertSame ( 'GET, HEAD, POST' , $response -> getHeaderLine ( 'Access-Control-Allow-Methods' ));
$this -> assertSame ( '*' , $response -> getHeaderLine ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertSame ( '300' , $response -> getHeaderLine ( 'Access-Control-Max-Age' ));
$response = $router -> handle ( HttpRequest :: createRequestWithoutBody (
'POST' , '/all-together-now' ,
[
'Origin' => [ 'https://flash.moe:8443' ],
],
));
$this -> assertSame ( 200 , $response -> getStatusCode ());
$this -> assertFalse ( $response -> hasHeader ( 'Content-Length' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Credentials' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Methods' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Allow-Origin' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Expose-Headers' ));
$this -> assertFalse ( $response -> hasHeader ( 'Access-Control-Max-Age' ));
2025-03-07 23:39:15 +00:00
}
2022-09-13 15:13:11 +02:00
}