Comparing version 11.0.0-3 to 11.0.0
@@ -13,12 +13,1 @@ import { Request, Response } from 'servie'; | ||
export declare function normalizeRequest<T extends Request, U extends Response>(options?: NormalizeRequestOptions): Middleware<T, U>; | ||
/** | ||
* Redirect middleware configuration. | ||
*/ | ||
export interface FollowRedirectsOptions { | ||
maxRedirects?: number; | ||
confirmRedirect?: (request: Request, response: Response) => boolean; | ||
} | ||
/** | ||
* Middleware function for following HTTP redirects. | ||
*/ | ||
export declare function followRedirects<T extends Request, U extends Response>(options?: FollowRedirectsOptions): Middleware<T, U>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const url_1 = require("url"); | ||
const servie_1 = require("servie"); | ||
const error_1 = require("./error"); | ||
const universal_1 = require("servie/dist/body/universal"); | ||
/** | ||
@@ -20,5 +8,2 @@ * Default header handling. | ||
return function (req, next) { | ||
// Block requests when already aborted. | ||
if (req.aborted) | ||
return Promise.reject(new error_1.PopsicleError('Request aborted', 'EABORT', req)); | ||
// Remove headers that should not be created by the user. | ||
@@ -40,70 +25,2 @@ req.headers.delete('Host'); | ||
exports.normalizeRequest = normalizeRequest; | ||
/** | ||
* Redirection types to handle. | ||
*/ | ||
var REDIRECT_TYPE; | ||
(function (REDIRECT_TYPE) { | ||
REDIRECT_TYPE[REDIRECT_TYPE["FOLLOW_WITH_GET"] = 0] = "FOLLOW_WITH_GET"; | ||
REDIRECT_TYPE[REDIRECT_TYPE["FOLLOW_WITH_CONFIRMATION"] = 1] = "FOLLOW_WITH_CONFIRMATION"; | ||
})(REDIRECT_TYPE || (REDIRECT_TYPE = {})); | ||
/** | ||
* Possible redirection status codes. | ||
*/ | ||
const REDIRECT_STATUS = { | ||
'301': REDIRECT_TYPE.FOLLOW_WITH_GET, | ||
'302': REDIRECT_TYPE.FOLLOW_WITH_GET, | ||
'303': REDIRECT_TYPE.FOLLOW_WITH_GET, | ||
'307': REDIRECT_TYPE.FOLLOW_WITH_CONFIRMATION, | ||
'308': REDIRECT_TYPE.FOLLOW_WITH_CONFIRMATION | ||
}; | ||
/** | ||
* Middleware function for following HTTP redirects. | ||
*/ | ||
function followRedirects(options = {}) { | ||
return function (initialRequest, next) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let req = initialRequest.clone(); | ||
let redirectCount = 0; | ||
const maxRedirects = typeof options.maxRedirects === 'number' ? options.maxRedirects : 5; | ||
const confirmRedirect = options.confirmRedirect || (() => false); | ||
while (redirectCount++ < maxRedirects) { | ||
const res = yield next(req); | ||
const redirect = REDIRECT_STATUS[res.statusCode]; | ||
if (redirect === undefined || !res.headers.has('Location')) | ||
return res; | ||
const newUrl = url_1.resolve(req.url, res.headers.get('Location')); // tslint:disable-line | ||
// Ignore the result of the response on redirect. | ||
req.abort(); | ||
req.events.emit('redirect', newUrl); | ||
if (redirect === REDIRECT_TYPE.FOLLOW_WITH_GET) { | ||
req = initialRequest.clone(); | ||
req.headers.set('Content-Length', '0'); | ||
req.url = newUrl; | ||
req.method = req.method.toUpperCase() === 'HEAD' ? 'HEAD' : 'GET'; | ||
req.body = universal_1.createBody(undefined); | ||
req.trailer = Promise.resolve(servie_1.createHeaders()); | ||
continue; | ||
} | ||
if (redirect === REDIRECT_TYPE.FOLLOW_WITH_CONFIRMATION) { | ||
const method = req.method.toUpperCase(); | ||
// Following HTTP spec by automatically redirecting with GET/HEAD. | ||
if (method === 'GET' || method === 'HEAD') { | ||
req = initialRequest.clone(); | ||
req.url = newUrl; | ||
continue; | ||
} | ||
// Allow the user to confirm redirect according to HTTP spec. | ||
if (confirmRedirect(req, res)) { | ||
req = initialRequest.clone(); | ||
req.url = newUrl; | ||
continue; | ||
} | ||
} | ||
return res; | ||
} | ||
throw new error_1.PopsicleError(`Maximum redirects exceeded: ${maxRedirects}`, 'EMAXREDIRECTS', req); | ||
}); | ||
}; | ||
} | ||
exports.followRedirects = followRedirects; | ||
//# sourceMappingURL=common.js.map |
@@ -7,6 +7,6 @@ "use strict"; | ||
describe('common', () => { | ||
it('should export `followRedirects` middleware', () => { | ||
expect(typeof common_1.followRedirects).toEqual('function'); | ||
it('should export `normalizeRequest` middleware', () => { | ||
expect(typeof common_1.normalizeRequest).toEqual('function'); | ||
}); | ||
}); | ||
//# sourceMappingURL=common.spec.js.map |
@@ -69,3 +69,3 @@ "use strict"; | ||
req.abort(); | ||
expect.assertions(2); | ||
expect.assertions(1); | ||
try { | ||
@@ -75,4 +75,3 @@ yield node_1.transport()(req); | ||
catch (err) { | ||
expect(err.message).toEqual('Request aborted'); | ||
expect(err.code).toEqual('EABORT'); | ||
expect(err.message).toEqual('Request has been aborted'); | ||
} | ||
@@ -92,7 +91,6 @@ })); | ||
try { | ||
const res = yield node_1.transport()(req); | ||
expect(yield res.body.text()).toEqual(''); | ||
yield node_1.transport()(req); | ||
} | ||
catch (err) { | ||
expect(err.code).toEqual('EABORT'); | ||
expect(err.message).toEqual('Request has been aborted'); | ||
} | ||
@@ -99,0 +97,0 @@ })); |
/// <reference types="node" /> | ||
import { CookieJar } from 'tough-cookie'; | ||
import { Middleware } from 'throwback'; | ||
import { Middleware, Composed } from 'throwback'; | ||
import { Agent } from 'http'; | ||
@@ -8,3 +8,3 @@ import { SecureContext } from 'tls'; | ||
import { Body } from 'servie/dist/body/node'; | ||
import { FollowRedirectsOptions, NormalizeRequestOptions } from '../common'; | ||
import { NormalizeRequestOptions } from '../common'; | ||
/** | ||
@@ -57,2 +57,16 @@ * Extend response with URL. | ||
export declare function normalizeUserAgent<T extends Request, U extends Response>(options?: NormalizeUserAgentOptions): Middleware<T, U>; | ||
/** | ||
* Redirect middleware configuration. | ||
*/ | ||
export interface FollowRedirectsOptions { | ||
maxRedirects?: number; | ||
confirmRedirect?: (request: Request, response: Response) => boolean; | ||
} | ||
/** | ||
* Middleware function for following HTTP redirects. | ||
*/ | ||
export declare function followRedirects<T extends Request, U extends Response>(process: Composed<T, U>, options?: FollowRedirectsOptions): Composed<T, U>; | ||
/** | ||
* Track HTTP connections for reuse. | ||
*/ | ||
export declare class ConnectionManager<T> { | ||
@@ -97,3 +111,3 @@ connections: Map<string, T>; | ||
HTTP2_FOR_HTTPS = 1, | ||
HTTP2_ONLY = 2, | ||
HTTP2_ONLY = 2 | ||
} | ||
@@ -100,0 +114,0 @@ /** |
@@ -12,2 +12,3 @@ "use strict"; | ||
const pump = require("pump"); | ||
const url_1 = require("url"); | ||
const tough_cookie_1 = require("tough-cookie"); | ||
@@ -112,2 +113,73 @@ const throwback_1 = require("throwback"); | ||
exports.normalizeUserAgent = normalizeUserAgent; | ||
/** | ||
* Redirection types to handle. | ||
*/ | ||
var REDIRECT_TYPE; | ||
(function (REDIRECT_TYPE) { | ||
REDIRECT_TYPE[REDIRECT_TYPE["FOLLOW_WITH_GET"] = 0] = "FOLLOW_WITH_GET"; | ||
REDIRECT_TYPE[REDIRECT_TYPE["FOLLOW_WITH_CONFIRMATION"] = 1] = "FOLLOW_WITH_CONFIRMATION"; | ||
})(REDIRECT_TYPE || (REDIRECT_TYPE = {})); | ||
/** | ||
* Possible redirection status codes. | ||
*/ | ||
const REDIRECT_STATUS = { | ||
'301': REDIRECT_TYPE.FOLLOW_WITH_GET, | ||
'302': REDIRECT_TYPE.FOLLOW_WITH_GET, | ||
'303': REDIRECT_TYPE.FOLLOW_WITH_GET, | ||
'307': REDIRECT_TYPE.FOLLOW_WITH_CONFIRMATION, | ||
'308': REDIRECT_TYPE.FOLLOW_WITH_CONFIRMATION | ||
}; | ||
/** | ||
* Middleware function for following HTTP redirects. | ||
*/ | ||
function followRedirects(process, options = {}) { | ||
return function (initialRequest, done) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let req = initialRequest.clone(); | ||
let redirectCount = 0; | ||
const maxRedirects = typeof options.maxRedirects === 'number' ? options.maxRedirects : 5; | ||
const confirmRedirect = options.confirmRedirect || (() => false); | ||
while (redirectCount++ < maxRedirects) { | ||
const res = yield process(req, done); | ||
const redirect = REDIRECT_STATUS[res.statusCode]; | ||
if (redirect === undefined || !res.headers.has('Location')) | ||
return res; | ||
const newUrl = url_1.resolve(req.url, res.headers.get('Location')); // tslint:disable-line | ||
// Ignore the result of the response on redirect. | ||
req.abort(); | ||
req.events.emit('redirect', newUrl); | ||
if (redirect === REDIRECT_TYPE.FOLLOW_WITH_GET) { | ||
req = initialRequest.clone(); | ||
req.headers.set('Content-Length', '0'); | ||
req.url = newUrl; | ||
req.method = req.method.toUpperCase() === 'HEAD' ? 'HEAD' : 'GET'; | ||
req.body = node_1.createBody(undefined); | ||
req.trailer = Promise.resolve(servie_1.createHeaders()); | ||
continue; | ||
} | ||
if (redirect === REDIRECT_TYPE.FOLLOW_WITH_CONFIRMATION) { | ||
const method = req.method.toUpperCase(); | ||
// Following HTTP spec by automatically redirecting with GET/HEAD. | ||
if (method === 'GET' || method === 'HEAD') { | ||
req = initialRequest.clone(); | ||
req.url = newUrl; | ||
continue; | ||
} | ||
// Allow the user to confirm redirect according to HTTP spec. | ||
if (confirmRedirect(req, res)) { | ||
req = initialRequest.clone(); | ||
req.url = newUrl; | ||
continue; | ||
} | ||
} | ||
return res; | ||
} | ||
throw new error_1.PopsicleError(`Maximum redirects exceeded: ${maxRedirects}`, 'EMAXREDIRECTS', req); | ||
}); | ||
}; | ||
} | ||
exports.followRedirects = followRedirects; | ||
/** | ||
* Track HTTP connections for reuse. | ||
*/ | ||
class ConnectionManager { | ||
@@ -552,13 +624,14 @@ constructor() { | ||
function transport(options = {}) { | ||
const fns = [common_1.normalizeRequest(options), normalizeUserAgent(options)]; | ||
const fns = []; | ||
const { jar = new tough_cookie_1.CookieJar(), unzip = true, follow = true } = options; | ||
// Built-in behaviours. | ||
fns.push(common_1.normalizeRequest(options)); | ||
fns.push(normalizeUserAgent(options)); | ||
if (unzip) | ||
fns.push(autoUnzip()); | ||
if (follow) | ||
fns.push(common_1.followRedirects(options)); | ||
if (jar) | ||
fns.push(getCookies({ jar }), saveCookies({ jar })); | ||
const done = send(options); | ||
const middlware = throwback_1.compose(fns); | ||
return (req) => middlware(req, done); | ||
const middleware = follow ? followRedirects(throwback_1.compose(fns), options) : throwback_1.compose(fns); | ||
return (req) => middleware(req, done); | ||
} | ||
@@ -565,0 +638,0 @@ exports.transport = transport; |
{ | ||
"name": "popsicle", | ||
"version": "11.0.0-3", | ||
"version": "11.0.0", | ||
"description": "Advanced HTTP requests in node.js and browsers, using Servie", | ||
@@ -23,3 +23,3 @@ "main": "dist/universal.js", | ||
"test": "npm run lint && npm run build && npm run server:open && npm run specs; EXIT=$?; npm run server:close; exit $EXIT", | ||
"prepublish": "npm run build" | ||
"prepare": "npm run build" | ||
}, | ||
@@ -67,3 +67,3 @@ "repository": { | ||
"devDependencies": { | ||
"@types/jest": "^22.2.3", | ||
"@types/jest": "^23.3.5", | ||
"@types/node": "^10.1.2", | ||
@@ -74,9 +74,9 @@ "body-parser": "^1.18.3", | ||
"express": "^4.16.3", | ||
"jest": "^22.4.4", | ||
"jest": "^23.6.0", | ||
"methods": "^1.1.2", | ||
"rimraf": "^2.6.2", | ||
"ts-jest": "^22.4.6", | ||
"ts-jest": "^23.10.4", | ||
"tslint": "^5.10.0", | ||
"tslint-config-standard": "^7.0.0", | ||
"typescript": "^2.8.3" | ||
"tslint-config-standard": "^8.0.1", | ||
"typescript": "^3.1.3" | ||
}, | ||
@@ -89,5 +89,5 @@ "dependencies": { | ||
"servie": "^3.2.3", | ||
"throwback": "^3.0.0", | ||
"throwback": "^4.0.0", | ||
"tough-cookie": "^2.0.0" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
153902
1336
+ Addedthrowback@4.1.0(transitive)
- Removedthrowback@3.0.0(transitive)
Updatedthrowback@^4.0.0