Permalink
Browse files

Cleanup http-client module, remove HttpClient, add support for follow…

…ing redirects (on by default)
  • Loading branch information...
1 parent d6d9bde commit 0d12310bb60cc8a523d9eee36db95311c8838452 Tom Robinson committed Nov 3, 2010
@@ -1,2 +0,0 @@
-require("narwhal").deprecated("use http-client-engine instead of http-engine");
-require("narwhal/util").update(exports. require("http-client-engine"));
@@ -1,99 +1,80 @@
-// -- isaacs Isaac Schlueter
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
+// -- tlrobinson Tom Robinson
-var IO = require("io").IO,
- UTIL = require("narwhal/util");
+var IO = require("io").IO;
-exports.IO = function (url) {
- return new IO(
- new java.net.URL(url).openStream(),
- null
- );
-};
+exports.open = function(url, mode, options) {
+ var connection, output, input;
-exports.connect = function HttpClient_engine_connect (tx) {
- if (tx._isConnected) return;
-
- var con = java.net.HttpURLConnection(new java.net.URL(tx.url).openConnection());
- con.setRequestMethod(tx.method.toUpperCase());
-
- UTIL.forEach(tx.headers, function (h, v) {
- con.setRequestProperty(h, v);
- });
- if (!tx.headers) tx.headers = {};
- var cl = UTIL.get(tx.headers, "Content-Length") || 0;
- if (cl > 0) {
- con.setDoOutput(true);
- var os = null;
- try {
- os = con.getOutputStream();
- } catch (ex) {}
- if (os) {
- var writer = new IO(null, con.getOutputStream());
- tx.body.forEach(function (piece) {
- writer.write(piece);
- });
- writer.close();
- }
- }
-
- try {
- con.connect();
- } catch (ex) {
- // It would be nice to do something clever and special here,
- // but I'm not feeling it at the moment.
- ex.message = [
- "Could not connect to "+tx.url+". Probably a bad hostname.",
- ex.message
- ].join("\n");
- throw ex;
- }
-
- tx._isConnected = true;
- var resp = tx._response = {status:200, headers:{}, body:[]};
-
- // Call this now to trigger the fetch asynchronously.
- // This way, if you set up multiple HttpClients, and then call connect()
- // on all of them, you'll only wait as long as the slowest one, since
- // the streams will start filling up right away.
-
-
- // now pull everything out.
- var fields = con.getHeaderFields();
- var fieldKeys = fields.keySet().toArray();
- for (var i = 0, l = fieldKeys.length; i < l; i ++ ) {
- var fieldValue = fields.get(fieldKeys[i]).toArray().join('');
- var fieldName = fieldKeys[i];
- if (fieldName === null) {
- // Something like: HTTP/1.1 200 OK
- UTIL.set(resp, "status", +(/HTTP\/1\.[01] ([0-9]{3})/.exec(fieldValue)[1]));
- // fieldName = "Status";
- resp.statusText = fieldValue;
- continue;
+ function startRequest() {
+ connection = new java.net.URL(url).openConnection();
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+ connection.setRequestMethod(options.method);
+ connection.setInstanceFollowRedirects(!!options.followRedirects);
+
+ for (var name in options.headers) {
+ if (options.headers.hasOwnProperty(name)) {
+ connection.addRequestProperty(String(name), String(options.headers[name]));
+ }
}
- UTIL.set(resp.headers, fieldName, fieldValue);
+
+ connection.connect();
+
+ output = new IO(null, connection.getOutputStream());
+ input = null;
}
- // TODO: Restructure using non-blocking IO to support asynchronous interactions.
- // In that case, you could just have a callback that gets each bytestring.
- var is = null;
- try {
- var is = con.getInputStream();
- } catch (ex) {
- return resp;
+ startRequest();
+
+ var request = {
+ status : null,
+ headers : {},
+ read : function() {
+ if (!input) {
+ output.close();
+ input = new IO(connection.getInputStream(), null);
+ this.status = Number(connection.getResponseCode());
+ this.statusText = String(connection.getResponseMessage() || "");
+ for (var i = 0; ; i++) {
+ var key = connection.getHeaderFieldKey(i), value = connection.getHeaderField(i);
+ if (!key && !value) {
+ break;
+ }
+ if (key) {
+ key = String(key);
+ value = String(value);
+ this.headers[key] = value;
+ if (key.toUpperCase() === "LOCATION")
+ url = value;
+ }
+ }
+
+ // Manually follow cross-protocol redirects because Java doesn't:
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4620571
+ if (options.followRedirects && this.status >= 300 && this.status < 400) {
+ // TODO: should we change the method to GET if it was not a GET like curl does?
+ startRequest();
+ return this.read.apply(this, arguments);
+ }
+ }
+ return input.read.apply(input, arguments);
+ },
+ write : function() {
+ output.write.apply(output, arguments);
+ return this;
+ },
+ flush : function() {
+ output.flush.apply(output, arguments);
+ return this;
+ },
+ close : function() {
+ output && output.close();
+ input && input.close();
+ return this;
+ },
+ copy : IO.prototype.copy
}
-
- // TODO: Should the input stream be rewindable?
- var reader = new IO(con.getInputStream(), null);
- resp.body = {forEach : function (block) {
- var buflen = 1024;
- for (
- var bytes = reader.read(buflen);
- bytes.length > 0;
- bytes = reader.read(buflen)
- ) block(bytes);
- }};
-
- return resp;
+ return request;
};
@@ -1,12 +0,0 @@
-
-// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
-
-var IO = require('./io').IO;
-
-exports.IO = function (url) {
- return new IO(
- new java.net.URL(url).openStream(),
- null
- );
-};
-
View
@@ -1,79 +0,0 @@
-
-// -- tlrobinson Tom Robinson
-
-var FILE = require("file");
-var IO = require("io").IO;
-
-exports.open = function(url, mode, options) {
- mode = mode || "b";
- options = options || {};
-
- options.method = options.method || "GET";
- options.headers = options.headers || {};
-
- var connection = new java.net.URL(url).openConnection();
- connection.setDoInput(true);
- connection.setDoOutput(true);
- connection.setRequestMethod(options.method);
-
- for (var name in options.headers){
- connection.addRequestProperty(String(name), String(options.headers[name]));
- }
-
- connection.connect();
-
- var output = new IO(null, connection.getOutputStream());
- var input = null;
-
- var request = {
- status : null,
- headers : {},
- read : function() {
- if (!input) {
- output.close();
- input = new IO(connection.getInputStream(), null);
- this.status = Number(connection.getResponseCode());
- this.statusText = String(connection.getResponseMessage() || "");
- for (var i = 0; ; i++) {
- var key = connection.getHeaderFieldKey(i), value = connection.getHeaderField(i);
- if (! key && ! value)
- break;
- if (key)
- this.headers[String(key)] = String(value);
- }
- }
- return input.read.apply(input, arguments);
- },
- write : function() {
- output.write.apply(output, arguments);
- return this;
- },
- flush : function() {
- output.flush.apply(output, arguments);
- return this;
- },
- close : function() {
- if (output)
- output.close();
- if (input)
- input.close();
- return this;
- },
- copy : IO.prototype.copy
- }
- return request;
-};
-
-exports.read = function(url) {
- var stream = exports.open(url);
- try {
- return stream.read();
- } finally {
- stream.close();
- }
-};
-
-exports.copy = function(source, target, mode) {
- mode = mode || "b";
- return FILE.path(target).write(exports.read(source, mode), mode);
-};
Oops, something went wrong.

0 comments on commit 0d12310

Please sign in to comment.