| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /* eslint-env node */
- var url = require( "url" );
- var fs = require( "fs" );
- var getRawBody = require( "raw-body" );
- var cspLog = "";
- /**
- * Keep in sync with /test/mock.php
- */
- var mocks = {
- contentType: function( req, resp ) {
- resp.writeHead( 200, {
- "content-type": req.query.contentType
- } );
- resp.end( req.query.response );
- },
- wait: function( req, resp ) {
- var wait = Number( req.query.wait ) * 1000;
- setTimeout( function() {
- if ( req.query.script ) {
- resp.writeHead( 200, { "content-type": "text/javascript" } );
- } else {
- resp.writeHead( 200, { "content-type": "text/html" } );
- resp.end( "ERROR <script>QUnit.assert.ok( true, \"mock executed\" );</script>" );
- }
- }, wait );
- },
- name: function( req, resp, next ) {
- resp.writeHead( 200 );
- if ( req.query.name === "foo" ) {
- resp.end( "bar" );
- return;
- }
- getBody( req ).then( function( body ) {
- if ( body === "name=peter" ) {
- resp.end( "pan" );
- } else {
- resp.end( "ERROR" );
- }
- }, next );
- },
- xml: function( req, resp, next ) {
- var content = "<math><calculation>5-2</calculation><result>3</result></math>";
- resp.writeHead( 200, { "content-type": "text/xml" } );
- if ( req.query.cal === "5-2" ) {
- resp.end( content );
- return;
- }
- getBody( req ).then( function( body ) {
- if ( body === "cal=5-2" ) {
- resp.end( content );
- } else {
- resp.end( "<error>ERROR</error>" );
- }
- }, next );
- },
- atom: function( req, resp, next ) {
- resp.writeHead( 200, { "content-type": "atom+xml" } );
- resp.end( "<root><element /></root>" );
- },
- script: function( req, resp ) {
- if ( req.query.header === "ecma" ) {
- resp.writeHead( 200, { "content-type": "application/ecmascript" } );
- } else if ( "header" in req.query ) {
- resp.writeHead( 200, { "content-type": "text/javascript" } );
- } else {
- resp.writeHead( 200, { "content-type": "text/html" } );
- }
- resp.end( "QUnit.assert.ok( true, \"mock executed\" );" );
- },
- testbar: function( req, resp ) {
- resp.writeHead( 200 );
- resp.end(
- "this.testBar = 'bar'; " +
- "jQuery('#ap').html('bar'); " +
- "QUnit.assert.ok( true, 'mock executed');"
- );
- },
- json: function( req, resp ) {
- if ( req.query.header ) {
- resp.writeHead( 200, { "content-type": "application/json" } );
- }
- if ( req.query.array ) {
- resp.end( JSON.stringify(
- [ { name: "John", age: 21 }, { name: "Peter", age: 25 } ]
- ) );
- } else {
- resp.end( JSON.stringify(
- { data: { lang: "en", length: 25 } }
- ) );
- }
- },
- jsonp: function( req, resp, next ) {
- var callback;
- if ( Array.isArray( req.query.callback ) ) {
- callback = Promise.resolve( req.query.callback[ req.query.callback.length - 1 ] );
- } else if ( req.query.callback ) {
- callback = Promise.resolve( req.query.callback );
- } else if ( req.method === "GET" ) {
- callback = Promise.resolve( req.url.match( /^.+\/([^\/?]+)\?.+$/ )[ 1 ] );
- } else {
- callback = getBody( req ).then( function( body ) {
- return body.trim().replace( "callback=", "" );
- } );
- }
- var json = req.query.array ?
- JSON.stringify(
- [ { name: "John", age: 21 }, { name: "Peter", age: 25 } ]
- ) :
- JSON.stringify(
- { data: { lang: "en", length: 25 } }
- );
- callback.then( function( cb ) {
- resp.end( cb + "(" + json + ")" );
- }, next );
- },
- xmlOverJsonp: function( req, resp ) {
- var callback = req.query.callback;
- var body = fs.readFileSync( __dirname + "/data/with_fries.xml" ).toString();
- resp.writeHead( 200 );
- resp.end( callback + "(" + JSON.stringify( body ) + ")\n" );
- },
- error: function( req, resp ) {
- if ( req.query.json ) {
- resp.writeHead( 400, { "content-type": "application/json" } );
- resp.end( "{ \"code\": 40, \"message\": \"Bad Request\" }" );
- } else {
- resp.writeHead( 400 );
- resp.end( "plain text message" );
- }
- },
- headers: function( req, resp ) {
- resp.writeHead( 200, {
- "Sample-Header": "Hello World",
- "Empty-Header": "",
- "Sample-Header2": "Hello World 2",
- "List-Header": "Item 1",
- "list-header": "Item 2",
- "constructor": "prototype collision (constructor)"
- } );
- req.query.keys.split( "|" ).forEach( function( key ) {
- if ( req.headers[ key.toLowerCase() ] ) {
- resp.write( key + ": " + req.headers[ key.toLowerCase() ] + "\n" );
- }
- } );
- resp.end();
- },
- echoData: function( req, resp, next ) {
- getBody( req ).then( function( body ) {
- resp.end( body );
- }, next );
- },
- echoQuery: function( req, resp ) {
- resp.end( req.parsed.search.slice( 1 ) );
- },
- echoMethod: function( req, resp ) {
- resp.end( req.method );
- },
- echoHtml: function( req, resp, next ) {
- resp.writeHead( 200, { "Content-Type": "text/html" } );
- resp.write( "<div id='method'>" + req.method + "</div>" );
- resp.write( "<div id='query'>" + req.parsed.search.slice( 1 ) + "</div>" );
- getBody( req ).then( function( body ) {
- resp.write( "<div id='data'>" + body + "</div>" );
- resp.end( body );
- }, next );
- },
- etag: function( req, resp ) {
- var hash = Number( req.query.ts ).toString( 36 );
- var etag = "W/\"" + hash + "\"";
- if ( req.headers[ "if-none-match" ] === etag ) {
- resp.writeHead( 304 );
- resp.end();
- return;
- }
- resp.writeHead( 200, {
- "Etag": etag
- } );
- resp.end();
- },
- ims: function( req, resp, next ) {
- var ts = req.query.ts;
- if ( req.headers[ "if-modified-since" ] === ts ) {
- resp.writeHead( 304 );
- resp.end();
- return;
- }
- resp.writeHead( 200, {
- "Last-Modified": ts
- } );
- resp.end();
- },
- status: function( req, resp, next ) {
- resp.writeHead( Number( req.query.code ) );
- resp.end();
- },
- testHTML: function( req, resp ) {
- resp.writeHead( 200, { "Content-Type": "text/html" } );
- var body = fs.readFileSync( __dirname + "/data/test.include.html" ).toString();
- body = body.replace( /{{baseURL}}/g, req.query.baseURL );
- resp.end( body );
- },
- cspFrame: function( req, resp ) {
- resp.writeHead( 200, {
- "Content-Type": "text/html",
- "Content-Security-Policy": "default-src 'self'; report-uri /base/test/data/mock.php?action=cspLog"
- } );
- var body = fs.readFileSync( __dirname + "/data/csp.include.html" ).toString();
- resp.end( body );
- },
- cspNonce: function( req, resp ) {
- var testParam = req.query.test ? "-" + req.query.test : "";
- resp.writeHead( 200, {
- "Content-Type": "text/html",
- "Content-Security-Policy": "script-src 'nonce-jquery+hardcoded+nonce'; report-uri /base/test/data/mock.php?action=cspLog"
- } );
- var body = fs.readFileSync(
- __dirname + "/data/csp-nonce" + testParam + ".html" ).toString();
- resp.end( body );
- },
- cspLog: function( req, resp ) {
- cspLog = "error";
- resp.writeHead( 200 );
- resp.end();
- },
- cspClean: function( req, resp ) {
- cspLog = "";
- resp.writeHead( 200 );
- resp.end();
- },
- errorWithScript: function( req, resp ) {
- if ( req.query.withScriptContentType ) {
- resp.writeHead( 404, { "Content-Type": "application/javascript" } );
- } else {
- resp.writeHead( 404 );
- }
- if ( req.query.callback ) {
- resp.end( req.query.callback + "( {\"status\": 404, \"msg\": \"Not Found\"} )" );
- } else {
- resp.end( "QUnit.assert.ok( false, \"Mock return erroneously executed\" );" );
- }
- }
- };
- var handlers = {
- "test/data/mock.php": function( req, resp, next ) {
- if ( !mocks[ req.query.action ] ) {
- resp.writeHead( 400 );
- resp.end( "Invalid action query.\n" );
- console.log( "Invalid action query:", req.method, req.url );
- return;
- }
- mocks[ req.query.action ]( req, resp, next );
- },
- "test/data/support/csp.log": function( req, resp ) {
- resp.writeHead( 200 );
- resp.end( cspLog );
- },
- "test/data/404.txt": function( req, resp ) {
- resp.writeHead( 404 );
- resp.end( "" );
- }
- };
- /**
- * Connect-compatible middleware factory for mocking server responses.
- * Used by Ajax unit tests when run via Karma.
- *
- * Despite Karma using Express, it uses Connect to deal with custom middleware,
- * which passes the raw Node Request and Response objects instead of the
- * Express versions of these (e.g. no req.path, req.query, resp.set).
- */
- function MockserverMiddlewareFactory() {
- /**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} resp
- * @param {Function} next Continue request handling
- */
- return function( req, resp, next ) {
- var parsed = url.parse( req.url, /* parseQuery */ true ),
- path = parsed.pathname.replace( /^\/base\//, "" ),
- query = parsed.query,
- subReq = Object.assign( Object.create( req ), {
- query: query,
- parsed: parsed
- } );
- if ( /^test\/data\/mock.php\//.test( path ) ) {
- // Support REST-like Apache PathInfo
- path = "test\/data\/mock.php";
- }
- if ( !handlers[ path ] ) {
- next();
- return;
- }
- handlers[ path ]( subReq, resp, next );
- };
- }
- function getBody( req ) {
- return req.method !== "POST" ?
- Promise.resolve( "" ) :
- getRawBody( req, {
- encoding: true
- } );
- }
- module.exports = MockserverMiddlewareFactory;
|