Skip to content

Commit

Permalink
server, launcher, ts: typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
flotwig committed Mar 26, 2019
1 parent dc2b8da commit d3f8b8b
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 158 deletions.
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@
"@cypress/env-or-json-file": "2.0.0",
"@cypress/npm-run-all": "4.0.5",
"@cypress/questions-remain": "1.0.1",
"@types/bluebird": "3.5.21",
"@types/chai": "3.5.2",
"@types/debug": "0.0.31",
"@types/execa": "0.7.2",
"@types/fs-extra": "3.0.0",
"@types/lodash": "4.14.122",
"@types/mocha": "2.2.48",
"@types/node": "7.10.3",
"@types/ramda": "0.25.47",
"@types/request-promise": "4.1.42",
"ansi-styles": "3.2.1",
"ascii-table": "0.0.9",
"babel-eslint": "10.0.1",
Expand Down
9 changes: 0 additions & 9 deletions packages/launcher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,6 @@
"lib"
],
"devDependencies": {
"@types/bluebird": "3.5.21",
"@types/chai": "3.5.2",
"@types/debug": "0.0.31",
"@types/execa": "0.7.2",
"@types/fs-extra": "3.0.0",
"@types/lodash": "4.14.122",
"@types/mocha": "2.2.48",
"@types/node": "7.10.3",
"@types/ramda": "0.25.47",
"bin-up": "1.1.0",
"chai": "3.5.0",
"prettier": "1.16.4",
Expand Down
63 changes: 33 additions & 30 deletions packages/server/lib/util/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import * as url from 'url'
import * as debugModule from 'debug'
import { getProxyForUrl } from 'proxy-from-env'
import * as Promise from 'bluebird'
import * as connect from './connect'
import { getAddress } from './connect'

const debug = debugModule('cypress:server:agent')

interface RequestOptionsWithProxy extends http.RequestOptions {
proxy: string
}

function createProxySock (proxy: url.Url) {
if (proxy.protocol === 'http:') {
return net.connect(Number(proxy.port || 80), proxy.hostname)
Expand All @@ -24,21 +28,21 @@ function createProxySock (proxy: url.Url) {
throw new Error(`Unsupported proxy protocol: ${proxy.protocol}`)
}

function regenerateRequestHead(req) {
req._header = null;
req._implicitHeader();
function regenerateRequestHead(req: http.ClientRequest) {
delete req._header
req._implicitHeader()
if (req.output && req.output.length > 0) {
// the _header has already been queued to be written to the socket
var first = req.output[0];
var endOfHeaders = first.indexOf('\r\n\r\n') + 4;
req.output[0] = req._header + first.substring(endOfHeaders);
var first = req.output[0]
var endOfHeaders = first.indexOf('\r\n\r\n') + 4
req.output[0] = req._header + first.substring(endOfHeaders)
}
}

export class CombinedAgent {
httpAgent: HttpAgent
httpsAgent: HttpsAgent
familyCache = {}
familyCache: { [host: string] : 4 | 6 } = {}

constructor(httpOpts: http.AgentOptions = {}, httpsOpts: https.AgentOptions = {}) {
this.httpAgent = new HttpAgent(httpOpts)
Expand Down Expand Up @@ -69,7 +73,7 @@ export class CombinedAgent {
debug(`addRequest called for ${options.href}`)

this._getFirstWorkingFamily(options)
.then(family => {
.then((family: Optional<Number>) => {
options.family = family

if (isHttps) {
Expand All @@ -80,7 +84,7 @@ export class CombinedAgent {
})
}

_getFirstWorkingFamily({ port, host }) {
_getFirstWorkingFamily({ port, host }: http.RequestOptions) {
// this is a workaround for localhost (and potentially others) having invalid
// A records but valid AAAA records. here, we just cache the family of the first
// returned A/AAAA record for a host that we can establish a connection to.
Expand All @@ -101,8 +105,8 @@ export class CombinedAgent {
return Promise.resolve(this.familyCache[host])
}

return connect.getAddress(port, host)
.then(firstWorkingAddress => {
return getAddress(port, host)
.then((firstWorkingAddress: net.Address) => {
this.familyCache[host] = firstWorkingAddress.family
return firstWorkingAddress.family
})
Expand All @@ -120,21 +124,21 @@ class HttpAgent extends http.Agent {
this.httpsAgent = new https.Agent({ keepAlive: true })
}

createSocket (req, options, cb) {
createSocket (req: http.ClientRequest, options: http.RequestOptions, cb: http.SocketCallback) {
if (process.env.HTTP_PROXY) {
const proxy = getProxyForUrl(options.href)

if (proxy) {
options.proxy = proxy

return this._createProxiedSocket(req, options, cb)
return this._createProxiedSocket(req, <RequestOptionsWithProxy>options, cb)
}
}

super.createSocket(req, options, cb)
}

_createProxiedSocket (req, options, cb) {
_createProxiedSocket (req: http.ClientRequest, options: RequestOptionsWithProxy, cb: http.SocketCallback) {
debug(`Creating proxied socket for ${options.href} through ${options.proxy}`)

const proxy = url.parse(options.proxy)
Expand All @@ -154,8 +158,8 @@ class HttpAgent extends http.Agent {
// https://github.com/TooTallNate/node-http-proxy-agent/blob/master/index.js#L93
regenerateRequestHead(req)

options.port = proxy.port
options.host = proxy.hostname
options.port = Number(proxy.port || 80)
options.host = proxy.hostname || 'localhost'
delete options.path // so the underlying net.connect doesn't default to IPC

if (proxy.protocol === 'https:') {
Expand All @@ -175,22 +179,22 @@ class HttpsAgent extends https.Agent {
super(opts)
}

createConnection (options, cb) {
createConnection (options: http.RequestOptions, cb: http.SocketCallback) {
if (process.env.HTTPS_PROXY) {
const proxy = getProxyForUrl(options.href)

if (proxy) {
options.proxy = proxy
if (typeof proxy === "string") {
options.proxy = <string>proxy

return this.createProxiedConnection(options, cb)
return this.createProxiedConnection(<RequestOptionsWithProxy>options, cb)
}
}

// @ts-ignore
cb(null, super.createConnection(options))
}

createProxiedConnection (options, cb) {
createProxiedConnection (options: RequestOptionsWithProxy, cb: http.SocketCallback) {
// heavily inspired by
// https://github.com/mknj/node-keepalive-proxy-agent/blob/master/index.js
debug(`Creating proxied socket for ${options.href} through ${options.proxy}`)
Expand All @@ -201,14 +205,14 @@ class HttpsAgent extends https.Agent {

const proxySocket = createProxySock(proxy)

const onError = (err) => {
const onError = (err: Error) => {
proxySocket.destroy()
cb(err)
cb(err, undefined)
}

let buffer = ''

const onData = (data) => {
const onData = (data: Buffer) => {
debug(`Proxy socket for ${options.href} established`)

buffer += data.toString()
Expand All @@ -223,19 +227,18 @@ class HttpsAgent extends https.Agent {
// read status code from proxy's response
const matches = buffer.match(/^HTTP\/1.1 (\d*)/)

if (matches[1] !== '200') {
return onError(new Error(`Error establishing proxy connection: ${matches[0]}`))
if (!matches || matches[1] !== '200') {
return onError(new Error(`Error establishing proxy connection: ${matches ? matches[0] : buffer}`))
}

if (options._agentKey) {
// https.Agent will upgrade and reuse this socket now
options.socket = proxySocket
options.servername = hostname
// @ts-ignore
return cb(null, super.createConnection(options))
return cb(undefined, super.createConnection(options, undefined))
}

cb(null, proxySocket)
cb(undefined, proxySocket)
}

proxySocket.once('error', onError)
Expand Down
62 changes: 0 additions & 62 deletions packages/server/lib/util/connect.js

This file was deleted.

58 changes: 58 additions & 0 deletions packages/server/lib/util/connect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as net from 'net'
import * as dns from 'dns'
import * as url from 'url'
import * as rp from 'request-promise'
import * as Promise from 'bluebird'

export function byPortAndAddress (port: number, address: net.Address) {
// https://nodejs.org/api/net.html#net_net_connect_port_host_connectlistener
return new Promise((resolve, reject) => {
const client = net.connect(port, address.address, () => {
client.end()
resolve(address)
})

client.on('error', reject)
})
}

export function getAddress (port: number, hostname: string) {
const fn = byPortAndAddress.bind({}, port)

// promisify at the very last second which enables us to
// modify dns lookup function (via hosts overrides)
const lookupAsync = Promise.promisify(dns.lookup, { context: dns })

// this does not go out to the network to figure
// out the addresess. in fact it respects the /etc/hosts file
// https://github.com/nodejs/node/blob/dbdbdd4998e163deecefbb1d34cda84f749844a4/lib/dns.js#L108
// https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback
// @ts-ignore
return lookupAsync(hostname, { all: true })
.then((addresses: net.Address[]) => {
// convert to an array if string
return Array.prototype.concat.call(addresses).map(fn)
})
.any()
}

export function ensureUrl (urlStr: string) {
// takes a urlStr and verifies the hostname + port
let { hostname, protocol, port } = url.parse(urlStr)

if (port == null) {
port = protocol === 'https:' ? '443' : '80'
}

if (process.env.HTTP_PROXY) {
// cannot make arbitrary connections behind a proxy, attempt HTTP/HTTPS
return rp({
url: urlStr,
agent: require('./agent'),
proxy: null,
})
.catch({ name: 'StatusCodeError' }, () => {}) // we just care if it can connect, not if it's a valid resource
}

return getAddress(Number(port), String(hostname))
}
42 changes: 0 additions & 42 deletions packages/server/lib/util/proxy.js

This file was deleted.

Loading

0 comments on commit d3f8b8b

Please sign in to comment.