2016-04-05 10:43:12 -07:00
|
|
|
|
2015-06-03 21:05:01 -07:00
|
|
|
/**
|
|
|
|
* request.js
|
|
|
|
*
|
|
|
|
* Request class contains server only options
|
|
|
|
*/
|
|
|
|
|
2016-10-08 18:31:42 -07:00
|
|
|
import { format as format_url, parse as parse_url } from 'url';
|
2016-10-10 11:50:04 -07:00
|
|
|
import Headers from './headers.js';
|
2016-11-23 13:39:35 -08:00
|
|
|
import Body, { clone, extractContentType, getTotalBytes } from './body';
|
|
|
|
|
|
|
|
const PARSED_URL = Symbol('url');
|
2015-06-03 21:05:01 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Request class
|
|
|
|
*
|
|
|
|
* @param Mixed input Url or Request instance
|
|
|
|
* @param Object init Custom options
|
|
|
|
* @return Void
|
|
|
|
*/
|
2016-10-10 11:50:04 -07:00
|
|
|
export default class Request extends Body {
|
|
|
|
constructor(input, init = {}) {
|
2016-10-08 18:31:42 -07:00
|
|
|
let parsedURL;
|
2015-06-03 21:05:01 -07:00
|
|
|
|
2016-10-10 11:50:04 -07:00
|
|
|
// normalize input
|
|
|
|
if (!(input instanceof Request)) {
|
2016-10-12 19:56:47 -07:00
|
|
|
if (input && input.href) {
|
|
|
|
// in order to support Node.js' Url objects; though WHATWG's URL objects
|
|
|
|
// will fall into this branch also (since their `toString()` will return
|
|
|
|
// `href` property anyway)
|
|
|
|
parsedURL = parse_url(input.href);
|
|
|
|
} else {
|
|
|
|
// coerce input to a string before attempting to parse
|
|
|
|
parsedURL = parse_url(input + '');
|
|
|
|
}
|
2016-10-10 11:50:04 -07:00
|
|
|
input = {};
|
|
|
|
} else {
|
2016-10-08 18:31:42 -07:00
|
|
|
parsedURL = parse_url(input.url);
|
2016-10-10 11:50:04 -07:00
|
|
|
}
|
2015-06-03 21:05:01 -07:00
|
|
|
|
2016-12-04 13:13:51 -08:00
|
|
|
let method = init.method || input.method || 'GET';
|
|
|
|
|
2016-12-04 13:16:03 -08:00
|
|
|
if ((init.body != null || input instanceof Request && input.body !== null) &&
|
2016-12-04 13:13:51 -08:00
|
|
|
(method === 'GET' || method === 'HEAD')) {
|
|
|
|
throw new TypeError('Request with GET/HEAD method cannot have body');
|
|
|
|
}
|
|
|
|
|
2016-12-04 13:16:03 -08:00
|
|
|
let inputBody = init.body != null ?
|
|
|
|
init.body :
|
|
|
|
input instanceof Request && input.body !== null ?
|
|
|
|
clone(input) :
|
|
|
|
null;
|
|
|
|
|
|
|
|
super(inputBody, {
|
2016-10-10 11:50:04 -07:00
|
|
|
timeout: init.timeout || input.timeout || 0,
|
|
|
|
size: init.size || input.size || 0
|
|
|
|
});
|
2015-06-03 21:05:01 -07:00
|
|
|
|
2016-10-10 11:50:04 -07:00
|
|
|
// fetch spec options
|
2016-12-04 13:13:51 -08:00
|
|
|
this.method = method;
|
2016-10-10 11:50:04 -07:00
|
|
|
this.redirect = init.redirect || input.redirect || 'follow';
|
|
|
|
this.headers = new Headers(init.headers || input.headers || {});
|
2015-06-03 21:40:01 -07:00
|
|
|
|
2016-12-04 13:13:51 -08:00
|
|
|
if (init.body != null) {
|
2016-11-23 12:42:24 -08:00
|
|
|
const contentType = extractContentType(this);
|
2016-12-05 20:25:13 -08:00
|
|
|
if (contentType !== null && !this.headers.has('Content-Type')) {
|
2016-11-23 12:42:24 -08:00
|
|
|
this.headers.append('Content-Type', contentType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 11:50:04 -07:00
|
|
|
// server only options
|
|
|
|
this.follow = init.follow !== undefined ?
|
|
|
|
init.follow : input.follow !== undefined ?
|
|
|
|
input.follow : 20;
|
|
|
|
this.compress = init.compress !== undefined ?
|
|
|
|
init.compress : input.compress !== undefined ?
|
|
|
|
input.compress : true;
|
|
|
|
this.counter = init.counter || input.counter || 0;
|
|
|
|
this.agent = init.agent || input.agent;
|
2015-08-10 12:35:01 -07:00
|
|
|
|
2016-11-23 13:39:35 -08:00
|
|
|
this[PARSED_URL] = parsedURL;
|
2016-11-23 14:36:08 -08:00
|
|
|
|
|
|
|
Object.defineProperty(this, Symbol.toStringTag, {
|
|
|
|
value: 'Request',
|
|
|
|
writable: false,
|
|
|
|
enumerable: false,
|
|
|
|
configurable: true
|
|
|
|
});
|
2016-10-08 18:31:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
get url() {
|
2016-11-23 13:39:35 -08:00
|
|
|
return format_url(this[PARSED_URL]);
|
2016-10-10 11:50:04 -07:00
|
|
|
}
|
2015-08-10 12:35:01 -07:00
|
|
|
|
2016-10-10 11:50:04 -07:00
|
|
|
/**
|
|
|
|
* Clone this request
|
|
|
|
*
|
|
|
|
* @return Request
|
|
|
|
*/
|
|
|
|
clone() {
|
|
|
|
return new Request(this);
|
|
|
|
}
|
|
|
|
}
|
2016-11-23 14:36:08 -08:00
|
|
|
|
|
|
|
Object.defineProperty(Request.prototype, Symbol.toStringTag, {
|
|
|
|
value: 'RequestPrototype',
|
|
|
|
writable: false,
|
|
|
|
enumerable: false,
|
|
|
|
configurable: true
|
|
|
|
});
|
2016-11-23 13:39:35 -08:00
|
|
|
|
|
|
|
function normalizeHeaders(request) {
|
|
|
|
const headers = new Headers(request.headers);
|
|
|
|
|
|
|
|
if (request.compress) {
|
|
|
|
headers.set('accept-encoding', 'gzip,deflate');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!headers.has('user-agent')) {
|
|
|
|
headers.set('user-agent', 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!headers.has('connection') && !request.agent) {
|
|
|
|
headers.set('connection', 'close');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!headers.has('accept')) {
|
|
|
|
headers.set('accept', '*/*');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!headers.has('content-length') && /post|put|patch|delete/i.test(request.method)) {
|
|
|
|
const totalBytes = getTotalBytes(request);
|
|
|
|
if (typeof totalBytes === 'number') {
|
|
|
|
headers.set('content-length', totalBytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getNodeRequestOptions(request) {
|
|
|
|
return Object.assign({}, request[PARSED_URL], {
|
|
|
|
method: request.method,
|
|
|
|
headers: normalizeHeaders(request).raw(),
|
|
|
|
agent: request.agent
|
|
|
|
});
|
|
|
|
}
|