Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 4x 4x 36x 36x 36x 36x 36x 36x 36x 12x 12x 12x 29x 29x 11x 11x 29x 1x 28x 28x 1x 28x 28x 21x 21x 9x 21x 21x 21x 2x 1x 1x 20x 12x 12x 8x 1x 1x 1x 7x 2x 2x 2x 5x 5x 5x 5x 5x | import url from 'url' import http from 'http' import path from 'path' import https from 'https' import merge from 'lodash.merge' import request from 'request' import EventEmitter from 'events' import logger from '@wdio/logger' import { isSuccessfulResponse, getErrorFromResponseBody } from './utils' import pkg from '../package.json' const log = logger('webdriver') const agents = { http: new http.Agent({ keepAlive: true }), https: new https.Agent({ keepAlive: true }) } export default class WebDriverRequest extends EventEmitter { constructor (method, endpoint, body, isHubCommand) { super() this.body = body this.method = method this.endpoint = endpoint this.isHubCommand = isHubCommand this.requiresSessionId = this.endpoint.match(/:sessionId/) this.defaultOptions = { method, followAllRedirects: true, json: true, headers: { 'Connection': 'keep-alive', 'Accept': 'application/json', 'User-Agent': 'webdriver/' + pkg.version } } } makeRequest (options, sessionId) { const fullRequestOptions = merge({}, this.defaultOptions, this._createOptions(options, sessionId)) this.emit('request', fullRequestOptions) return this._request(fullRequestOptions, options.connectionRetryCount) } _createOptions (options, sessionId) { const requestOptions = { agent: options.agent || agents[options.protocol], headers: typeof options.headers === 'object' ? options.headers : {}, qs: typeof options.queryParams === 'object' ? options.queryParams : {} } /** * only apply body property if existing */ if (this.body && (Object.keys(this.body).length || this.method === 'POST')) { requestOptions.body = this.body requestOptions.headers = merge({}, requestOptions.headers, { 'Content-Length': Buffer.byteLength(JSON.stringify(requestOptions.body), 'UTF-8') }) } /** * if we don't have a session id we set it here, unless we call commands that don't require session ids, for * example /sessions. The call to /sessions is not connected to a session itself and it therefore doesn't * require it */ if (this.requiresSessionId && !sessionId) { throw new Error('A sessionId is required for this command') } requestOptions.uri = url.parse( `${options.protocol}://` + `${options.hostname}:${options.port}` + (this.isHubCommand ? this.endpoint : path.join(options.path, this.endpoint.replace(':sessionId', sessionId))) ) /** * send authentication credentials only when creating new session */ if (this.endpoint === '/session' && options.user && options.key) { requestOptions.auth = { user: options.user, pass: options.key } } /** * if the environment variable "STRICT_SSL" is defined as "false", it doesn't require SSL certificates to be valid. */ requestOptions.strictSSL = !(process.env.STRICT_SSL === 'false' || process.env.strict_ssl === 'false') return requestOptions } _request (fullRequestOptions, totalRetryCount = 0, retryCount = 0) { log.info(`[${fullRequestOptions.method}] ${fullRequestOptions.uri.href}`) if (fullRequestOptions.body && Object.keys(fullRequestOptions.body).length) { log.info('DATA', fullRequestOptions.body) } return new Promise((resolve, reject) => request(fullRequestOptions, (err, response, body) => { const error = err || getErrorFromResponseBody(body) /** * hub commands don't follow standard response formats * and can have empty bodies */ if (this.isHubCommand) { /** * if body contains HTML the command was called on a node * directly without using a hub, therefor throw */ if (typeof body === 'string' && body.startsWith('<!DOCTYPE html>')) { return reject(new Error('Command can only be called to a Selenium Hub')) } body = { value: body || null } } /** * Resolve only if successful response */ if (!err && isSuccessfulResponse(response.statusCode, body)) { this.emit('response', { result: body }) return resolve(body) } /** * stop retrying as this will never be successful. * we will handle this at the elementErrorHandler */ if(error.name === 'stale element reference') { log.warn('Request encountered a stale element - terminating request') this.emit('response', { error }) return reject(error) } /** * stop retrying if totalRetryCount was exceeded or there is no reason to * retry, e.g. if sessionId is invalid */ if (retryCount >= totalRetryCount || error.message.includes('invalid session id')) { log.error('Request failed due to', error) this.emit('response', { error }) return reject(error) } ++retryCount this.emit('retry', { error, retryCount }) log.warn('Request failed due to', error.message) log.info(`Retrying ${retryCount}/${totalRetryCount}`) this._request(fullRequestOptions, totalRetryCount, retryCount).then(resolve, reject) })) } } |