2017-08-01 16:52:45 +00:00
|
|
|
<?php
|
2021-04-13 20:13:48 +00:00
|
|
|
|
2017-08-01 16:52:45 +00:00
|
|
|
/**
|
|
|
|
* Keep in sync with /test/middleware-mockserver.js
|
|
|
|
*/
|
2021-04-13 20:13:48 +00:00
|
|
|
function cleanCallback( $callback ) {
|
|
|
|
return preg_replace( '/[^a-z0-9_]/i', '', $callback );
|
|
|
|
}
|
|
|
|
|
2017-08-01 16:52:45 +00:00
|
|
|
class MockServer {
|
|
|
|
protected function contentType( $req ) {
|
|
|
|
$type = $req->query['contentType'];
|
|
|
|
header("Content-type: $type");
|
|
|
|
echo $req->query['response'];
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function wait( $req ) {
|
|
|
|
$wait = (int) $req->query['wait'];
|
|
|
|
sleep( $wait );
|
|
|
|
if ( isset( $req->query['script'] ) ) {
|
|
|
|
header( 'Content-type: text/javascript' );
|
|
|
|
} else {
|
|
|
|
header( 'Content-type: text/html' );
|
2019-02-18 18:02:38 +00:00
|
|
|
echo 'ERROR <script>QUnit.assert.ok( true, "mock executed" );</script>';
|
2017-08-01 16:52:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function name( $req ) {
|
|
|
|
if ( $req->query['name'] === 'foo' ) {
|
|
|
|
echo 'bar';
|
|
|
|
} elseif ( $_POST['name'] === 'peter' ) {
|
|
|
|
echo 'pan';
|
|
|
|
} else {
|
|
|
|
echo 'ERROR';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function xml( $req ) {
|
|
|
|
header( 'Content-type: text/xml' );
|
|
|
|
if ( $req->query['cal'] !== '5-2' && $_POST['cal'] !== '5-2' ) {
|
|
|
|
echo '<error>ERROR</error>';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
echo "<math><calculation>5-2</calculation><result>3</result></math>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function atom( $req ) {
|
|
|
|
header( 'Content-type: atom+xml' );
|
|
|
|
echo '<root><element /></root>';
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function script( $req ) {
|
|
|
|
if ( isset( $req->query['header'] ) ) {
|
|
|
|
if ( $req->query['header'] === 'ecma' ) {
|
|
|
|
header( 'Content-type: application/ecmascript' );
|
|
|
|
} else {
|
|
|
|
header( 'Content-type: text/javascript' );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
header( 'Content-type: text/html' );
|
|
|
|
}
|
2020-09-22 15:30:18 +00:00
|
|
|
|
|
|
|
if ( !empty( $req->query['cors'] ) ) {
|
|
|
|
header( "Access-Control-Allow-Origin: *" );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !empty( $req->query['callback'] ) ) {
|
|
|
|
$headers = array_combine(
|
|
|
|
array_map( 'strtolower', array_keys( $req->headers ) ),
|
|
|
|
array_values( $req->headers )
|
|
|
|
);
|
|
|
|
|
2021-04-13 20:13:48 +00:00
|
|
|
echo cleanCallback( $req->query['callback'] ) .
|
|
|
|
"(" . json_encode( [ 'headers' => $headers ] ) . ")";
|
2020-09-22 15:30:18 +00:00
|
|
|
} else {
|
|
|
|
echo 'QUnit.assert.ok( true, "mock executed" );';
|
|
|
|
}
|
2017-08-01 16:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Used to be in test.js, but was renamed to testbar.php
|
|
|
|
// https://github.com/jquery/jquery/commit/d89c278a33#commitcomment-23423165
|
|
|
|
protected function testbar( $req ) {
|
|
|
|
echo 'this.testBar = "bar";
|
|
|
|
jQuery("#ap").html("bar");
|
2019-02-18 18:02:38 +00:00
|
|
|
QUnit.assert.ok( true, "mock executed");';
|
2017-08-01 16:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function json( $req ) {
|
|
|
|
if ( isset( $req->query['header'] ) ) {
|
|
|
|
header( 'Content-type: application/json' );
|
|
|
|
}
|
|
|
|
|
2020-07-27 17:15:57 +00:00
|
|
|
if ( isset( $req->query['cors'] ) ) {
|
|
|
|
header( 'Access-Control-Allow-Origin: *' );
|
|
|
|
}
|
|
|
|
|
2017-08-01 16:52:45 +00:00
|
|
|
if ( isset( $req->query['array'] ) ) {
|
|
|
|
echo '[ {"name": "John", "age": 21}, {"name": "Peter", "age": 25 } ]';
|
|
|
|
} else {
|
|
|
|
echo '{ "data": {"lang": "en", "length": 25} }';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function jsonp( $req ) {
|
|
|
|
if ( isset( $req->query['callback'] ) ) {
|
|
|
|
$callback = $req->query['callback'];
|
|
|
|
} elseif ( $req->method === 'GET' ) {
|
|
|
|
// Try REST-like path
|
|
|
|
preg_match( '/\/([^\/?]+)\?.+$/', $req->url, $m );
|
|
|
|
$callback = $m[1];
|
|
|
|
} else {
|
|
|
|
$callback = $_POST['callback'];
|
|
|
|
}
|
2021-04-13 20:13:48 +00:00
|
|
|
$json = isset( $req->query['array'] ) ?
|
|
|
|
'[ { "name": "John", "age": 21 }, { "name": "Peter", "age": 25 } ]' :
|
|
|
|
'{ "data": { "lang": "en", "length": 25 } }';
|
|
|
|
echo cleanCallback( $callback ) . '(' . $json . ')';
|
2017-08-01 16:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function xmlOverJsonp( $req ) {
|
|
|
|
$callback = $_REQUEST['callback'];
|
2021-04-13 20:13:48 +00:00
|
|
|
$cleanCallback = cleanCallback( $callback );
|
2017-08-01 16:52:45 +00:00
|
|
|
$text = json_encode( file_get_contents( __DIR__ . '/with_fries.xml' ) );
|
2021-04-13 20:13:48 +00:00
|
|
|
echo "$cleanCallback($text)\n";
|
2017-08-01 16:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function error( $req ) {
|
|
|
|
header( 'HTTP/1.0 400 Bad Request' );
|
|
|
|
if ( isset( $req->query['json'] ) ) {
|
|
|
|
header( 'Content-Type: application/json' );
|
|
|
|
echo '{ "code": 40, "message": "Bad Request" }';
|
|
|
|
} else {
|
|
|
|
echo 'plain text message';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function headers( $req ) {
|
|
|
|
header( 'Sample-Header: Hello World' );
|
|
|
|
header( 'Empty-Header: ' );
|
|
|
|
header( 'Sample-Header2: Hello World 2' );
|
2018-11-26 17:00:41 +00:00
|
|
|
header( 'List-Header: Item 1' );
|
2018-11-26 17:46:58 +00:00
|
|
|
header( 'list-header: Item 2', FALSE );
|
2018-11-26 17:00:41 +00:00
|
|
|
header( 'constructor: prototype collision (constructor)' );
|
2017-08-01 16:52:45 +00:00
|
|
|
|
|
|
|
foreach ( explode( '|' , $req->query[ 'keys' ] ) as $key ) {
|
|
|
|
// Only echo if key exists in the header
|
|
|
|
if ( isset( $req->headers[ strtoupper( $key ) ] ) ) {
|
|
|
|
echo "$key: " . $req->headers[ strtoupper( $key ) ] . "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function echoData( $req ) {
|
|
|
|
echo file_get_contents('php://input');
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function echoQuery( $req ) {
|
|
|
|
echo $_SERVER['QUERY_STRING'];
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function echoMethod( $req ) {
|
|
|
|
echo $req->method;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function echoHtml( $req ) {
|
|
|
|
header( 'Content-type: text/html' );
|
|
|
|
echo '<div id="method">' . $req->method . '</div>';
|
|
|
|
echo '<div id="query">' . $_SERVER['QUERY_STRING'] . '</div>';
|
|
|
|
echo '<div id="data">' . file_get_contents('php://input') . '</div>';
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function etag( $req ) {
|
|
|
|
$hash = md5( $req->query['ts'] );
|
|
|
|
$etag = 'W/"' . $hash . '"';
|
|
|
|
|
|
|
|
$ifNoneMatch = isset( $req->headers['IF-NONE-MATCH'] ) ? $req->headers['IF-NONE-MATCH'] : '';
|
|
|
|
if ($ifNoneMatch === $etag) {
|
|
|
|
header('HTTP/1.0 304 Not Modified');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
header("Etag: $etag");
|
|
|
|
echo "ETag: $etag\n";
|
|
|
|
if ( $ifNoneMatch ) {
|
|
|
|
echo "If-None-Match: $ifNoneMatch\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function ims( $req ) {
|
|
|
|
$ts = $req->query['ts'];
|
|
|
|
|
|
|
|
$ims = isset( $req->headers['IF-MODIFIED-SINCE'] ) ? $req->headers['IF-MODIFIED-SINCE'] : '';
|
|
|
|
if ($ims === $ts) {
|
|
|
|
header('HTTP/1.0 304 Not Modified');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
header("Last-Modified: $ts");
|
|
|
|
echo "Last-Modified: $ts\n";
|
|
|
|
if ( $ims ) {
|
|
|
|
echo "If-Modified-Since: $ims\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function status( $req ) {
|
|
|
|
header( "HTTP/1.0 {$req->query['code']} {$req->query['text']}" );
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function testHTML( $req ) {
|
|
|
|
header( 'Content-type: text/html' );
|
|
|
|
$html = file_get_contents( __DIR__ . '/test.include.html' );
|
|
|
|
$html = str_replace( '{{baseURL}}', $req->query['baseURL'], $html );
|
|
|
|
echo $html;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function cspFrame( $req ) {
|
|
|
|
header( "Content-Security-Policy: default-src 'self'; report-uri ./mock.php?action=cspLog" );
|
|
|
|
header( 'Content-type: text/html' );
|
|
|
|
echo file_get_contents( __DIR__ . '/csp.include.html' );
|
|
|
|
}
|
|
|
|
|
2019-01-14 18:29:54 +00:00
|
|
|
protected function cspNonce( $req ) {
|
2019-01-21 17:42:39 +00:00
|
|
|
$test = $req->query['test'] ? '-' . $req->query['test'] : '';
|
2019-01-14 18:29:54 +00:00
|
|
|
header( "Content-Security-Policy: script-src 'nonce-jquery+hardcoded+nonce'; report-uri ./mock.php?action=cspLog" );
|
|
|
|
header( 'Content-type: text/html' );
|
2019-01-21 17:42:39 +00:00
|
|
|
echo file_get_contents( __DIR__ . '/csp-nonce' . $test . '.html' );
|
2019-01-14 18:29:54 +00:00
|
|
|
}
|
|
|
|
|
2020-08-25 19:28:30 +00:00
|
|
|
protected function cspAjaxScript( $req ) {
|
|
|
|
header( "Content-Security-Policy: script-src 'self'; report-uri /base/test/data/mock.php?action=cspLog" );
|
|
|
|
header( 'Content-type: text/html' );
|
|
|
|
echo file_get_contents( __DIR__ . '/csp-ajax-script.html' );
|
|
|
|
}
|
|
|
|
|
2017-08-01 16:52:45 +00:00
|
|
|
protected function cspLog( $req ) {
|
|
|
|
file_put_contents( $this->cspFile, 'error' );
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function cspClean( $req ) {
|
|
|
|
file_put_contents( $this->cspFile, '' );
|
|
|
|
unlink( $this->cspFile );
|
|
|
|
}
|
|
|
|
|
2019-04-26 14:25:08 +00:00
|
|
|
protected function errorWithScript( $req ) {
|
|
|
|
header( 'HTTP/1.0 404 Not Found' );
|
|
|
|
if ( isset( $req->query['withScriptContentType'] ) ) {
|
|
|
|
header( 'Content-Type: application/javascript' );
|
|
|
|
}
|
|
|
|
if ( isset( $req->query['callback'] ) ) {
|
|
|
|
$callback = $req->query['callback'];
|
2021-04-13 20:13:48 +00:00
|
|
|
echo cleanCallback( $callback ) . '( {"status": 404, "msg": "Not Found"} )';
|
2019-04-26 14:25:08 +00:00
|
|
|
} else {
|
|
|
|
echo 'QUnit.assert.ok( false, "Mock return erroneously executed" );';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 16:52:45 +00:00
|
|
|
public function __construct() {
|
|
|
|
$this->cspFile = __DIR__ . '/support/csp.log';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function respond( stdClass $req ) {
|
|
|
|
if ( !isset( $req->query['action'] ) || !method_exists( $this, $req->query['action'] ) ) {
|
|
|
|
header( "HTTP/1.0 400 Bad Request" );
|
|
|
|
echo "Invalid action query.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$this->{$req->query['action']}( $req );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't include PHP errors in http response
|
|
|
|
error_reporting( 0 );
|
|
|
|
|
|
|
|
// Collect headers
|
|
|
|
$headers = array();
|
|
|
|
foreach ( $_SERVER as $name => $value ) {
|
|
|
|
if ( substr( $name, 0, 5 ) === 'HTTP_' ) {
|
|
|
|
$name = str_replace( '_', '-', substr( $name, 5 ) );
|
|
|
|
$headers[$name] = $value;
|
|
|
|
} elseif ( $name === 'CONTENT_LENGTH' ) {
|
|
|
|
$headers['CONTENT-LENGTH'] = $value;
|
|
|
|
} elseif ( $name === 'CONTENT_TYPE' ) {
|
|
|
|
$headers['CONTENT-TYPE'] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$mock = new MockServer();
|
|
|
|
$req = (object) array(
|
|
|
|
'query' => $_GET,
|
|
|
|
'headers' => $headers,
|
|
|
|
'method' => $_SERVER['REQUEST_METHOD'],
|
|
|
|
'url' => $_SERVER['REQUEST_URI'],
|
|
|
|
);
|
|
|
|
$mock->respond( $req );
|