Skip to content

Commit

Permalink
Cleanup http-client module, remove HttpClient, add support for follow…
Browse files Browse the repository at this point in the history
…ing redirects (on by default)
  • Loading branch information
Tom Robinson committed Nov 3, 2010
1 parent d6d9bde commit 0d12310
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 330 deletions.
2 changes: 0 additions & 2 deletions engines/default/lib/http-engine.js

This file was deleted.

159 changes: 70 additions & 89 deletions engines/rhino/lib/http-client-engine.js
@@ -1,99 +1,80 @@


// -- isaacs Isaac Schlueter
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
// -- tlrobinson Tom Robinson


var IO = require("io").IO, var IO = require("io").IO;
UTIL = require("narwhal/util");


exports.IO = function (url) { exports.open = function(url, mode, options) {
return new IO( var connection, output, input;
new java.net.URL(url).openStream(),
null
);
};


exports.connect = function HttpClient_engine_connect (tx) { function startRequest() {
if (tx._isConnected) return; connection = new java.net.URL(url).openConnection();

connection.setDoInput(true);
var con = java.net.HttpURLConnection(new java.net.URL(tx.url).openConnection()); connection.setDoOutput(true);
con.setRequestMethod(tx.method.toUpperCase()); connection.setRequestMethod(options.method);

connection.setInstanceFollowRedirects(!!options.followRedirects);
UTIL.forEach(tx.headers, function (h, v) {
con.setRequestProperty(h, v); for (var name in options.headers) {
}); if (options.headers.hasOwnProperty(name)) {
if (!tx.headers) tx.headers = {}; connection.addRequestProperty(String(name), String(options.headers[name]));
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;
} }
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. startRequest();
// In that case, you could just have a callback that gets each bytestring.
var is = null; var request = {
try { status : null,
var is = con.getInputStream(); headers : {},
} catch (ex) { read : function() {
return resp; 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
} }

return request;
// 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;
}; };
12 changes: 0 additions & 12 deletions engines/rhino/lib/http-engine.js

This file was deleted.

79 changes: 0 additions & 79 deletions engines/rhino/lib/http.js

This file was deleted.

0 comments on commit 0d12310

Please sign in to comment.