Work on net2 http client
authorRyan Dahl <ry@tinyclouds.org>
Sat, 13 Mar 2010 02:39:02 +0000 (18:39 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Sat, 13 Mar 2010 02:39:02 +0000 (18:39 -0800)
lib/http2.js
lib/net.js
test/simple/test-http-1.0.js
test/simple/test-http-cat.js

index 8b26a3f1b610636ac9d218ae8857bd0d16462955..c040dd229501bf64cb064d4c86bc3ad8991cbc5c 100644 (file)
@@ -447,3 +447,192 @@ exports.createServer = function (requestListener, options) {
 };
 
 
+
+function Client () {
+  net.Socket.call(this);
+
+  var self = this;
+  var requests = [];
+  var currentRequest;
+
+  var parser = newParser('response');
+  parser.socket = self;
+
+  self.addListener("connect", function () {
+    self.resetParser();
+    currentRequest = requests.shift();
+    currentRequest.flush();
+  });
+
+  self.ondata = function (d, start, end) {
+    parser.execute(d, start, end - start);
+  };
+
+  parser.onIncoming = function (res) {
+    //sys.debug("incoming response!");
+
+    res.addListener('end', function ( ) {
+      //sys.debug("request complete disconnecting. readyState = " + self.readyState);
+      self.close();
+    });
+
+    currentRequest.emit("response", res);
+  };
+
+  self._pushRequest = function (req) {
+  };
+
+  self.addListener("end", function () {
+    self.close();
+  });
+
+  self.onend = function () {
+    parser.finish();
+    // unref the parser for easy gc
+    freeParser(parser);
+    //sys.debug("self got end closing. readyState = " + self.readyState);
+    self.close();
+  };
+
+  self.addListener("close", function (had_error) {
+    if (had_error) {
+      self.emit("error");
+      return;
+    }
+
+    //sys.debug("HTTP CLIENT onClose. readyState = " + self.readyState);
+
+    // If there are more requests to handle, reconnect.
+    if (requests.length > 0) {
+      self._reconnect();
+    }
+  });
+}
+sys.inherits(Client, net.Socket);
+
+
+exports.Client = Client;
+
+
+exports.createClient = function (port, host) {
+  var client = new Client();
+  client.port = port;
+  client.host = host;
+  client.connect(port, host);
+  return client;
+};
+
+
+Client.prototype._reconnect = function () {
+  if (this.readyState != "opening") {
+    //sys.debug("HTTP CLIENT: reconnecting readyState = " + self.readyState);
+    this.connect(this.port, this.host);
+  }
+};
+
+
+Client.prototype.request = function (method, url, headers) {
+  var self = this;
+
+  if (typeof(url) != "string") { // assume method was omitted, shift arguments
+    headers = url;
+    url = method;
+    method = null;
+  }
+  var req = new ClientRequest(this, method || "GET", url, headers);
+
+  req.addListener("flush", function () {
+    if (self.readyState == "closed") {
+      //sys.debug("HTTP CLIENT request flush. reconnect.  readyState = " + self.readyState);
+      self._reconnect();
+      return;
+    }
+    //sys.debug("self flush  readyState = " + self.readyState);
+    if (req == currentRequest) flushMessageQueue(self, [req]);
+  });
+  requests.push(req);
+
+  return req;
+};
+
+Client.prototype.get = function () {
+  throw new Error("client.get(...) is now client.request('GET', ...)");
+};
+
+Client.prototype.head = function () {
+  throw new Error("client.head(...) is now client.request('HEAD', ...)");
+};
+
+Client.prototype.post = function () {
+  throw new Error("client.post(...) is now client.request('POST', ...)");
+};
+
+Client.prototype.del = function () {
+  throw new Error("client.del(...) is now client.request('DELETE', ...)");
+};
+
+Client.prototype.put = function () {
+  throw new Error("client.put(...) is now client.request('PUT', ...)");
+};
+
+
+exports.cat = function (url, encoding_, headers_) {
+  var encoding = 'utf8', 
+      headers = {},
+      callback = null;
+
+  // parse the arguments for the various options... very ugly
+  if (typeof(arguments[1]) == 'string') {
+    encoding = arguments[1];
+    if (typeof(arguments[2]) == 'object') {
+      headers = arguments[2];
+      if (typeof(arguments[3]) == 'function') callback = arguments[3];
+    } else {
+      if (typeof(arguments[2]) == 'function') callback = arguments[2];
+    }
+  } else {
+    // didn't specify encoding
+    if (typeof(arguments[1]) == 'object') {
+      headers = arguments[1];
+      callback = arguments[2];
+    } else {
+      callback = arguments[1];
+    }
+  }
+
+  var url = require("url").parse(url);
+  
+  var hasHost = false;
+  for (var i in headers) {
+    if (i.toLowerCase() === "host") {
+      hasHost = true;
+      break;
+    }
+  }
+  if (!hasHost) headers["Host"] = url.hostname;
+
+  var content = "";
+  
+  var client = exports.createClient(url.port || 80, url.hostname);
+  var req = client.request((url.pathname || "/")+(url.search || "")+(url.hash || ""), headers);
+
+  req.addListener('response', function (res) {
+    if (res.statusCode < 200 || res.statusCode >= 300) {
+      if (callback) callback(res.statusCode);
+      client.close();
+      return;
+    }
+    res.setBodyEncoding(encoding);
+    res.addListener('data', function (chunk) { content += chunk; });
+    res.addListener('end', function () {
+      if (callback) callback(null, content);
+    });
+  });
+
+  client.addListener("error", function (err) {
+    // todo an error should actually be passed here...
+    if (callback) callback(new Error('Connection error'));
+  });
+
+  req.close();
+};
index 1b2b348ee2a4e16f226ace29dc6bb9ae1e69ed94..fe5fa0d85cf6977056e78899416758ae22a8c700 100644 (file)
@@ -632,19 +632,16 @@ function doConnect (socket, port, host) {
 // stream.connect(80, 'nodejs.org') - TCP connect to port 80 on nodejs.org
 // stream.connect('/tmp/socket')    - UNIX connect to socket specified by path
 Socket.prototype.connect = function () {
-  initSocket(this);
-
   var self = this;
+  initSocket(self);
   if (self.fd) throw new Error('Socket already opened');
+  if (!self._readWatcher) throw new Error('No readWatcher');
   
   timeout.active(socket);
 
-  if (typeof(arguments[0]) == 'string') {
-    self.fd = socket('unix');
-    self.type = 'unix';
-    // TODO check if sockfile exists?
-    doConnect(self, arguments[0]);
-  } else {
+  var port = parseInt(arguments[0]);
+
+  if (port >= 0) {
     self.fd = socket('tcp');
     debug('new fd = ' + self.fd);
     self.type = 'tcp';
@@ -653,6 +650,11 @@ Socket.prototype.connect = function () {
     lookupDomainName(arguments[1], function (ip) {
       doConnect(self, port, ip);
     });
+  } else {
+    self.fd = socket('unix');
+    self.type = 'unix';
+    // TODO check if sockfile exists?
+    doConnect(self, arguments[0]);
   }
 };
 
index ceca527719f883434a13268cea29a98f51348908..b3f69c23cfeddb4133d411c4e1290a17ac77d6a9 100644 (file)
@@ -1,6 +1,6 @@
 require("../common");
 tcp = require("tcp");
-http = require("http");
+http = require("http2");
 
 var body = "hello world\n";
 var server_response = "";
index e81a5c502fe531ca89efbf7f84ae4c8c49ab2459..32177ee92b8c244a079f0c0ef05300c2973eb41e 100644 (file)
@@ -1,5 +1,5 @@
 require("../common");
-http = require("http");
+http = require("http2");
 
 var body = "exports.A = function() { return 'A';}";
 var server = http.createServer(function (req, res) {