Path: blob/trunk/javascript/selenium-webdriver/test/http/http_test.js
2885 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617'use strict'1819const assert = require('node:assert')20const http = require('node:http')21const url = require('node:url')2223const HttpClient = require('selenium-webdriver/http').HttpClient24const HttpRequest = require('selenium-webdriver/lib/http').Request25const Server = require('../../lib/test/httpserver').Server2627describe('HttpClient', function () {28const server = new Server(function (req, res) {29// eslint-disable-next-line n/no-deprecated-api30const parsedUrl = url.parse(req.url)3132if (req.method === 'GET' && req.url === '/echo') {33res.writeHead(200)34res.end(JSON.stringify(req.headers))35} else if (req.method === 'GET' && req.url === '/redirect') {36res.writeHead(303, { Location: server.url('/hello') })37res.end()38} else if (req.method === 'GET' && req.url === '/hello') {39res.writeHead(200, { 'content-type': 'text/plain' })40res.end('hello, world!')41} else if (req.method === 'GET' && req.url === '/chunked') {42res.writeHead(200, {43'content-type': 'text/html; charset=utf-8',44'transfer-encoding': 'chunked',45})46res.write('<!DOCTYPE html>')47setTimeout(() => res.end('<h1>Hello, world!</h1>'), 20)48} else if (req.method === 'GET' && req.url === '/badredirect') {49res.writeHead(303, {})50res.end()51} else if (req.method === 'GET' && req.url === '/protected') {52const denyAccess = function () {53res.writeHead(401, { 'WWW-Authenticate': 'Basic realm="test"' })54res.end('Access denied')55}5657// eslint-disable-next-line no-useless-escape58const basicAuthRegExp = /^\s*basic\s+([a-z0-9\-\._~\+\/]+)=*\s*$/i59const auth = req.headers.authorization60const match = basicAuthRegExp.exec(auth || '')61if (!match) {62denyAccess()63return64}6566const userNameAndPass = Buffer.from(match[1], 'base64').toString()67const parts = userNameAndPass.split(':', 2)68if (parts[0] !== 'genie' && parts[1] !== 'bottle') {69denyAccess()70return71}7273res.writeHead(200, { 'content-type': 'text/plain' })74res.end('Access granted!')75} else if (req.method === 'GET' && parsedUrl.pathname && parsedUrl.pathname.endsWith('/proxy')) {76let headers = Object.assign({}, req.headers)77headers['x-proxy-request-uri'] = req.url78res.writeHead(200, headers)79res.end()80} else if (req.method === 'GET' && parsedUrl.pathname && parsedUrl.pathname.endsWith('/proxy/redirect')) {81let path = `/proxy${parsedUrl.search || ''}${parsedUrl.hash || ''}`82res.writeHead(303, { Location: path })83res.end()84} else {85res.writeHead(404, {})86res.end()87}88})8990before(function () {91return server.start()92})9394after(function () {95return server.stop()96})9798it('can send a basic HTTP request', function () {99const request = new HttpRequest('GET', '/echo')100request.headers.set('Foo', 'Bar')101102const agent = new http.Agent()103agent.maxSockets = 1 // Only making 1 request.104105const client = new HttpClient(server.url(), agent)106return client.send(request).then(function (response) {107assert.strictEqual(200, response.status)108109const headers = JSON.parse(response.body)110assert.strictEqual(headers['content-length'], '0')111assert.strictEqual(headers['connection'], 'keep-alive')112assert.strictEqual(headers['host'], server.host())113114const regex = /^selenium\/.* \(js (windows|mac|linux)\)$/115assert.ok(regex.test(headers['user-agent']), `${headers['user-agent']} does not match ${regex}`)116117assert.strictEqual(request.headers.get('Foo'), 'Bar')118assert.strictEqual(request.headers.get('Accept'), 'application/json; charset=utf-8')119assert.strictEqual(agent.keepAlive, false)120})121})122123it('can send a basic HTTP request with custom user-agent via client_options', function () {124const request = new HttpRequest('GET', '/echo')125request.headers.set('Foo', 'Bar')126127const agent = new http.Agent()128agent.maxSockets = 1 // Only making 1 request.129130const client = new HttpClient(server.url(), agent, null, {131'user-agent': 'test',132})133134return client.send(request).then(function (response) {135assert.strictEqual(200, response.status)136137const headers = JSON.parse(response.body)138assert.strictEqual(headers['content-length'], '0')139assert.strictEqual(headers['connection'], 'keep-alive')140assert.strictEqual(headers['host'], server.host())141assert.strictEqual(headers['user-agent'], 'test')142143assert.strictEqual(request.headers.get('Foo'), 'Bar')144assert.strictEqual(agent.keepAlive, false)145assert.strictEqual(request.headers.get('Accept'), 'application/json; charset=utf-8')146})147})148149it('can send a basic HTTP request with keep-alive being set to true via client_options', function () {150const request = new HttpRequest('GET', '/echo')151request.headers.set('Foo', 'Bar')152153const agent = new http.Agent()154agent.maxSockets = 1 // Only making 1 request.155156const client = new HttpClient(server.url(), agent, null, {157'keep-alive': 'true',158})159160return client.send(request).then(function (response) {161assert.strictEqual(200, response.status)162163const headers = JSON.parse(response.body)164assert.strictEqual(headers['content-length'], '0')165assert.strictEqual(headers['connection'], 'keep-alive')166assert.strictEqual(headers['host'], server.host())167168const regex = /^selenium\/.* \(js (windows|mac|linux)\)$/169assert.ok(regex.test(headers['user-agent']), `${headers['user-agent']} does not match ${regex}`)170171assert.strictEqual(request.headers.get('Foo'), 'Bar')172assert.strictEqual(agent.keepAlive, true)173assert.strictEqual(request.headers.get('Accept'), 'application/json; charset=utf-8')174})175})176177it('handles chunked responses', function () {178let request = new HttpRequest('GET', '/chunked')179180let client = new HttpClient(server.url())181return client.send(request).then((response) => {182assert.strictEqual(200, response.status)183assert.strictEqual(response.body, '<!DOCTYPE html><h1>Hello, world!</h1>')184})185})186187it('can use basic auth', function () {188// eslint-disable-next-line n/no-deprecated-api189const parsed = url.parse(server.url())190parsed.auth = 'genie:bottle'191192const client = new HttpClient(url.format(parsed))193const request = new HttpRequest('GET', '/protected')194return client.send(request).then(function (response) {195assert.strictEqual(200, response.status)196assert.strictEqual(response.headers.get('content-type'), 'text/plain')197assert.strictEqual(response.body, 'Access granted!')198})199})200201it('fails requests missing required basic auth', function () {202const client = new HttpClient(server.url())203const request = new HttpRequest('GET', '/protected')204return client.send(request).then(function (response) {205assert.strictEqual(401, response.status)206assert.strictEqual(response.body, 'Access denied')207})208})209210it('automatically follows redirects', function () {211const request = new HttpRequest('GET', '/redirect')212const client = new HttpClient(server.url())213return client.send(request).then(function (response) {214assert.strictEqual(200, response.status)215assert.strictEqual(response.headers.get('content-type'), 'text/plain')216assert.strictEqual(response.body, 'hello, world!')217})218})219220it('handles malformed redirect responses', function () {221const request = new HttpRequest('GET', '/badredirect')222const client = new HttpClient(server.url())223return client.send(request).then(assert.fail, function (err) {224assert.ok(/Failed to parse "Location"/.test(err.message), 'Not the expected error: ' + err.message)225})226})227228describe('with proxy', function () {229it('sends request to proxy with absolute URI', function () {230const request = new HttpRequest('GET', '/proxy')231const client = new HttpClient('http://another.server.com', undefined, server.url())232return client.send(request).then(function (response) {233assert.strictEqual(200, response.status)234assert.strictEqual(response.headers.get('host'), 'another.server.com')235assert.strictEqual(response.headers.get('x-proxy-request-uri'), 'http://another.server.com/proxy')236})237})238239it('uses proxy when following redirects', function () {240const request = new HttpRequest('GET', '/proxy/redirect')241const client = new HttpClient('http://another.server.com', undefined, server.url())242return client.send(request).then(function (response) {243assert.strictEqual(200, response.status)244assert.strictEqual(response.headers.get('host'), 'another.server.com')245assert.strictEqual(response.headers.get('x-proxy-request-uri'), 'http://another.server.com/proxy')246})247})248249it('includes search and hash in redirect URI', function () {250const request = new HttpRequest('GET', '/proxy/redirect?foo#bar')251const client = new HttpClient('http://another.server.com', undefined, server.url())252return client.send(request).then(function (response) {253assert.strictEqual(200, response.status)254assert.strictEqual(response.headers.get('host'), 'another.server.com')255assert.strictEqual(response.headers.get('x-proxy-request-uri'), 'http://another.server.com/proxy?foo#bar')256})257})258})259})260261262