http2-wrapper
Advanced tools
Comparing version 2.0.9 to 2.1.0
@@ -23,2 +23,3 @@ // See https://github.com/facebook/jest/issues/2549 | ||
}; | ||
resolveProtocol?: ResolveProtocolFunction; | ||
} | ||
@@ -112,5 +113,20 @@ | ||
export type ResolveProtocolResult = { | ||
alpnProtocol: string; | ||
socket?: tls.TLSSocket; | ||
timeout?: boolean; | ||
}; | ||
export type ResolveProtocolFunction = (options: AutoRequestOptions) => Promise<ResolveProtocolResult>; | ||
type Promisable<T> = T | Promise<T>; | ||
export type ResolveProtocolConnectFunction = (options: tls.ConnectionOptions, callback: () => void) => Promisable<tls.TLSSocket>; | ||
export const request: RequestFunction<http.ClientRequest>; | ||
export const get: RequestFunction<http.ClientRequest>; | ||
export const auto: RequestFunction<Promise<http.ClientRequest>, AutoRequestOptions> & {protocolCache: QuickLRU<string, string>}; | ||
export const auto: RequestFunction<Promise<http.ClientRequest>, AutoRequestOptions> & { | ||
protocolCache: QuickLRU<string, string>; | ||
resolveProtocol: ResolveProtocolFunction; | ||
createResolveProtocol: (cache: Map<string, string>, queue: Map<string, Promise<ResolveProtocolResult>>, connect?: ResolveProtocolConnectFunction) => ResolveProtocolFunction; | ||
}; | ||
@@ -117,0 +133,0 @@ export { |
{ | ||
"name": "http2-wrapper", | ||
"version": "2.0.9", | ||
"version": "2.1.0", | ||
"description": "HTTP2 client, just with the familiar `https` API", | ||
@@ -35,3 +35,3 @@ "main": "source", | ||
"quick-lru": "^5.1.1", | ||
"resolve-alpn": "^1.1.2" | ||
"resolve-alpn": "^1.2.0" | ||
}, | ||
@@ -38,0 +38,0 @@ "devDependencies": { |
@@ -165,2 +165,26 @@ # http2-wrapper | ||
### http2.auto.createResolveProtocol(cache, queue, connect) | ||
#### cache | ||
Type: `Map<string, string>` | ||
This is the store where cached ALPN protocols are put into. | ||
#### queue | ||
Type: `Map<string, Promise>` | ||
This is the store that contains pending ALPN negotiation promises. | ||
#### connect | ||
Type: `(options, callback) => TLSSocket | Promise<TLSSocket>` | ||
See https://github.com/szmarczak/resolve-alpn#connect | ||
### http2.auto.resolveProtocol(options) | ||
Returns a `Promise<{alpnProtocol: string}>`. | ||
### http2.request(url, options, callback) | ||
@@ -357,2 +381,60 @@ | ||
**Note:** If you use the `http2.auto` function, the real IP address will leak. `http2wrapper` is not aware of the context. It will create a connection to the end server using your real IP address to get the ALPN protocol. Then it will create another connection using proxy. To migitate this, you need to pass a custom `resolveProtocol` function as an option: | ||
```js | ||
const resolveAlpnProxy = new URL('https://username:password@localhost:8000'); | ||
const connect = async (options, callback) => new Promise((resolve, reject) => { | ||
const host = `${options.host}:${options.port}`; | ||
(async () => { | ||
try { | ||
const request = await http2.auto(resolveAlpnProxy, { | ||
method: 'CONNECT', | ||
headers: { | ||
host | ||
}, | ||
path: host, | ||
// For demo purposes only! | ||
rejectUnauthorized: false, | ||
}); | ||
request.end(); | ||
request.once('connect', (response, socket, head) => { | ||
if (head.length > 0) { | ||
reject(new Error(`Unexpected data before CONNECT tunnel: ${head.length} bytes`)); | ||
socket.destroy(); | ||
return; | ||
} | ||
const tlsSocket = tls.connect({ | ||
...options, | ||
socket | ||
}, callback); | ||
resolve(tlsSocket); | ||
}); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
})(); | ||
}); | ||
// This is required to prevent leaking real IP address on ALPN negotiation | ||
const resolveProtocol = http2.auto.createResolveProtocol(new Map(), new Map(), connect); | ||
const request = await http2.auto('https://httpbin.org/anything', { | ||
agent: {…}, | ||
resolveProtocol | ||
}, response => { | ||
// Read the response here | ||
}); | ||
request.end(); | ||
``` | ||
See [`unknown-over-unknown.js`](examples/proxies/unknown-over-unknown.js) to learn more. | ||
## Mirroring another server | ||
@@ -359,0 +441,0 @@ |
@@ -57,38 +57,42 @@ 'use strict'; | ||
const resolveProtocol = async options => { | ||
const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`; | ||
const createResolveProtocol = (cache, queue = new Map(), connect = undefined) => { | ||
return async options => { | ||
const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`; | ||
if (!cache.has(name)) { | ||
if (queue.has(name)) { | ||
const result = await queue.get(name); | ||
return {alpnProtocol: result.alpnProtocol}; | ||
} | ||
if (!cache.has(name)) { | ||
if (queue.has(name)) { | ||
const result = await queue.get(name); | ||
return {alpnProtocol: result.alpnProtocol}; | ||
} | ||
const {path} = options; | ||
options.path = options.socketPath; | ||
const {path} = options; | ||
options.path = options.socketPath; | ||
const resultPromise = resolveALPN(options); | ||
queue.set(name, resultPromise); | ||
const resultPromise = resolveALPN(options, connect); | ||
queue.set(name, resultPromise); | ||
try { | ||
const result = await resultPromise; | ||
try { | ||
const result = await resultPromise; | ||
cache.set(name, result.alpnProtocol); | ||
queue.delete(name); | ||
cache.set(name, result.alpnProtocol); | ||
queue.delete(name); | ||
options.path = path; | ||
options.path = path; | ||
return result; | ||
} catch (error) { | ||
queue.delete(name); | ||
return result; | ||
} catch (error) { | ||
queue.delete(name); | ||
options.path = path; | ||
options.path = path; | ||
throw error; | ||
throw error; | ||
} | ||
} | ||
} | ||
return {alpnProtocol: cache.get(name)}; | ||
return {alpnProtocol: cache.get(name)}; | ||
}; | ||
}; | ||
const defaultResolveProtocol = createResolveProtocol(cache, queue); | ||
module.exports = async (input, options, callback) => { | ||
@@ -127,2 +131,4 @@ if (typeof input === 'string') { | ||
const resolveProtocol = options.resolveProtocol || defaultResolveProtocol; | ||
// Note: We don't support `h2session` here | ||
@@ -200,2 +206,3 @@ | ||
module.exports.protocolCache = cache; | ||
module.exports.resolveProtocol = resolveProtocol; | ||
module.exports.resolveProtocol = defaultResolveProtocol; | ||
module.exports.createResolveProtocol = createResolveProtocol; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
73692
1848
458
Updatedresolve-alpn@^1.2.0