├── 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 | --------------------------------------------------------------------------------