// Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The SFC licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. 'use strict' const path = require('node:path') const url = require('node:url') const express = require('express') const multer = require('multer') const serveIndex = require('serve-index') const { isDevMode } = require('./build') const resources = require('./resources') const { Server } = require('./httpserver') const WEB_ROOT = '/common' const DATA_ROOT = '/data' const JS_ROOT = '/javascript' const baseDirectory = resources.locate('common/src/web') const dataDirectory = path.join(__dirname, 'data') const jsDirectory = resources.locate('javascript') const Pages = (function () { let pages = {} function addPage(page, path) { pages.__defineGetter__(page, function () { return exports.whereIs(path) }) } addPage('ajaxyPage', 'ajaxy_page.html') addPage('alertsPage', 'alerts.html') addPage('basicAuth', 'basicAuth') addPage('blankPage', 'blank.html') addPage('bodyTypingPage', 'bodyTypingTest.html') addPage('booleanAttributes', 'booleanAttributes.html') addPage('childPage', 'child/childPage.html') addPage('chinesePage', 'cn-test.html') addPage('clickJacker', 'click_jacker.html') addPage('clickEventPage', 'clickEventPage.html') addPage('clicksPage', 'clicks.html') addPage('colorPage', 'colorPage.html') addPage('deletingFrame', 'deletingFrame.htm') addPage('draggableLists', 'draggableLists.html') addPage('dragAndDropPage', 'dragAndDropTest.html') addPage('droppableItems', 'droppableItems.html') addPage('documentWrite', 'document_write_in_onload.html') addPage('dynamicallyModifiedPage', 'dynamicallyModifiedPage.html') addPage('dynamicPage', 'dynamic.html') addPage('echoPage', 'echo') addPage('errorsPage', 'errors.html') addPage('xhtmlFormPage', 'xhtmlFormPage.xhtml') addPage('formPage', 'formPage.html') addPage('formSelectionPage', 'formSelectionPage.html') addPage('framesetPage', 'frameset.html') addPage('grandchildPage', 'child/grandchild/grandchildPage.html') addPage('html5Page', 'html5Page.html') addPage('html5OfflinePage', 'html5/offline.html') addPage('iframePage', 'iframes.html') addPage('javascriptEnhancedForm', 'javascriptEnhancedForm.html') addPage('javascriptPage', 'javascriptPage.html') addPage('linkedImage', 'linked_image.html') addPage('longContentPage', 'longContentPage.html') addPage('macbethPage', 'macbeth.html') addPage('mapVisibilityPage', 'map_visibility.html') addPage('metaRedirectPage', 'meta-redirect.html') addPage('missedJsReferencePage', 'missedJsReference.html') addPage('mouseTrackerPage', 'mousePositionTracker.html') addPage('nestedPage', 'nestedElements.html') addPage('readOnlyPage', 'readOnlyPage.html') addPage('rectanglesPage', 'rectangles.html') addPage('relativeLocators', 'relative_locators.html') addPage('redirectPage', 'redirect') addPage('resultPage', 'resultPage.html') addPage('richTextPage', 'rich_text.html') addPage('printPage', 'printPage.html') addPage('scrollingPage', 'scrollingPage.html') addPage('selectableItemsPage', 'selectableItems.html') addPage('selectPage', 'selectPage.html') addPage('selectSpacePage', 'select_space.html') addPage('simpleTestPage', 'simpleTest.html') addPage('simpleXmlDocument', 'simple.xml') addPage('sleepingPage', 'sleep') addPage('slowIframes', 'slow_loading_iframes.html') addPage('slowLoadingAlertPage', 'slowLoadingAlert.html') addPage('svgPage', 'svgPiechart.xhtml') addPage('tables', 'tables.html') addPage('underscorePage', 'underscore.html') addPage('unicodeLtrPage', 'utf8/unicode_ltr.html') addPage('uploadPage', 'upload.html') addPage('veryLargeCanvas', 'veryLargeCanvas.html') addPage('webComponents', 'webComponents.html') addPage('xhtmlTestPage', 'xhtmlTest.html') addPage('uploadInvisibleTestPage', 'upload_invisible.html') addPage('userpromptPage', 'userprompt.html') addPage('virtualAuthenticator', 'virtual-authenticator.html') addPage('logEntryAdded', 'bidi/logEntryAdded.html') addPage('scriptTestAccessProperty', 'bidi/scriptTestAccessProperty.html') addPage('scriptTestRemoveProperty', 'bidi/scriptTestRemoveProperty.html') addPage('emptyPage', 'bidi/emptyPage.html') addPage('emptyText', 'bidi/emptyText.txt') addPage('redirectedHttpEquiv', 'bidi/redirected_http_equiv.html') addPage('releaseAction', 'bidi/release_action.html') addPage('fedcm', 'fedcm/fedcm_async_js.html') return pages })() const Path = { BASIC_AUTH: WEB_ROOT + '/basicAuth', ECHO: WEB_ROOT + '/echo', GENERATED: WEB_ROOT + '/generated', MANIFEST: WEB_ROOT + '/manifest', REDIRECT: WEB_ROOT + '/redirect', PAGE: WEB_ROOT + '/page', SLEEP: WEB_ROOT + '/sleep', UPLOAD: WEB_ROOT + '/upload', } var app = express() app .get('/', sendIndex) .get('/favicon.ico', function (_req, res) { res.writeHead(204) res.end() }) .use(JS_ROOT, serveIndex(jsDirectory), express.static(jsDirectory)) .post(Path.UPLOAD, handleUpload) .use(WEB_ROOT, serveIndex(baseDirectory), express.static(baseDirectory)) .use(DATA_ROOT, serveIndex(dataDirectory), express.static(dataDirectory)) .get(Path.ECHO, sendEcho) .get(Path.PAGE, sendInifinitePage) .get(Path.PAGE + '/*', sendInifinitePage) .get(Path.REDIRECT, redirectToResultPage) .get(Path.SLEEP, sendDelayedResponse) .get(Path.BASIC_AUTH, sendBasicAuth) if (isDevMode()) { var closureDir = resources.locate('third_party/closure/goog') app.use('/third_party/closure/goog', serveIndex(closureDir), express.static(closureDir)) } var server = new Server(app) function redirectToResultPage(_, response) { response.writeHead(303, { Location: Pages.resultPage, }) return response.end() } function sendInifinitePage(request, response) { // eslint-disable-next-line n/no-deprecated-api var pathname = url.parse(request.url).pathname var lastIndex = pathname.lastIndexOf('/') var pageNumber = lastIndex == -1 ? 'Unknown' : pathname.substring(lastIndex + 1) var body = [ '', '
top', ].join('') response.writeHead(200, { 'Content-Length': Buffer.byteLength(body, 'utf8'), 'Content-Type': 'text/html; charset=utf-8', }) response.end(body) } function sendBasicAuth(request, response) { const denyAccess = function () { response.writeHead(401, { 'WWW-Authenticate': 'Basic realm="test"' }) response.end('Access denied') } const basicAuthRegExp = /^\s*basic\s+([a-z0-9\-._~+/]+)=*\s*$/i const auth = request.headers.authorization const match = basicAuthRegExp.exec(auth || '') if (!match) { denyAccess() return } const userNameAndPass = Buffer.from(match[1], 'base64').toString() const parts = userNameAndPass.split(':', 2) if (parts[0] !== 'genie' || parts[1] !== 'bottle') { denyAccess() return } response.writeHead(200, { 'content-type': 'text/plain' }) response.end('Access granted!') } function sendDelayedResponse(request, response) { var duration = 0 // eslint-disable-next-line n/no-deprecated-api var query = url.parse(request.url).search.substr(1) || '' var match = query.match(/\btime=(\d+)/) if (match) { duration = parseInt(match[1], 10) } setTimeout(function () { var body = ['', '