├── LICENSE
├── example
├── get
│ ├── index.html
│ ├── main.js
│ ├── node_modules
│ │ └── http-browserify
│ └── server.js
├── headers
│ ├── index.html
│ ├── main.js
│ ├── node_modules
│ │ └── http-browserify
│ └── server.js
├── post
│ ├── index.html
│ ├── main.js
│ ├── node_modules
│ │ └── http-browserify
│ └── server.js
└── streaming
│ ├── index.html
│ ├── main.js
│ ├── node_modules
│ └── http-browserify
│ └── server.js
├── index.js
├── lib
├── request.js
└── response.js
├── package.json
├── readme.markdown
└── test
└── request_url.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2013 James Halliday (mail@substack.net)
4 |
5 | Permission is hereby granted, free of charge,
6 | to any person obtaining a copy of this software and
7 | associated documentation files (the "Software"), to
8 | deal in the Software without restriction, including
9 | without limitation the rights to use, copy, modify,
10 | merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom
12 | the Software is furnished to do so,
13 | subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice
16 | shall be included in all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
22 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/example/get/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | xhr
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/get/main.js:
--------------------------------------------------------------------------------
1 | var http = require('../../');
2 |
3 | http.get({ path : '/beep' }, function (res) {
4 | var div = document.getElementById('result');
5 | div.innerHTML += 'GET /beep
';
6 |
7 | res.on('data', function (buf) {
8 | div.innerHTML += buf;
9 | });
10 |
11 | res.on('end', function () {
12 | div.innerHTML += '
__END__';
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/example/get/node_modules/http-browserify:
--------------------------------------------------------------------------------
1 | ../../../
--------------------------------------------------------------------------------
/example/get/server.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var ecstatic = require('ecstatic')(__dirname);
3 | var server = http.createServer(function (req, res) {
4 | if (req.url === '/beep') {
5 | res.setHeader('content-type', 'text/plain');
6 | res.end('boop');
7 | }
8 | else ecstatic(req, res);
9 | });
10 |
11 | console.log('Listening on :8082');
12 | server.listen(8082);
13 |
--------------------------------------------------------------------------------
/example/headers/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | xhr
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/headers/main.js:
--------------------------------------------------------------------------------
1 | var http = require('../../');
2 |
3 | var opts = { path : '/beep', method : 'GET' };
4 | var req = http.request(opts, function (res) {
5 | var div = document.getElementById('result');
6 |
7 | for (var key in res.headers) {
8 | div.innerHTML += key + ': ' + res.getHeader(key) + '
';
9 | }
10 | div.innerHTML += '
';
11 |
12 | res.on('data', function (buf) {
13 | div.innerHTML += buf;
14 | });
15 | });
16 |
17 | req.setHeader('bling', 'blong');
18 | req.end();
19 |
--------------------------------------------------------------------------------
/example/headers/node_modules/http-browserify:
--------------------------------------------------------------------------------
1 | ../../../
--------------------------------------------------------------------------------
/example/headers/server.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var ecstatic = require('ecstatic')(__dirname);
3 | var server = http.createServer(function (req, res) {
4 | if (req.url === '/beep') {
5 | res.setHeader('content-type', 'text/plain');
6 | res.setHeader('foo', 'bar');
7 | res.setHeader('bling', req.headers.bling + '-blong');
8 |
9 | res.end('boop');
10 | }
11 | else ecstatic(req, res);
12 | });
13 |
14 | console.log('Listening on :8082');
15 | server.listen(8082);
16 |
--------------------------------------------------------------------------------
/example/post/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | xhr
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/post/main.js:
--------------------------------------------------------------------------------
1 | var http = require('../../');
2 |
3 | var n = 100;
4 | var opts = { path : '/plusone', method : 'post' };
5 |
6 | var req = http.request(opts, function (res) {
7 | var div = document.getElementById('result');
8 | div.innerHTML += n.toString() + ' + 1 = ';
9 |
10 | res.on('data', function (buf) {
11 | div.innerHTML += buf;
12 | });
13 | });
14 |
15 | req.write(n);
16 | req.end();
17 |
--------------------------------------------------------------------------------
/example/post/node_modules/http-browserify:
--------------------------------------------------------------------------------
1 | ../../../
--------------------------------------------------------------------------------
/example/post/server.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var ecstatic = require('ecstatic')(__dirname);
3 | var server = http.createServer(function (req, res) {
4 | if (req.method === 'POST' && req.url === '/plusone') {
5 | res.setHeader('content-type', 'text/plain');
6 |
7 | var s = '';
8 | req.on('data', function (buf) { s += buf.toString() });
9 |
10 | req.on('end', function () {
11 | var n = parseInt(s) + 1;
12 | res.end(n.toString());
13 | });
14 | }
15 | else ecstatic(req, res);
16 | });
17 |
18 | console.log('Listening on :8082');
19 | server.listen(8082);
20 |
--------------------------------------------------------------------------------
/example/streaming/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | xhr
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/streaming/main.js:
--------------------------------------------------------------------------------
1 | var http = require('../../');
2 |
3 | http.get({ path : '/doom' }, function (res) {
4 | var div = document.getElementById('result');
5 | if (!div.style) div.style = {};
6 | div.style.color = 'rgb(80,80,80)';
7 |
8 | res.on('data', function (buf) {
9 | div.innerHTML += buf;
10 | });
11 |
12 | res.on('end', function () {
13 | div.style.color = 'black';
14 | div.innerHTML += '!';
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/example/streaming/node_modules/http-browserify:
--------------------------------------------------------------------------------
1 | ../../../
--------------------------------------------------------------------------------
/example/streaming/server.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var ecstatic = require('ecstatic')(__dirname);
3 | var server = http.createServer(function (req, res) {
4 | if (req.url === '/doom') {
5 | res.setHeader('content-type', 'multipart/octet-stream');
6 |
7 | res.write('d');
8 | var i = 0;
9 | var iv = setInterval(function () {
10 | res.write('o');
11 | if (i++ >= 10) {
12 | clearInterval(iv);
13 | res.end('m');
14 | }
15 | }, 500);
16 | }
17 | else ecstatic(req, res);
18 | });
19 |
20 | console.log('Listening on :8082');
21 | server.listen(8082);
22 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var http = module.exports;
2 | var EventEmitter = require('events').EventEmitter;
3 | var Request = require('./lib/request');
4 | var url = require('url')
5 |
6 | http.request = function (params, cb) {
7 | if (typeof params === 'string') {
8 | params = url.parse(params)
9 | }
10 | if (!params) params = {};
11 | if (!params.host && !params.port) {
12 | params.port = parseInt(window.location.port, 10);
13 | }
14 | if (!params.host && params.hostname) {
15 | params.host = params.hostname;
16 | }
17 |
18 | if (!params.protocol) {
19 | if (params.scheme) {
20 | params.protocol = params.scheme + ':';
21 | } else {
22 | params.protocol = window.location.protocol;
23 | }
24 | }
25 |
26 | if (!params.host) {
27 | params.host = window.location.hostname || window.location.host;
28 | }
29 | if (/:/.test(params.host)) {
30 | if (!params.port) {
31 | params.port = params.host.split(':')[1];
32 | }
33 | params.host = params.host.split(':')[0];
34 | }
35 | if (!params.port) params.port = params.protocol == 'https:' ? 443 : 80;
36 |
37 | var req = new Request(new xhrHttp, params);
38 | if (cb) req.on('response', cb);
39 | return req;
40 | };
41 |
42 | http.get = function (params, cb) {
43 | params.method = 'GET';
44 | var req = http.request(params, cb);
45 | req.end();
46 | return req;
47 | };
48 |
49 | http.Agent = function () {};
50 | http.Agent.defaultMaxSockets = 4;
51 |
52 | var xhrHttp = (function () {
53 | if (typeof window === 'undefined') {
54 | throw new Error('no window object present');
55 | }
56 | else if (window.XMLHttpRequest) {
57 | return window.XMLHttpRequest;
58 | }
59 | else if (window.ActiveXObject) {
60 | var axs = [
61 | 'Msxml2.XMLHTTP.6.0',
62 | 'Msxml2.XMLHTTP.3.0',
63 | 'Microsoft.XMLHTTP'
64 | ];
65 | for (var i = 0; i < axs.length; i++) {
66 | try {
67 | var ax = new(window.ActiveXObject)(axs[i]);
68 | return function () {
69 | if (ax) {
70 | var ax_ = ax;
71 | ax = null;
72 | return ax_;
73 | }
74 | else {
75 | return new(window.ActiveXObject)(axs[i]);
76 | }
77 | };
78 | }
79 | catch (e) {}
80 | }
81 | throw new Error('ajax not supported in this browser')
82 | }
83 | else {
84 | throw new Error('ajax not supported in this browser');
85 | }
86 | })();
87 |
88 | http.STATUS_CODES = {
89 | 100 : 'Continue',
90 | 101 : 'Switching Protocols',
91 | 102 : 'Processing', // RFC 2518, obsoleted by RFC 4918
92 | 200 : 'OK',
93 | 201 : 'Created',
94 | 202 : 'Accepted',
95 | 203 : 'Non-Authoritative Information',
96 | 204 : 'No Content',
97 | 205 : 'Reset Content',
98 | 206 : 'Partial Content',
99 | 207 : 'Multi-Status', // RFC 4918
100 | 300 : 'Multiple Choices',
101 | 301 : 'Moved Permanently',
102 | 302 : 'Moved Temporarily',
103 | 303 : 'See Other',
104 | 304 : 'Not Modified',
105 | 305 : 'Use Proxy',
106 | 307 : 'Temporary Redirect',
107 | 400 : 'Bad Request',
108 | 401 : 'Unauthorized',
109 | 402 : 'Payment Required',
110 | 403 : 'Forbidden',
111 | 404 : 'Not Found',
112 | 405 : 'Method Not Allowed',
113 | 406 : 'Not Acceptable',
114 | 407 : 'Proxy Authentication Required',
115 | 408 : 'Request Time-out',
116 | 409 : 'Conflict',
117 | 410 : 'Gone',
118 | 411 : 'Length Required',
119 | 412 : 'Precondition Failed',
120 | 413 : 'Request Entity Too Large',
121 | 414 : 'Request-URI Too Large',
122 | 415 : 'Unsupported Media Type',
123 | 416 : 'Requested Range Not Satisfiable',
124 | 417 : 'Expectation Failed',
125 | 418 : 'I\'m a teapot', // RFC 2324
126 | 422 : 'Unprocessable Entity', // RFC 4918
127 | 423 : 'Locked', // RFC 4918
128 | 424 : 'Failed Dependency', // RFC 4918
129 | 425 : 'Unordered Collection', // RFC 4918
130 | 426 : 'Upgrade Required', // RFC 2817
131 | 428 : 'Precondition Required', // RFC 6585
132 | 429 : 'Too Many Requests', // RFC 6585
133 | 431 : 'Request Header Fields Too Large',// RFC 6585
134 | 500 : 'Internal Server Error',
135 | 501 : 'Not Implemented',
136 | 502 : 'Bad Gateway',
137 | 503 : 'Service Unavailable',
138 | 504 : 'Gateway Time-out',
139 | 505 : 'HTTP Version Not Supported',
140 | 506 : 'Variant Also Negotiates', // RFC 2295
141 | 507 : 'Insufficient Storage', // RFC 4918
142 | 509 : 'Bandwidth Limit Exceeded',
143 | 510 : 'Not Extended', // RFC 2774
144 | 511 : 'Network Authentication Required' // RFC 6585
145 | };
--------------------------------------------------------------------------------
/lib/request.js:
--------------------------------------------------------------------------------
1 | var Stream = require('stream');
2 | var Response = require('./response');
3 | var Base64 = require('Base64');
4 | var inherits = require('inherits');
5 |
6 | var Request = module.exports = function (xhr, params) {
7 | var self = this;
8 | self.writable = true;
9 | self.xhr = xhr;
10 | self.body = [];
11 |
12 | self.uri = (params.protocol || 'http:') + '//'
13 | + params.host
14 | + (params.port ? ':' + params.port : '')
15 | + (params.path || '/')
16 | ;
17 |
18 | if (typeof params.withCredentials === 'undefined') {
19 | params.withCredentials = true;
20 | }
21 |
22 | try { xhr.withCredentials = params.withCredentials }
23 | catch (e) {}
24 |
25 | if (params.responseType) try { xhr.responseType = params.responseType }
26 | catch (e) {}
27 |
28 | xhr.open(
29 | params.method || 'GET',
30 | self.uri,
31 | true
32 | );
33 |
34 | xhr.onerror = function(event) {
35 | self.emit('error', new Error('Network error'));
36 | };
37 |
38 | self._headers = {};
39 |
40 | if (params.headers) {
41 | var keys = objectKeys(params.headers);
42 | for (var i = 0; i < keys.length; i++) {
43 | var key = keys[i];
44 | if (!self.isSafeRequestHeader(key)) continue;
45 | var value = params.headers[key];
46 | self.setHeader(key, value);
47 | }
48 | }
49 |
50 | if (params.auth) {
51 | //basic auth
52 | this.setHeader('Authorization', 'Basic ' + Base64.btoa(params.auth));
53 | }
54 |
55 | var res = new Response;
56 | res.on('close', function () {
57 | self.emit('close');
58 | });
59 |
60 | res.on('ready', function () {
61 | self.emit('response', res);
62 | });
63 |
64 | res.on('error', function (err) {
65 | self.emit('error', err);
66 | });
67 |
68 | xhr.onreadystatechange = function () {
69 | // Fix for IE9 bug
70 | // SCRIPT575: Could not complete the operation due to error c00c023f
71 | // It happens when a request is aborted, calling the success callback anyway with readyState === 4
72 | if (xhr.__aborted) return;
73 | res.handle(xhr);
74 | };
75 | };
76 |
77 | inherits(Request, Stream);
78 |
79 | Request.prototype.setHeader = function (key, value) {
80 | this._headers[key.toLowerCase()] = value
81 | };
82 |
83 | Request.prototype.getHeader = function (key) {
84 | return this._headers[key.toLowerCase()]
85 | };
86 |
87 | Request.prototype.removeHeader = function (key) {
88 | delete this._headers[key.toLowerCase()]
89 | };
90 |
91 | Request.prototype.write = function (s) {
92 | this.body.push(s);
93 | };
94 |
95 | Request.prototype.destroy = function (s) {
96 | this.xhr.__aborted = true;
97 | this.xhr.abort();
98 | this.emit('close');
99 | };
100 |
101 | Request.prototype.end = function (s) {
102 | if (s !== undefined) this.body.push(s);
103 |
104 | var keys = objectKeys(this._headers);
105 | for (var i = 0; i < keys.length; i++) {
106 | var key = keys[i];
107 | var value = this._headers[key];
108 | if (isArray(value)) {
109 | for (var j = 0; j < value.length; j++) {
110 | this.xhr.setRequestHeader(key, value[j]);
111 | }
112 | }
113 | else this.xhr.setRequestHeader(key, value)
114 | }
115 |
116 | if (this.body.length === 0) {
117 | this.xhr.send('');
118 | }
119 | else if (typeof this.body[0] === 'string') {
120 | this.xhr.send(this.body.join(''));
121 | }
122 | else if (isArray(this.body[0])) {
123 | var body = [];
124 | for (var i = 0; i < this.body.length; i++) {
125 | body.push.apply(body, this.body[i]);
126 | }
127 | this.xhr.send(body);
128 | }
129 | else if (/Array/.test(Object.prototype.toString.call(this.body[0]))) {
130 | var len = 0;
131 | for (var i = 0; i < this.body.length; i++) {
132 | len += this.body[i].length;
133 | }
134 | var body = new(this.body[0].constructor)(len);
135 | var k = 0;
136 |
137 | for (var i = 0; i < this.body.length; i++) {
138 | var b = this.body[i];
139 | for (var j = 0; j < b.length; j++) {
140 | body[k++] = b[j];
141 | }
142 | }
143 | this.xhr.send(body);
144 | }
145 | else if (isXHR2Compatible(this.body[0])) {
146 | this.xhr.send(this.body[0]);
147 | }
148 | else {
149 | var body = '';
150 | for (var i = 0; i < this.body.length; i++) {
151 | body += this.body[i].toString();
152 | }
153 | this.xhr.send(body);
154 | }
155 | };
156 |
157 | // Taken from http://dxr.mozilla.org/mozilla/mozilla-central/content/base/src/nsXMLHttpRequest.cpp.html
158 | Request.unsafeHeaders = [
159 | "accept-charset",
160 | "accept-encoding",
161 | "access-control-request-headers",
162 | "access-control-request-method",
163 | "connection",
164 | "content-length",
165 | "cookie",
166 | "cookie2",
167 | "content-transfer-encoding",
168 | "date",
169 | "expect",
170 | "host",
171 | "keep-alive",
172 | "origin",
173 | "referer",
174 | "te",
175 | "trailer",
176 | "transfer-encoding",
177 | "upgrade",
178 | "user-agent",
179 | "via"
180 | ];
181 |
182 | Request.prototype.isSafeRequestHeader = function (headerName) {
183 | if (!headerName) return false;
184 | return indexOf(Request.unsafeHeaders, headerName.toLowerCase()) === -1;
185 | };
186 |
187 | var objectKeys = Object.keys || function (obj) {
188 | var keys = [];
189 | for (var key in obj) keys.push(key);
190 | return keys;
191 | };
192 |
193 | var isArray = Array.isArray || function (xs) {
194 | return Object.prototype.toString.call(xs) === '[object Array]';
195 | };
196 |
197 | var indexOf = function (xs, x) {
198 | if (xs.indexOf) return xs.indexOf(x);
199 | for (var i = 0; i < xs.length; i++) {
200 | if (xs[i] === x) return i;
201 | }
202 | return -1;
203 | };
204 |
205 | var isXHR2Compatible = function (obj) {
206 | if (typeof Blob !== 'undefined' && obj instanceof Blob) return true;
207 | if (typeof ArrayBuffer !== 'undefined' && obj instanceof ArrayBuffer) return true;
208 | if (typeof FormData !== 'undefined' && obj instanceof FormData) return true;
209 | };
210 |
--------------------------------------------------------------------------------
/lib/response.js:
--------------------------------------------------------------------------------
1 | var Stream = require('stream');
2 | var util = require('util');
3 |
4 | var Response = module.exports = function (res) {
5 | this.offset = 0;
6 | this.readable = true;
7 | };
8 |
9 | util.inherits(Response, Stream);
10 |
11 | var capable = {
12 | streaming : true,
13 | status2 : true
14 | };
15 |
16 | function parseHeaders (res) {
17 | var lines = res.getAllResponseHeaders().split(/\r?\n/);
18 | var headers = {};
19 | for (var i = 0; i < lines.length; i++) {
20 | var line = lines[i];
21 | if (line === '') continue;
22 |
23 | var m = line.match(/^([^:]+):\s*(.*)/);
24 | if (m) {
25 | var key = m[1].toLowerCase(), value = m[2];
26 |
27 | if (headers[key] !== undefined) {
28 |
29 | if (isArray(headers[key])) {
30 | headers[key].push(value);
31 | }
32 | else {
33 | headers[key] = [ headers[key], value ];
34 | }
35 | }
36 | else {
37 | headers[key] = value;
38 | }
39 | }
40 | else {
41 | headers[line] = true;
42 | }
43 | }
44 | return headers;
45 | }
46 |
47 | Response.prototype.getResponse = function (xhr) {
48 | var respType = String(xhr.responseType).toLowerCase();
49 | if (respType === 'blob') return xhr.responseBlob || xhr.response;
50 | if (respType === 'arraybuffer') return xhr.response;
51 | return xhr.responseText;
52 | }
53 |
54 | Response.prototype.getHeader = function (key) {
55 | return this.headers[key.toLowerCase()];
56 | };
57 |
58 | Response.prototype.handle = function (res) {
59 | if (res.readyState === 2 && capable.status2) {
60 | try {
61 | this.statusCode = res.status;
62 | this.headers = parseHeaders(res);
63 | }
64 | catch (err) {
65 | capable.status2 = false;
66 | }
67 |
68 | if (capable.status2) {
69 | this.emit('ready');
70 | }
71 | }
72 | else if (capable.streaming && res.readyState === 3) {
73 | try {
74 | if (!this.statusCode) {
75 | this.statusCode = res.status;
76 | this.headers = parseHeaders(res);
77 | this.emit('ready');
78 | }
79 | }
80 | catch (err) {}
81 |
82 | try {
83 | this._emitData(res);
84 | }
85 | catch (err) {
86 | capable.streaming = false;
87 | }
88 | }
89 | else if (res.readyState === 4) {
90 | if (!this.statusCode) {
91 | this.statusCode = res.status;
92 | this.emit('ready');
93 | }
94 | this._emitData(res);
95 |
96 | if (res.error) {
97 | this.emit('error', this.getResponse(res));
98 | }
99 | else this.emit('end');
100 |
101 | this.emit('close');
102 | }
103 | };
104 |
105 | Response.prototype._emitData = function (res) {
106 | var respBody = this.getResponse(res);
107 | if (respBody.toString().match(/ArrayBuffer/)) {
108 | this.emit('data', new Uint8Array(respBody, this.offset));
109 | this.offset = respBody.byteLength;
110 | return;
111 | }
112 | if (respBody.length > this.offset) {
113 | this.emit('data', respBody.slice(this.offset));
114 | this.offset = respBody.length;
115 | }
116 | };
117 |
118 | var isArray = Array.isArray || function (xs) {
119 | return Object.prototype.toString.call(xs) === '[object Array]';
120 | };
121 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "http-browserify",
3 | "version": "1.7.0",
4 | "description": "http module compatability for browserify",
5 | "main": "index.js",
6 | "browserify": "index.js",
7 | "directories": {
8 | "lib": ".",
9 | "example": "example",
10 | "test": "test"
11 | },
12 | "scripts": {
13 | "test": "tape test/*.js"
14 | },
15 | "dependencies": {
16 | "Base64": "~0.2.0",
17 | "inherits": "~2.0.1"
18 | },
19 | "devDependencies": {
20 | "ecstatic": "~0.1.6",
21 | "tape": "~2.3.2"
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "http://github.com/substack/http-browserify.git"
26 | },
27 | "keywords": [
28 | "http",
29 | "browserify",
30 | "compatible",
31 | "meatless",
32 | "browser"
33 | ],
34 | "author": {
35 | "name": "James Halliday",
36 | "email": "mail@substack.net",
37 | "url": "http://substack.net"
38 | },
39 | "license": "MIT/X11"
40 | }
41 |
--------------------------------------------------------------------------------
/readme.markdown:
--------------------------------------------------------------------------------
1 | # http-browserify
2 |
3 | The
4 | [http](http://nodejs.org/docs/v0.4.10/api/all.html#hTTP) module from node.js,
5 | but for browsers.
6 |
7 | When you `require('http')` in
8 | [browserify](http://github.com/substack/node-browserify),
9 | this module will be loaded.
10 |
11 | # example
12 |
13 | ``` js
14 | var http = require('http');
15 |
16 | http.get({ path : '/beep' }, function (res) {
17 | var div = document.getElementById('result');
18 | div.innerHTML += 'GET /beep
';
19 |
20 | res.on('data', function (buf) {
21 | div.innerHTML += buf;
22 | });
23 |
24 | res.on('end', function () {
25 | div.innerHTML += '
__END__';
26 | });
27 | });
28 | ```
29 |
30 | # http methods
31 |
32 | var http = require('http');
33 |
34 | ## var req = http.request(opts, cb)
35 |
36 | where `opts` are:
37 |
38 | * `opts.method='GET'` - http method verb
39 | * `opts.path` - path string, example: `'/foo/bar?baz=555'`
40 | * `opts.headers={}` - as an object mapping key names to string or Array values
41 | * `opts.host=window.location.host` - http host
42 | * `opts.port=window.location.port` - http port
43 | * `opts.responseType` - response type to set on the underlying xhr object
44 |
45 | The callback will be called with the response object.
46 |
47 | ## var req = http.get(options, cb)
48 |
49 | A shortcut for
50 |
51 | ``` js
52 | options.method = 'GET';
53 | var req = http.request(options, cb);
54 | req.end();
55 | ```
56 |
57 | # request methods
58 |
59 | ## req.setHeader(key, value)
60 |
61 | Set an http header.
62 |
63 | ## req.getHeader(key)
64 |
65 | Get an http header.
66 |
67 | ## req.removeHeader(key)
68 |
69 | Remove an http header.
70 |
71 | ## req.write(data)
72 |
73 | Write some data to the request body.
74 |
75 | If only 1 piece of data is written, `data` can be a FormData, Blob, or
76 | ArrayBuffer instance. Otherwise, `data` should be a string or a buffer.
77 |
78 | ## req.end(data)
79 |
80 | Close and send the request body, optionally with additional `data` to append.
81 |
82 | # response methods
83 |
84 | ## res.getHeader(key)
85 |
86 | Return an http header, if set. `key` is case-insensitive.
87 |
88 | # response attributes
89 |
90 | * res.statusCode, the numeric http response code
91 | * res.headers, an object with all lowercase keys
92 |
93 | # compatibility
94 |
95 | This module has been tested and works with:
96 |
97 | * Internet Explorer 5.5, 6, 7, 8, 9
98 | * Firefox 3.5
99 | * Chrome 7.0
100 | * Opera 10.6
101 | * Safari 5.0
102 |
103 | Multipart streaming responses are buffered in all versions of Internet Explorer
104 | and are somewhat buffered in Opera. In all the other browsers you get a nice
105 | unbuffered stream of `"data"` events when you send down a content-type of
106 | `multipart/octet-stream` or similar.
107 |
108 | # protip
109 |
110 | You can do:
111 |
112 | ````javascript
113 | var bundle = browserify({
114 | require : { http : 'http-browserify' }
115 | });
116 | ````
117 |
118 | in order to map "http-browserify" over `require('http')` in your browserified
119 | source.
120 |
121 | # install
122 |
123 | With [npm](https://npmjs.org) do:
124 |
125 | ```
126 | npm install http-browserify
127 | ```
128 |
129 | # license
130 |
131 | MIT
132 |
--------------------------------------------------------------------------------
/test/request_url.js:
--------------------------------------------------------------------------------
1 | global.window = global;
2 | global.location = {
3 | host: 'localhost:8081',
4 | port: 8081,
5 | protocol: 'http:'
6 | };
7 |
8 | var noop = function() {};
9 | global.XMLHttpRequest = function() {
10 | this.open = noop;
11 | this.send = noop;
12 | };
13 |
14 | global.FormData = function () {};
15 | global.Blob = function () {};
16 | global.ArrayBuffer = function () {};
17 |
18 | var test = require('tape').test;
19 | var http = require('../index.js');
20 |
21 |
22 | test('Test simple url string', function(t) {
23 | var url = { path: '/api/foo' };
24 | var request = http.get(url, noop);
25 |
26 | t.equal( request.uri, 'http://localhost:8081/api/foo', 'Url should be correct');
27 | t.end();
28 |
29 | });
30 |
31 |
32 | test('Test full url object', function(t) {
33 | var url = {
34 | host: "localhost:8081",
35 | hostname: "localhost",
36 | href: "http://localhost:8081/api/foo?bar=baz",
37 | method: "GET",
38 | path: "/api/foo?bar=baz",
39 | pathname: "/api/foo",
40 | port: "8081",
41 | protocol: "http:",
42 | query: "bar=baz",
43 | search: "?bar=baz",
44 | slashes: true
45 | };
46 |
47 | var request = http.get(url, noop);
48 |
49 | t.equal( request.uri, 'http://localhost:8081/api/foo?bar=baz', 'Url should be correct');
50 | t.end();
51 |
52 | });
53 |
54 | test('Test alt protocol', function(t) {
55 | var params = {
56 | protocol: "foo:",
57 | hostname: "localhost",
58 | port: "3000",
59 | path: "/bar"
60 | };
61 |
62 | var request = http.get(params, noop);
63 |
64 | t.equal( request.uri, 'foo://localhost:3000/bar', 'Url should be correct');
65 | t.end();
66 |
67 | });
68 |
69 | test('Test string as parameters', function(t) {
70 | var url = '/api/foo';
71 | var request = http.get(url, noop);
72 |
73 | t.equal( request.uri, 'http://localhost:8081/api/foo', 'Url should be correct');
74 | t.end();
75 |
76 | });
77 |
78 | test('Test withCredentials param', function(t) {
79 | var url = '/api/foo';
80 |
81 | var request = http.request({ url: url, withCredentials: false }, noop);
82 | t.equal( request.xhr.withCredentials, false, 'xhr.withCredentials should be false');
83 |
84 | var request = http.request({ url: url, withCredentials: true }, noop);
85 | t.equal( request.xhr.withCredentials, true, 'xhr.withCredentials should be true');
86 |
87 | var request = http.request({ url: url }, noop);
88 | t.equal( request.xhr.withCredentials, true, 'xhr.withCredentials should be true');
89 |
90 | t.end();
91 | });
92 |
93 | test('Test POST XHR2 types', function(t) {
94 | t.plan(3);
95 | var url = '/api/foo';
96 |
97 | var request = http.request({ url: url, method: 'POST' }, noop);
98 | request.xhr.send = function (data) {
99 | t.ok(data instanceof global.ArrayBuffer, 'data should be instanceof ArrayBuffer');
100 | };
101 | request.end(new global.ArrayBuffer());
102 |
103 | request = http.request({ url: url, method: 'POST' }, noop);
104 | request.xhr.send = function (data) {
105 | t.ok(data instanceof global.Blob, 'data should be instanceof Blob');
106 | };
107 | request.end(new global.Blob());
108 |
109 | request = http.request({ url: url, method: 'POST' }, noop);
110 | request.xhr.send = function (data) {
111 | t.ok(data instanceof global.FormData, 'data should be instanceof FormData');
112 | };
113 | request.end(new global.FormData());
114 | });
115 |
--------------------------------------------------------------------------------