From 254ec155eb13b8e761dd3b2595d510e210f53c3e Mon Sep 17 00:00:00 2001 From: Karan Shah <64479353+karanshah-browserstack@users.noreply.github.com> Date: Thu, 3 Jun 2021 00:06:58 +0530 Subject: [PATCH] feat(user-agent): Adding User-Agent in headers while making connection to browser (#6813) --- src/client/browserType.ts | 8 +++++--- src/utils/utils.ts | 6 ++++++ tests/browsertype-connect.spec.ts | 16 ++++++++++++++++ tests/chromium/chromium.spec.ts | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/client/browserType.ts b/src/client/browserType.ts index d38809c05f..68d13d4a8a 100644 --- a/src/client/browserType.ts +++ b/src/client/browserType.ts @@ -25,7 +25,7 @@ import { Events } from './events'; import { TimeoutSettings } from '../utils/timeoutSettings'; import { ChildProcess } from 'child_process'; import { envObjectToArray } from './clientHelper'; -import { assert, headersObjectToArray, makeWaitForNextTask } from '../utils/utils'; +import { assert, headersObjectToArray, makeWaitForNextTask, getUserAgent } from '../utils/utils'; import { kBrowserClosedError } from '../utils/errors'; import * as api from '../../types/types'; import type { Playwright } from './playwright'; @@ -109,12 +109,13 @@ export class BrowserType extends ChannelOwner { const logger = params.logger; + const paramsHeaders = Object.assign({'User-Agent': getUserAgent()}, params.headers); return this._wrapApiCall('browserType.connect', async () => { const ws = new WebSocket(params.wsEndpoint, [], { perMessageDeflate: false, maxPayload: 256 * 1024 * 1024, // 256Mb, handshakeTimeout: this._timeoutSettings.timeout(params), - headers: params.headers, + headers: paramsHeaders, }); const connection = new Connection(() => ws.close()); @@ -224,7 +225,8 @@ export class BrowserType extends ChannelOwner { - const headers = params.headers ? headersObjectToArray(params.headers) : undefined; + const paramsHeaders = Object.assign({'User-Agent': getUserAgent()}, params.headers); + const headers = paramsHeaders ? headersObjectToArray(paramsHeaders) : undefined; const result = await channel.connectOverCDP({ sdkLanguage: 'javascript', endpointURL: 'endpointURL' in params ? params.endpointURL : params.wsEndpoint, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index c77c045046..a90135ef9a 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -19,6 +19,7 @@ import fs from 'fs'; import removeFolder from 'rimraf'; import * as util from 'util'; import * as crypto from 'crypto'; +import os from 'os'; import { spawn } from 'child_process'; const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); @@ -203,3 +204,8 @@ const localIpAddresses = [ export function isLocalIpAddress(ipAdress: string): boolean { return localIpAddresses.includes(ipAdress); } + +export function getUserAgent() { + const packageJson = require('./../../package.json'); + return `Playwright/${packageJson.version} (${os.arch()}/${os.platform()}/${os.release()})`; +} diff --git a/tests/browsertype-connect.spec.ts b/tests/browsertype-connect.spec.ts index 2e9f4ccf13..134ec0489d 100644 --- a/tests/browsertype-connect.spec.ts +++ b/tests/browsertype-connect.spec.ts @@ -18,6 +18,7 @@ import { playwrightTest as test, expect } from './config/browserTest'; import fs from 'fs'; import * as path from 'path'; +import { getUserAgent } from '../lib/utils/utils'; test.slow(true, 'All connect tests are slow'); @@ -86,6 +87,21 @@ test('should send extra headers with connect request', async ({browserType, star expect(request.headers['foo']).toBe('bar'); }); +test('should send default User-Agent header with connect request', async ({browserType, startRemoteServer, server}) => { + const [request] = await Promise.all([ + server.waitForWebSocketConnectionRequest(), + browserType.connect({ + wsEndpoint: `ws://localhost:${server.PORT}/ws`, + headers: { + 'foo': 'bar', + }, + timeout: 100, + }).catch(() => {}) + ]); + expect(request.headers['user-agent']).toBe(getUserAgent()); + expect(request.headers['foo']).toBe('bar'); +}); + test('disconnected event should be emitted when browser is closed or server is closed', async ({browserType, startRemoteServer}) => { const remoteServer = await startRemoteServer(); diff --git a/tests/chromium/chromium.spec.ts b/tests/chromium/chromium.spec.ts index af5e43a406..4acc5bf59d 100644 --- a/tests/chromium/chromium.spec.ts +++ b/tests/chromium/chromium.spec.ts @@ -18,6 +18,7 @@ import { contextTest as test, expect } from '../config/browserTest'; import { playwrightTest } from '../config/browserTest'; import http from 'http'; +import { getUserAgent } from '../../lib/utils/utils'; test('should create a worker from a service worker', async ({page, server}) => { const [worker] = await Promise.all([ @@ -241,6 +242,23 @@ playwrightTest('should send extra headers with connect request', async ({browser } }); +playwrightTest('should send default User-Agent header with connect request', async ({browserType, browserOptions, server}, testInfo) => { + { + const [request] = await Promise.all([ + server.waitForWebSocketConnectionRequest(), + browserType.connectOverCDP({ + wsEndpoint: `ws://localhost:${server.PORT}/ws`, + headers: { + 'foo': 'bar', + }, + timeout: 100, + }).catch(() => {}) + ]); + expect(request.headers['user-agent']).toBe(getUserAgent()); + expect(request.headers['foo']).toBe('bar'); + } +}); + playwrightTest('should report all pages in an existing browser', async ({ browserType, browserOptions }, testInfo) => { const port = 9339 + testInfo.workerIndex; const browserServer = await browserType.launch({