|  | /* 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 | 
|  | */ | 
|  | function cleanCallback( callback ) { | 
|  | return callback.replace( /[^a-z0-9_]/gi, "" ); | 
|  | } | 
|  |  | 
|  | 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( cleanCallback( 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( cleanCallback( 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, { "Content-Type": "text/html; charset=UTF-8" } ); | 
|  | } | 
|  | if ( req.query.callback ) { | 
|  | resp.end( cleanCallback( 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; |