Skip to content

Commit 8fe3c21

Browse files
author
Denis Rechkunov
committed
Merge branch 'release/3.0.0'
Conflicts: README.md
2 parents 91529d8 + 3ce6f01 commit 8fe3c21

6 files changed

Lines changed: 347 additions & 158 deletions

File tree

README.md

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#Universal HTTP(S) Request for Catberry 2 [![Build Status](https://travis-ci.org/catberry/catberry-uhr.png?branch=master)](https://travis-ci.org/catberry/catberry-uhr) [![Coverage Status](https://coveralls.io/repos/catberry/catberry-uhr/badge.png?branch=master)](https://coveralls.io/r/catberry/catberry-uhr?branch=master) [![Codacy Badge](https://www.codacy.com/project/badge/5576b3df3def4b769978b42818ad96bc)](https://www.codacy.com/public/catberry/catberry-uhr.git)
1+
#Universal HTTP(S) Request for Catberry [![Build Status](https://travis-ci.org/catberry/catberry-uhr.png?branch=master)](https://travis-ci.org/catberry/catberry-uhr) [![Coverage Status](https://coveralls.io/repos/catberry/catberry-uhr/badge.png?branch=master)](https://coveralls.io/r/catberry/catberry-uhr?branch=master)
22
[![NPM](https://nodei.co/npm/catberry-uhr.png)](https://nodei.co/npm/catberry-uhr/)
33

44
##Description
@@ -30,49 +30,81 @@ UHR has following methods:
3030
/**
3131
* Does GET request to HTTP server.
3232
* @param {string} url URL to request.
33-
* @param {Object} options Object with options.
33+
* @param {Object?} options Request parameters.
34+
* @param {Object?} options.headers HTTP headers to send.
35+
* @param {String|Object?} options.data Data to send.
36+
* @param {Number?} options.timeout Request timeout.
37+
* @param {Boolean?} options.unsafeHTTPS If true then requests to servers with
38+
* invalid HTTPS certificates are allowed.
3439
* @returns {Promise<Object>} Promise for result with status object and content.
3540
*/
36-
UHRBase.prototype.get = function (url, options) { };
41+
UHRBase.prototype.get = function (url, options) { }
3742

3843
/**
3944
* Does POST request to HTTP server.
4045
* @param {string} url URL to request.
41-
* @param {Object} options Object with options.
46+
* @param {Object?} options Request parameters.
47+
* @param {Object?} options.headers HTTP headers to send.
48+
* @param {String|Object?} options.data Data to send.
49+
* @param {Number?} options.timeout Request timeout.
50+
* @param {Boolean?} options.unsafeHTTPS If true then requests to servers with
51+
* invalid HTTPS certificates are allowed.
4252
* @returns {Promise<Object>} Promise for result with status object and content.
4353
*/
44-
UHRBase.prototype.post = function (url, options) { };
54+
UHRBase.prototype.post = function (url, options) { }
4555

4656
/**
4757
* Does PUT request to HTTP server.
4858
* @param {string} url URL to request.
49-
* @param {Object} options Object with options.
59+
* @param {Object?} options Request parameters.
60+
* @param {Object?} options.headers HTTP headers to send.
61+
* @param {String|Object?} options.data Data to send.
62+
* @param {Number?} options.timeout Request timeout.
63+
* @param {Boolean?} options.unsafeHTTPS If true then requests to servers with
64+
* invalid HTTPS certificates are allowed.
5065
* @returns {Promise<Object>} Promise for result with status object and content.
5166
*/
52-
UHRBase.prototype.put = function (url, options) { };
67+
UHRBase.prototype.put = function (url, options) { }
5368

5469
/**
5570
* Does PATCH request to HTTP server.
5671
* @param {string} url URL to request.
57-
* @param {Object} options Object with options.
72+
* @param {Object?} options Request parameters.
73+
* @param {Object?} options.headers HTTP headers to send.
74+
* @param {String|Object?} options.data Data to send.
75+
* @param {Number?} options.timeout Request timeout.
76+
* @param {Boolean?} options.unsafeHTTPS If true then requests to servers with
77+
* invalid HTTPS certificates are allowed.
5878
* @returns {Promise<Object>} Promise for result with status object and content.
5979
*/
60-
UHRBase.prototype.patch = function (url, options) { };
80+
UHRBase.prototype.patch = function (url, options) { }
6181

6282
/**
6383
* Does DELETE request to HTTP server.
6484
* @param {string} url URL to request.
65-
* @param {Object} options Object with options.
85+
* @param {Object?} options Request parameters.
86+
* @param {Object?} options.headers HTTP headers to send.
87+
* @param {String|Object?} options.data Data to send.
88+
* @param {Number?} options.timeout Request timeout.
89+
* @param {Boolean?} options.unsafeHTTPS If true then requests to servers with
90+
* invalid HTTPS certificates are allowed.
6691
* @returns {Promise<Object>} Promise for result with status object and content.
6792
*/
68-
UHRBase.prototype.delete = function (url, options) { };
93+
UHRBase.prototype.delete = function (url, options) { }
6994

7095
/**
7196
* Does request with specified parameters.
7297
* @param {Object} parameters Request parameters.
98+
* @param {String} parameters.method HTTP method.
99+
* @param {String} parameters.url URL for request.
100+
* @param {Object?} parameters.headers HTTP headers to send.
101+
* @param {String|Object?} parameters.data Data to send.
102+
* @param {Number?} parameters.timeout Request timeout.
103+
* @param {Boolean?} parameters.unsafeHTTPS If true then requests
104+
* to servers with invalid HTTPS certificates are allowed.
73105
* @returns {Promise<Object>} Promise for result with status object and content.
74106
*/
75-
UHRBase.prototype.request = function (parameters) { };
107+
UHRBase.prototype.request = function (parameters) { }
76108
```
77109

78110
##Request options example
@@ -91,11 +123,17 @@ UHRBase.prototype.request = function (parameters) { };
91123
}
92124
```
93125

94-
In case you do `POST`/`PUT`/`PATCH` request `data` will be passed as
95-
JSON via request stream otherwise it will be passed as query string.
96-
Also if you put something to `data` field and use
126+
In case you do `POST`/`PUT`/`PATCH` requests then `data` object will
127+
be passed as `application/x-www-form-urlencoded` via request stream.
128+
If you set header `Content-Type` to `application/json` then object will
129+
be sent as JSON.
130+
131+
If `data` value is not an object then its string representation will be sent
132+
as `text/plain` to server.
133+
134+
Also if you put something to `data` object and use
97135
`application/x-www-form-urlencoded` then this data will be
98-
automatically [encoded](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent).
136+
automatically [percent-encoded](http://en.wikipedia.org/wiki/Percent-encoding).
99137

100138
##Returns promise
101139
Any UHR request returns [Promise](https://www.promisejs.org) for request result.

browser/UHR.js

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ module.exports = UHR;
3434

3535
var UHRBase = require('../lib/UHRBase'),
3636
Promise = require('promise'),
37-
url = require('url'),
37+
URI = require('catberry-uri').URI,
3838
util = require('util');
3939

4040
// if browser still does not have promises then add it.
@@ -72,32 +72,29 @@ UHR.prototype.window = null;
7272
/**
7373
* Does request with specified parameters using protocol implementation.
7474
* @param {Object} parameters Request parameters.
75+
* @param {String} parameters.method HTTP method.
76+
* @param {String} parameters.url URL for request.
77+
* @param {URI} parameters.uri URI object.
78+
* @param {Object} parameters.headers HTTP headers to send.
79+
* @param {String|Object} parameters.data Data to send.
80+
* @param {Number} parameters.timeout Request timeout.
81+
* @param {Boolean} parameters.unsafeHTTPS If true then requests to servers with
82+
* invalid HTTPS certificates are allowed.
7583
* @returns {Promise<Object>} Promise for result with status object and content.
7684
* @protected
7785
*/
7886
UHR.prototype._doRequest = function (parameters) {
79-
var self = this,
80-
xhrParameters = Object.create(parameters),
81-
urlInfo = url.parse(parameters.url);
82-
xhrParameters.headers = this._createHeaders(parameters.headers);
87+
var self = this;
8388

84-
Object.keys(xhrParameters.headers)
89+
Object.keys(parameters.headers)
8590
.forEach(function (name) {
8691
if (NON_SAFE_HEADERS.hasOwnProperty(name.toLowerCase())) {
87-
delete xhrParameters.headers[name];
92+
delete parameters.headers[name];
8893
}
8994
});
9095

91-
if (xhrParameters.data.length > 0 &&
92-
!this._isUpstreamRequest(xhrParameters.method)) {
93-
xhrParameters.url +=
94-
(!urlInfo.search || urlInfo.search.length === 0 ? '?' : '&') +
95-
xhrParameters.data;
96-
}
97-
9896
return new Promise(function (fulfill, reject) {
9997
var requestError = null,
100-
loginAndPass = String(urlInfo.auth || '').split(':'),
10198
xhr = new self.window.XMLHttpRequest();
10299

103100
xhr.onabort = function () {
@@ -118,27 +115,30 @@ UHR.prototype._doRequest = function (parameters) {
118115
}
119116
var statusObject = getStatusObject(xhr),
120117
content = self.convertResponse(
121-
statusObject.headers['content-type'],
118+
statusObject.headers,
122119
xhr.responseText
123120
);
124121
fulfill({status: statusObject, content: content});
125122
};
126123

124+
var user = parameters.uri.authority.userInfo ?
125+
parameters.uri.authority.userInfo.user : null,
126+
password = parameters.uri.authority.userInfo ?
127+
parameters.uri.authority.userInfo.password : null;
127128
xhr.open(
128-
xhrParameters.method, xhrParameters.url, true,
129-
loginAndPass[0], loginAndPass[1]
129+
parameters.method, parameters.uri.toString(), true,
130+
user || undefined, password || undefined
130131
);
131-
xhr.timeout = xhrParameters.timeout;
132+
xhr.timeout = parameters.timeout;
132133

133-
Object.keys(xhrParameters.headers)
134+
Object.keys(parameters.headers)
134135
.forEach(function (headerName) {
135136
xhr.setRequestHeader(
136-
headerName, xhrParameters.headers[headerName]
137+
headerName, parameters.headers[headerName]
137138
);
138139
});
139140

140-
xhr.send(xhrParameters.data);
141-
141+
xhr.send(parameters.data);
142142
});
143143
};
144144

lib/UHR.js

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
module.exports = UHR;
3434

35-
var url = require('url'),
35+
var URI = require('catberry-uri'),
3636
util = require('util'),
3737
http = require('http'),
3838
https = require('https'),
@@ -71,37 +71,44 @@ function UHR() {
7171
/**
7272
* Does request with specified parameters using protocol implementation.
7373
* @param {Object} parameters Request parameters.
74+
* @param {String} parameters.method HTTP method.
75+
* @param {String} parameters.url URL for request.
76+
* @param {URI} parameters.uri URI object.
77+
* @param {Object} parameters.headers HTTP headers to send.
78+
* @param {String|Object} parameters.data Data to send.
79+
* @param {Number} parameters.timeout Request timeout.
80+
* @param {Boolean} parameters.unsafeHTTPS If true then requests to servers with
81+
* invalid HTTPS certificates are allowed.
7482
* @returns {Promise<Object>} Promise for result with status object and content.
7583
* @protected
7684
*/
7785
UHR.prototype._doRequest = function (parameters) {
78-
var self = this,
79-
urlInfo = url.parse(parameters.url),
80-
protocol = urlInfo.protocol === 'http:' ? http : https,
81-
requestOptions = {
82-
method: parameters.method,
83-
headers: this._createHeaders(parameters.headers),
84-
path: urlInfo.path,
85-
host: urlInfo.host,
86-
hostname: urlInfo.hostname,
87-
port: urlInfo.port,
88-
auth: urlInfo.auth,
89-
rejectUnauthorized: ('unsafeHTTPS' in parameters) ?
90-
!Boolean(parameters.unsafeHTTPS)
91-
: true
92-
};
93-
94-
// RFC 2616 14.23. This header is required
95-
requestOptions.headers.Host = urlInfo.host;
96-
97-
if (parameters.data.length > 0 &&
98-
!this._isUpstreamRequest(requestOptions.method)) {
99-
requestOptions.path +=
100-
(!urlInfo.search || urlInfo.search.length === 0 ? '?' : '&') +
101-
parameters.data;
102-
}
103-
86+
var self = this;
10487
return new Promise(function (fulfill, reject) {
88+
var pathAndQuery = parameters.uri.clone();
89+
pathAndQuery.scheme = null;
90+
pathAndQuery.authority = null;
91+
pathAndQuery.fragment = null;
92+
93+
var protocol = parameters.uri.scheme === 'https' ? https : http,
94+
requestOptions = {
95+
method: parameters.method,
96+
headers: parameters.headers,
97+
path: pathAndQuery.toString(),
98+
hostname: parameters.uri.authority.host,
99+
port: parameters.uri.authority.port || null,
100+
auth: parameters.uri.authority.userInfo ?
101+
parameters.uri.authority.userInfo.toString() : null,
102+
rejectUnauthorized: ('unsafeHTTPS' in parameters) ?
103+
!Boolean(parameters.unsafeHTTPS)
104+
: true
105+
};
106+
107+
var authorityWithoutUserInfo = parameters.uri.authority.clone();
108+
authorityWithoutUserInfo.userInfo = null;
109+
// RFC 2616 14.23. This header is required
110+
requestOptions.headers.Host = authorityWithoutUserInfo.toString();
111+
105112
var request = protocol.request(requestOptions, function (response) {
106113
self._processResponse(response).then(fulfill, reject);
107114
});
@@ -129,26 +136,26 @@ UHR.prototype._doRequest = function (parameters) {
129136
* @private
130137
*/
131138
UHR.prototype._processResponse = function (response) {
132-
var headers = response.headers || {},
133-
encoding = headers['content-encoding'],
134-
responseData = '',
135-
responseStream;
136-
137-
switch (encoding) {
138-
case ENCODINGS.GZIP:
139-
responseStream = response.pipe(zlib.createGunzip());
140-
break;
141-
case ENCODINGS.DEFLATE:
142-
responseStream = response.pipe(zlib.createInflate());
143-
break;
144-
default :
145-
responseStream = response;
146-
}
147-
148139
var self = this;
149140

150-
responseStream.setEncoding('utf8');
151141
return new Promise(function (fulfill, reject) {
142+
var headers = response.headers || {},
143+
encoding = headers['content-encoding'],
144+
responseData = '',
145+
responseStream;
146+
147+
switch (encoding) {
148+
case ENCODINGS.GZIP:
149+
responseStream = response.pipe(zlib.createGunzip());
150+
break;
151+
case ENCODINGS.DEFLATE:
152+
responseStream = response.pipe(zlib.createInflate());
153+
break;
154+
default :
155+
responseStream = response;
156+
}
157+
158+
responseStream.setEncoding('utf8');
152159
responseStream
153160
.on('data', function (chunk) {
154161
responseData += chunk;
@@ -157,22 +164,23 @@ UHR.prototype._processResponse = function (response) {
157164
reject(error);
158165
})
159166
.on('end', function () {
160-
var contentType = headers['content-type'] || '';
161167
fulfill({
162168
status: getStatusObject(response),
163-
content: self.convertResponse(contentType, responseData)
169+
content: self.convertResponse(headers, responseData)
164170
});
165171
});
166172
});
167173
};
168174

169175
/**
170-
* Creates HTTP headers for current UHR.
171-
* @param {Object} parameterHeaders HTTP headers from UHR parameters.
172-
* @returns {Object} HTTP headers for UHR.
173-
* @private
176+
* Creates HTTP headers for request using defaults and current parameters.
177+
* @param {Object} parameterHeaders HTTP headers of UHR.
178+
* @protected
174179
*/
175180
UHR.prototype._createHeaders = function (parameterHeaders) {
181+
if (!parameterHeaders || typeof(parameterHeaders) !== 'object') {
182+
parameterHeaders = {};
183+
}
176184
var headers = {
177185
'Accept-Encoding': ACCEPT_ENCODING,
178186
'User-Agent': USER_AGENT

0 commit comments

Comments
 (0)