server/wd-hub.js (73 lines of code) (raw):
const Promise = require('bluebird');
const path = require('path');
const fs = require('fs-extra');
const outputFile = Promise.promisify(fs.outputFile);
const router = require('express').Router();
const config = require('../lib/config');
const { logger } = require('../lib/log');
const rawBodyParser = require('../lib/raw-body-parser');
const proxyRequest = require('../lib/proxy-request');
const logUtils = require('../lib/selenium-log-utils');
const uid = require('../lib/unique-id');
const createSeleniumError = require ('../lib/create-selenium-error');
const getSessionIdFromReq = require('../lib/get-session-id-from-req');
const { isEndingSession } = require('../lib/identify-command-from-req');
const doesRequestTriggerScreenshot = require('../lib/does-request-trigger-screenshot');
const getLogEntryFromReq = require('../lib/get-log-entry-from-req');
const takeScreenshot = require('../lib/take-screenshot');
router.all('*', rawBodyParser, function(req, res) {
const targetEndpoint = config.get('targetEndpoint');
const sessionId = getSessionIdFromReq(req);
const commandId = uid();
const startTime = Date.now();
// TODO: We may need to insert our own loggingPrefs into their capabilities when they `POST /wd/hub/session`
// {"desiredCapabilities":{"browserName":"chrome","loggingPrefs":{"browser":"ALL","client":"ALL","driver":"ALL","performance":"ALL","server":"ALL"}}}
//logger.log('debug', 'req', req);
Promise.resolve()
.then(() => {
if(!targetEndpoint) {
throw new Error('No target endpoint provided. You probably need to set the `GITLAB_TARGET_SELENIUM_REMOTE_URL` environment variable');
}
})
.then(() => {
// If the session is ending, grab the logs
let fetchLogsMiddlewarePromise = Promise.resolve();
if(isEndingSession(req).result) {
fetchLogsMiddlewarePromise = logUtils.fetchAllLogs(targetEndpoint, sessionId)
.then((logMap) => {
const seleniumLogPath = path.join(config.get('logDir'), `./${sessionId}/selenium-logs.json`);
return outputFile(seleniumLogPath, JSON.stringify(logMap, null, 2));
});
}
return fetchLogsMiddlewarePromise;
})
.then(() => {
// Forward on the request to the target
return proxyRequest(targetEndpoint, req);
})
.then((proxyRes) => {
const endTime = Date.now();
// Add an entry for our custom GitLab log we use in CI views
logUtils.updateLog(sessionId, 'gitlab', getLogEntryFromReq(req, commandId, startTime, endTime));
let screenshotMiddlewarePromise = Promise.resolve();
if(sessionId && doesRequestTriggerScreenshot(req)) {
screenshotMiddlewarePromise = takeScreenshot(targetEndpoint, sessionId, commandId);
}
return screenshotMiddlewarePromise
.then(() => proxyRes);
})
.tap((proxyRes) => {
// Return the proxied response back to our originating user
Object.keys(proxyRes.headers).forEach((headerName) => {
const headerValue = proxyRes.headers[headerName];
res.set(headerName, headerValue);
});
res.status(proxyRes.statusCode);
//logger.log('debug', '->', req.method, req.url, proxyRes.headers, proxyRes.body);
res.send(proxyRes.body);
})
.tap((proxyRes) => {
// TODO: If someone uses `POST /wd/hub/session/:sessionId/log` add it to our own log
// because the log buffer is cleared on any request (need to test this)
if(sessionId && req.method === 'POST' && (/session\/[a-f\d-]+\/log\/?$/i).test(req.path)) {
const type = req.body.type;
const logValue = proxyRes.body.value;
logUtils.updateLog(sessionId, type, logValue);
}
})
.catch((err) => {
logger.error('Error', err.message, err.stack);
res.status(500).json(createSeleniumError(err));
});
});
module.exports = router;