Merge remote-tracking branch 'upstream/v0.10'
authorTimothy J Fontaine <tjfontaine@gmail.com>
Fri, 12 Jul 2013 20:26:56 +0000 (13:26 -0700)
committerTimothy J Fontaine <tjfontaine@gmail.com>
Fri, 12 Jul 2013 20:26:56 +0000 (13:26 -0700)
Conflicts:
AUTHORS
ChangeLog
deps/npm/Makefile
deps/npm/doc/api/npm-commands.md
deps/npm/doc/api/npm-deprecate.md
deps/npm/doc/api/npm-init.md
deps/npm/doc/api/npm-owner.md
deps/npm/doc/api/npm-publish.md
deps/npm/doc/api/npm-run-script.md
deps/npm/doc/cli/npm-adduser.md
deps/npm/doc/cli/npm-bin.md
deps/npm/doc/cli/npm-bugs.md
deps/npm/doc/cli/npm-build.md
deps/npm/doc/cli/npm-cache.md
deps/npm/doc/cli/npm-completion.md
deps/npm/doc/cli/npm-deprecate.md
deps/npm/doc/cli/npm-docs.md
deps/npm/doc/cli/npm-edit.md
deps/npm/doc/cli/npm-explore.md
deps/npm/doc/cli/npm-help-search.md
deps/npm/doc/cli/npm-help.md
deps/npm/doc/cli/npm-init.md
deps/npm/doc/cli/npm-install.md
deps/npm/doc/cli/npm-link.md
deps/npm/doc/cli/npm-ls.md
deps/npm/doc/cli/npm-outdated.md
deps/npm/doc/cli/npm-owner.md
deps/npm/doc/cli/npm-pack.md
deps/npm/doc/cli/npm-prefix.md
deps/npm/doc/cli/npm-prune.md
deps/npm/doc/cli/npm-publish.md
deps/npm/doc/cli/npm-restart.md
deps/npm/doc/cli/npm-rm.md
deps/npm/doc/cli/npm-root.md
deps/npm/doc/cli/npm-run-script.md
deps/npm/doc/cli/npm-search.md
deps/npm/doc/cli/npm-shrinkwrap.md
deps/npm/doc/cli/npm-start.md
deps/npm/doc/cli/npm-stop.md
deps/npm/doc/cli/npm-submodule.md
deps/npm/doc/cli/npm-tag.md
deps/npm/doc/cli/npm-test.md
deps/npm/doc/cli/npm-uninstall.md
deps/npm/doc/cli/npm-unpublish.md
deps/npm/doc/cli/npm-update.md
deps/npm/doc/cli/npm-version.md
deps/npm/doc/cli/npm-view.md
deps/npm/doc/cli/npm-whoami.md
deps/npm/doc/files/npm-folders.md
deps/npm/doc/files/package.json.md
deps/npm/doc/misc/npm-coding-style.md
deps/npm/doc/misc/npm-config.md
deps/npm/doc/misc/npm-developers.md
deps/npm/doc/misc/npm-disputes.md
deps/npm/doc/misc/npm-faq.md
deps/npm/doc/misc/npm-registry.md
deps/npm/doc/misc/npm-scripts.md
deps/npm/doc/misc/semver.md
deps/npm/html/doc/README.html
deps/npm/html/doc/api/npm-bin.html
deps/npm/html/doc/api/npm-bugs.html
deps/npm/html/doc/api/npm-commands.html
deps/npm/html/doc/api/npm-config.html
deps/npm/html/doc/api/npm-deprecate.html
deps/npm/html/doc/api/npm-docs.html
deps/npm/html/doc/api/npm-edit.html
deps/npm/html/doc/api/npm-explore.html
deps/npm/html/doc/api/npm-help-search.html
deps/npm/html/doc/api/npm-init.html
deps/npm/html/doc/api/npm-install.html
deps/npm/html/doc/api/npm-link.html
deps/npm/html/doc/api/npm-load.html
deps/npm/html/doc/api/npm-ls.html
deps/npm/html/doc/api/npm-outdated.html
deps/npm/html/doc/api/npm-owner.html
deps/npm/html/doc/api/npm-pack.html
deps/npm/html/doc/api/npm-prefix.html
deps/npm/html/doc/api/npm-prune.html
deps/npm/html/doc/api/npm-publish.html
deps/npm/html/doc/api/npm-rebuild.html
deps/npm/html/doc/api/npm-restart.html
deps/npm/html/doc/api/npm-root.html
deps/npm/html/doc/api/npm-run-script.html
deps/npm/html/doc/api/npm-search.html
deps/npm/html/doc/api/npm-shrinkwrap.html
deps/npm/html/doc/api/npm-start.html
deps/npm/html/doc/api/npm-stop.html
deps/npm/html/doc/api/npm-submodule.html
deps/npm/html/doc/api/npm-tag.html
deps/npm/html/doc/api/npm-test.html
deps/npm/html/doc/api/npm-uninstall.html
deps/npm/html/doc/api/npm-unpublish.html
deps/npm/html/doc/api/npm-update.html
deps/npm/html/doc/api/npm-version.html
deps/npm/html/doc/api/npm-view.html
deps/npm/html/doc/api/npm-whoami.html
deps/npm/html/doc/api/npm.html
deps/npm/html/doc/cli/npm-adduser.html
deps/npm/html/doc/cli/npm-bin.html
deps/npm/html/doc/cli/npm-bugs.html
deps/npm/html/doc/cli/npm-build.html
deps/npm/html/doc/cli/npm-bundle.html
deps/npm/html/doc/cli/npm-cache.html
deps/npm/html/doc/cli/npm-completion.html
deps/npm/html/doc/cli/npm-config.html
deps/npm/html/doc/cli/npm-dedupe.html
deps/npm/html/doc/cli/npm-deprecate.html
deps/npm/html/doc/cli/npm-docs.html
deps/npm/html/doc/cli/npm-edit.html
deps/npm/html/doc/cli/npm-explore.html
deps/npm/html/doc/cli/npm-help-search.html
deps/npm/html/doc/cli/npm-help.html
deps/npm/html/doc/cli/npm-init.html
deps/npm/html/doc/cli/npm-install.html
deps/npm/html/doc/cli/npm-link.html
deps/npm/html/doc/cli/npm-ls.html
deps/npm/html/doc/cli/npm-outdated.html
deps/npm/html/doc/cli/npm-owner.html
deps/npm/html/doc/cli/npm-pack.html
deps/npm/html/doc/cli/npm-prefix.html
deps/npm/html/doc/cli/npm-prune.html
deps/npm/html/doc/cli/npm-publish.html
deps/npm/html/doc/cli/npm-rebuild.html
deps/npm/html/doc/cli/npm-restart.html
deps/npm/html/doc/cli/npm-rm.html
deps/npm/html/doc/cli/npm-root.html
deps/npm/html/doc/cli/npm-run-script.html
deps/npm/html/doc/cli/npm-search.html
deps/npm/html/doc/cli/npm-shrinkwrap.html
deps/npm/html/doc/cli/npm-star.html
deps/npm/html/doc/cli/npm-stars.html
deps/npm/html/doc/cli/npm-start.html
deps/npm/html/doc/cli/npm-stop.html
deps/npm/html/doc/cli/npm-submodule.html
deps/npm/html/doc/cli/npm-tag.html
deps/npm/html/doc/cli/npm-test.html
deps/npm/html/doc/cli/npm-uninstall.html
deps/npm/html/doc/cli/npm-unpublish.html
deps/npm/html/doc/cli/npm-update.html
deps/npm/html/doc/cli/npm-version.html
deps/npm/html/doc/cli/npm-view.html
deps/npm/html/doc/cli/npm-whoami.html
deps/npm/html/doc/cli/npm.html
deps/npm/html/doc/files/npm-folders.html
deps/npm/html/doc/files/npm-global.html
deps/npm/html/doc/files/npm-json.html
deps/npm/html/doc/files/npmrc.html
deps/npm/html/doc/files/package.json.html
deps/npm/html/doc/index.html
deps/npm/html/doc/misc/npm-coding-style.html
deps/npm/html/doc/misc/npm-config.html
deps/npm/html/doc/misc/npm-developers.html
deps/npm/html/doc/misc/npm-disputes.html
deps/npm/html/doc/misc/npm-faq.html
deps/npm/html/doc/misc/npm-index.html
deps/npm/html/doc/misc/npm-registry.html
deps/npm/html/doc/misc/npm-scripts.html
deps/npm/html/doc/misc/removing-npm.html
deps/npm/html/doc/misc/semver.html
deps/npm/man/man1/npm-README.1
deps/npm/man/man1/npm-adduser.1
deps/npm/man/man1/npm-bin.1
deps/npm/man/man1/npm-bugs.1
deps/npm/man/man1/npm-build.1
deps/npm/man/man1/npm-bundle.1
deps/npm/man/man1/npm-cache.1
deps/npm/man/man1/npm-completion.1
deps/npm/man/man1/npm-dedupe.1
deps/npm/man/man1/npm-deprecate.1
deps/npm/man/man1/npm-docs.1
deps/npm/man/man1/npm-edit.1
deps/npm/man/man1/npm-explore.1
deps/npm/man/man1/npm-help-search.1
deps/npm/man/man1/npm-help.1
deps/npm/man/man1/npm-init.1
deps/npm/man/man1/npm-install.1
deps/npm/man/man1/npm-link.1
deps/npm/man/man1/npm-ls.1
deps/npm/man/man1/npm-outdated.1
deps/npm/man/man1/npm-owner.1
deps/npm/man/man1/npm-pack.1
deps/npm/man/man1/npm-prefix.1
deps/npm/man/man1/npm-prune.1
deps/npm/man/man1/npm-publish.1
deps/npm/man/man1/npm-rebuild.1
deps/npm/man/man1/npm-restart.1
deps/npm/man/man1/npm-rm.1
deps/npm/man/man1/npm-root.1
deps/npm/man/man1/npm-run-script.1
deps/npm/man/man1/npm-search.1
deps/npm/man/man1/npm-shrinkwrap.1
deps/npm/man/man1/npm-star.1
deps/npm/man/man1/npm-stars.1
deps/npm/man/man1/npm-start.1
deps/npm/man/man1/npm-stop.1
deps/npm/man/man1/npm-submodule.1
deps/npm/man/man1/npm-tag.1
deps/npm/man/man1/npm-test.1
deps/npm/man/man1/npm-uninstall.1
deps/npm/man/man1/npm-unpublish.1
deps/npm/man/man1/npm-update.1
deps/npm/man/man1/npm-version.1
deps/npm/man/man1/npm-view.1
deps/npm/man/man1/npm-whoami.1
deps/npm/man/man1/npm.1
deps/npm/man/man3/npm-bin.3
deps/npm/man/man3/npm-bugs.3
deps/npm/man/man3/npm-commands.3
deps/npm/man/man3/npm-config.3
deps/npm/man/man3/npm-deprecate.3
deps/npm/man/man3/npm-docs.3
deps/npm/man/man3/npm-edit.3
deps/npm/man/man3/npm-explore.3
deps/npm/man/man3/npm-help-search.3
deps/npm/man/man3/npm-init.3
deps/npm/man/man3/npm-install.3
deps/npm/man/man3/npm-link.3
deps/npm/man/man3/npm-load.3
deps/npm/man/man3/npm-ls.3
deps/npm/man/man3/npm-outdated.3
deps/npm/man/man3/npm-owner.3
deps/npm/man/man3/npm-pack.3
deps/npm/man/man3/npm-prefix.3
deps/npm/man/man3/npm-prune.3
deps/npm/man/man3/npm-publish.3
deps/npm/man/man3/npm-rebuild.3
deps/npm/man/man3/npm-restart.3
deps/npm/man/man3/npm-root.3
deps/npm/man/man3/npm-run-script.3
deps/npm/man/man3/npm-search.3
deps/npm/man/man3/npm-shrinkwrap.3
deps/npm/man/man3/npm-start.3
deps/npm/man/man3/npm-stop.3
deps/npm/man/man3/npm-submodule.3
deps/npm/man/man3/npm-tag.3
deps/npm/man/man3/npm-test.3
deps/npm/man/man3/npm-uninstall.3
deps/npm/man/man3/npm-unpublish.3
deps/npm/man/man3/npm-update.3
deps/npm/man/man3/npm-version.3
deps/npm/man/man3/npm-view.3
deps/npm/man/man3/npm-whoami.3
deps/npm/man/man3/npm.3
deps/npm/man/man5/npm-folders.5
deps/npm/man/man5/npm-global.5
deps/npm/man/man5/npm-json.5
deps/npm/man/man7/npm-coding-style.7
deps/npm/man/man7/npm-config.7
deps/npm/man/man7/npm-developers.7
deps/npm/man/man7/npm-disputes.7
deps/npm/man/man7/npm-faq.7
deps/npm/man/man7/npm-registry.7
deps/npm/man/man7/npm-scripts.7
deps/npm/man/man7/removing-npm.7
deps/npm/man/man7/semver.7
deps/npm/package.json
deps/uv/AUTHORS
deps/uv/ChangeLog
deps/uv/src/version.c
deps/uv/test/test-fs.c
deps/uv/test/test-list.h
lib/http.js
lib/tls.js
src/node_version.h

1  2 
AUTHORS
ChangeLog
Makefile
doc/api/tls.markdown
lib/_http_client.js
lib/_tls_legacy.js
src/node.cc
src/node_version.h

diff --cc AUTHORS
+++ b/AUTHORS
@@@ -461,5 -455,4 +461,6 @@@ Daniel G. Taylor <dan@programmer-art.or
  Kiyoshi Nomo <tokyoincidents.g@gmail.com>
  Veres Lajos <vlajos@gmail.com>
  Yuan Chuan <yuanchuan23@gmail.com>
 +Krzysztof Chrapka <chrapka.k@gmail.com>
 +Linus Mårtensson <linus.martensson@sonymobile.com>
+ Peter Rust <peter@cornerstonenw.com>
diff --cc ChangeLog
+++ b/ChangeLog
 -2013.07.09, Version 0.10.13 (Stable)
 +2013.06.26, Version 0.11.3 (Unstable)
 +
 +* uv: Upgrade to v0.11.5
 +
 +* c-ares: upgrade to 1.10.0
 +
 +* v8: upgrade to v3.19.13
 +
 +* punycode: update to v1.2.3 (Mathias Bynens)
 +
 +* debugger: break on uncaught exception (Miroslav Bajtos)
 +
 +* child_process: emit 'disconnect' asynchronously (Ben Noordhuis)
 +
 +* dtrace: enable uv's probes if enabled (Timothy J Fontaine)
 +
 +* dtrace: unify dtrace and systemtap interfaces (Timothy J Fontaine)
 +
 +* buffer: New API for backing data store (Trevor Norris)
 +
 +* buffer: return `this` in fill() for chainability (Brian White)
 +
 +* build: fix include order for building on windows (Timothy J Fontaine)
 +
 +* build: add android support (Linus Mårtensson)
 +
 +* readline: strip ctrl chars for prompt width calc (Krzysztof Chrapka)
 +
 +* tls: introduce TLSSocket based on tls_wrap binding (Fedor Indutny)
 +
 +* tls: add localAddress and localPort properties (Ben Noordhuis)
 +
 +* crypto: free excessive memory in NodeBIO (Fedor Indutny)
 +
 +* process: remove maxTickDepth (Trevor Norris)
 +
 +* timers: use uv_now instead of Date.now (Timothy J Fontaine)
 +
 +* util: Add debuglog, deprecate console lookalikes (isaacs)
 +
 +* module: use path.sep instead of a custom solution (Robert Kowalski)
 +
 +* http: don't escape request path, reject bad chars (Ben Noordhuis)
 +
 +* net: emit dns 'lookup' event before connect (Ben Noordhuis)
 +
 +* dns: add getServers and setServers (Timothy J Fontaine)
 +
 +
 +2013.05.13, Version 0.11.2 (Unstable), 5d3dc0e4c3369dfb00b7b13e08936c2e652fa696
 +
 +* uv: Upgrade to 0.11.2
 +
 +* V8: Upgrade to 3.19.0
 +
 +* npm: Upgrade to 1.2.21
 +
 +* build: Makefile should respect configure --prefix (Timothy J Fontaine)
 +
 +* cluster: use round-robin load balancing (Ben Noordhuis)
 +
 +* debugger, cluster: each worker has new debug port (Miroslav Bajtoš)
 +
 +* debugger: `restart` with custom debug port (Miroslav Bajtoš)
 +
 +* debugger: breakpoints in scripts not loaded yet (Miroslav Bajtoš)
 +
 +* event: EventEmitter#setMaxListeners() returns this (Sam Roberts)
 +
 +* events: add EventEmitter.defaultMaxListeners (Ben Noordhuis)
 +
 +* install: Support $(PREFIX) install target directory prefix (Olof Johansson)
 +
 +* os: Include netmask in os.networkInterfaces() (Ben Kelly)
 +
 +* path: add path.isAbsolute(path) (Ryan Doenges)
 +
 +* stream: Guarantee ordering of 'finish' event (isaacs)
 +
 +* streams: introduce .cork/.uncork/._writev (Fedor Indutny)
 +
 +* vm: add support for timeout argument (Andrew Paprocki)
 +
 +
 +2013.04.19, Version 0.11.1 (Unstable), 4babd2b46ebf9fbea2c9946af5cfae25a33b2b22
 +
 +* V8: upgrade to 3.18.0
 +
 +* uv: Upgrade to v0.11.1
 +
 +* http: split into multiple separate modules (Timothy J Fontaine)
 +
 +* http: escape unsafe characters in request path (Ben Noordhuis)
 +
 +* url: Escape all unwise characters (isaacs)
 +
 +* build: depend on v8 postmortem-metadata if enabled (Paddy Byers)
 +
 +* etw: update prototypes to match dtrace provider (Timothy J Fontaine)
 +
 +* buffer: change output of Buffer.prototype.toJSON() (David Braun)
 +
 +* dtrace: actually use the _handle.fd value (Timothy J Fontaine)
 +
 +* dtrace: pass more arguments to probes (Dave Pacheco)
 +
 +* build: allow building with dtrace on osx (Dave Pacheco)
 +
 +* zlib: allow passing options to convenience methods (Kyle Robinson Young)
 +
 +
 +2013.03.28, Version 0.11.0 (Unstable), bce38b3d74e64fcb7d04a2dd551151da6168cdc5
 +
 +* V8: update to 3.17.13
 +
 +* os: use %SystemRoot% or %windir% in os.tmpdir() (Suwon Chae)
 +
 +* util: fix util.inspect() line width calculation (Marcin Kostrzewa)
 +
 +* buffer: remove _charsWritten (Trevor Norris)
 +
 +* fs: uv_[fl]stat now reports subsecond resolution (Timothy J Fontaine)
 +
 +* fs: Throw if error raised and missing callback (bnoordhuis)
 +
 +* tls: expose SSL_CTX_set_timeout via tls.createServer (Manav Rathi)
 +
 +* tls: remove harmful unnecessary bounds checking (Marcel Laverdet)
 +
 +* buffer: write ascii strings using WriteOneByte (Trevor Norris)
 +
 +* dtrace: fix generation of v8 constants on freebsd (Fedor Indutny)
 +
 +* dtrace: x64 ustack helper (Fedor Indutny)
 +
 +* readline: handle wide characters properly (Nao Iizuka)
 +
 +* repl: Use a domain to catch async errors safely (isaacs)
 +
 +* repl: emit 'reset' event when context is reset (Sami Samhuri)
 +
 +* util: custom `inspect()` method may return an Object (Nathan Rajlich)
 +
 +* console: `console.dir()` bypasses inspect() methods (Nathan Rajlich)
 +
 +
++2013.07.09, Version 0.10.13 (Stable), e32660a984427d46af6a144983cf7b8045b7299c
+ * uv: Upgrade to v0.10.12
+ * npm: Upgrade to 1.3.2
+ * windows: get proper errno (Ben Noordhuis)
+ * tls: only wait for finish if we haven't seen it (Timothy J Fontaine)
+ * http: Dump response when request is aborted (isaacs)
+ * http: use an unref'd timer to fix delay in exit (Peter Rust)
+ * zlib: level can be negative (Brian White)
+ * zlib: allow zero values for level and strategy (Brian White)
+ * buffer: add comment explaining buffer alignment (Ben Noordhuis)
+ * string_bytes: properly detect 64bit (Timothy J Fontaine)
+ * src: fix memory leak in UsingDomains() (Ben Noordhuis)
 -2013.06.18, Version 0.10.12 (Stable)
 +2013.06.18, Version 0.10.12 (Stable), a088cf4f930d3928c97d239adf950ab43e7794aa
  
  * npm: Upgrade to 1.2.32
  
diff --cc Makefile
Simple merge
Simple merge
index 276c640,0000000..e0a68e6
mode 100644,000000..100644
--- /dev/null
@@@ -1,494 -1,0 +1,502 @@@
 +// Copyright Joyent, Inc. and other Node contributors.
 +//
 +// Permission is hereby granted, free of charge, to any person obtaining a
 +// copy of this software and associated documentation files (the
 +// "Software"), to deal in the Software without restriction, including
 +// without limitation the rights to use, copy, modify, merge, publish,
 +// distribute, sublicense, and/or sell copies of the Software, and to permit
 +// persons to whom the Software is furnished to do so, subject to the
 +// following conditions:
 +//
 +// The above copyright notice and this permission notice shall be included
 +// in all copies or substantial portions of the Software.
 +//
 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 +// USE OR OTHER DEALINGS IN THE SOFTWARE.
 +
 +var util = require('util');
 +var net = require('net');
 +var EventEmitter = require('events').EventEmitter;
 +var HTTPParser = process.binding('http_parser').HTTPParser;
 +var assert = require('assert').ok;
 +
 +var common = require('_http_common');
 +
 +var httpSocketSetup = common.httpSocketSetup;
 +var parsers = common.parsers;
 +var freeParser = common.freeParser;
 +var debug = common.debug;
 +
 +var IncomingMessage = require('_http_incoming').IncomingMessage;
 +var OutgoingMessage = require('_http_outgoing').OutgoingMessage;
 +
 +var agent = require('_http_agent');
 +var Agent = agent.Agent;
 +var globalAgent = agent.globalAgent;
 +
 +
 +function ClientRequest(options, cb) {
 +  var self = this;
 +  OutgoingMessage.call(self);
 +
 +  self.agent = options.agent === undefined ? globalAgent : options.agent;
 +
 +  var defaultPort = options.defaultPort || 80;
 +
 +  var port = options.port || defaultPort;
 +  var host = options.hostname || options.host || 'localhost';
 +
 +  if (options.setHost === undefined) {
 +    var setHost = true;
 +  }
 +
 +  self.socketPath = options.socketPath;
 +
 +  var method = self.method = (options.method || 'GET').toUpperCase();
 +  self.path = options.path || '/';
 +  if (cb) {
 +    self.once('response', cb);
 +  }
 +
 +  if (!Array.isArray(options.headers)) {
 +    if (options.headers) {
 +      var keys = Object.keys(options.headers);
 +      for (var i = 0, l = keys.length; i < l; i++) {
 +        var key = keys[i];
 +        self.setHeader(key, options.headers[key]);
 +      }
 +    }
 +    if (host && !this.getHeader('host') && setHost) {
 +      var hostHeader = host;
 +      if (port && +port !== defaultPort) {
 +        hostHeader += ':' + port;
 +      }
 +      this.setHeader('Host', hostHeader);
 +    }
 +  }
 +
 +  if (options.auth && !this.getHeader('Authorization')) {
 +    //basic auth
 +    this.setHeader('Authorization', 'Basic ' +
 +                   new Buffer(options.auth).toString('base64'));
 +  }
 +
 +  if (method === 'GET' || method === 'HEAD' || method === 'CONNECT') {
 +    self.useChunkedEncodingByDefault = false;
 +  } else {
 +    self.useChunkedEncodingByDefault = true;
 +  }
 +
 +  if (Array.isArray(options.headers)) {
 +    self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n',
 +                      options.headers);
 +  } else if (self.getHeader('expect')) {
 +    self._storeHeader(self.method + ' ' + self.path + ' HTTP/1.1\r\n',
 +                      self._renderHeaders());
 +  }
 +
 +  if (self.socketPath) {
 +    self._last = true;
 +    self.shouldKeepAlive = false;
 +    var conn = self.agent.createConnection({ path: self.socketPath });
 +    self.onSocket(conn);
 +  } else if (self.agent) {
 +    // If there is an agent we should default to Connection:keep-alive.
 +    self._last = false;
 +    self.shouldKeepAlive = true;
 +    self.agent.addRequest(self, options);
 +  } else {
 +    // No agent, default to Connection:close.
 +    self._last = true;
 +    self.shouldKeepAlive = false;
 +    if (options.createConnection) {
 +      var conn = options.createConnection(options);
 +    } else {
 +      debug('CLIENT use net.createConnection', options);
 +      var conn = net.createConnection(options);
 +    }
 +    self.onSocket(conn);
 +  }
 +
 +  self._deferToConnect(null, null, function() {
 +    self._flush();
 +    self = null;
 +  });
 +}
 +
 +util.inherits(ClientRequest, OutgoingMessage);
 +
 +exports.ClientRequest = ClientRequest;
 +
 +ClientRequest.prototype._finish = function() {
 +  DTRACE_HTTP_CLIENT_REQUEST(this, this.connection);
 +  COUNTER_HTTP_CLIENT_REQUEST();
 +  OutgoingMessage.prototype._finish.call(this);
 +};
 +
 +ClientRequest.prototype._implicitHeader = function() {
 +  this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n',
 +                    this._renderHeaders());
 +};
 +
 +ClientRequest.prototype.abort = function() {
++// If we're aborting, we don't care about any more response data.
++  if (this.res)
++    this.res._dump();
++  else
++    this.once('response', function(res) {
++      res._dump();
++    });
++
 +  if (this.socket) {
 +    // in-progress
 +    this.socket.destroy();
 +  } else {
 +    // haven't been assigned a socket yet.
 +    // this could be more efficient, it could
 +    // remove itself from the pending requests
 +    this._deferToConnect('destroy', []);
 +  }
 +};
 +
 +
 +function createHangUpError() {
 +  var error = new Error('socket hang up');
 +  error.code = 'ECONNRESET';
 +  return error;
 +}
 +
 +
 +function socketCloseListener() {
 +  var socket = this;
 +  var parser = socket.parser;
 +  var req = socket._httpMessage;
 +  debug('HTTP socket close');
 +  req.emit('close');
 +  if (req.res && req.res.readable) {
 +    // Socket closed before we emitted 'end' below.
 +    req.res.emit('aborted');
 +    var res = req.res;
 +    res.on('end', function() {
 +      res.emit('close');
 +    });
 +    res.push(null);
 +  } else if (!req.res && !req.socket._hadError) {
 +    // This socket error fired before we started to
 +    // receive a response. The error needs to
 +    // fire on the request.
 +    req.emit('error', createHangUpError());
 +    req.socket._hadError = true;
 +  }
 +
 +  // Too bad.  That output wasn't getting written.
 +  // This is pretty terrible that it doesn't raise an error.
 +  // Fixed better in v0.10
 +  if (req.output)
 +    req.output.length = 0;
 +  if (req.outputEncodings)
 +    req.outputEncodings.length = 0;
 +
 +  if (parser) {
 +    parser.finish();
 +    freeParser(parser, req);
 +  }
 +}
 +
 +function socketErrorListener(err) {
 +  var socket = this;
 +  var parser = socket.parser;
 +  var req = socket._httpMessage;
 +  debug('SOCKET ERROR:', err.message, err.stack);
 +
 +  if (req) {
 +    req.emit('error', err);
 +    // For Safety. Some additional errors might fire later on
 +    // and we need to make sure we don't double-fire the error event.
 +    req.socket._hadError = true;
 +  }
 +
 +  if (parser) {
 +    parser.finish();
 +    freeParser(parser, req);
 +  }
 +  socket.destroy();
 +}
 +
 +function socketOnEnd() {
 +  var socket = this;
 +  var req = this._httpMessage;
 +  var parser = this.parser;
 +
 +  if (!req.res && !req.socket._hadError) {
 +    // If we don't have a response then we know that the socket
 +    // ended prematurely and we need to emit an error on the request.
 +    req.emit('error', createHangUpError());
 +    req.socket._hadError = true;
 +  }
 +  if (parser) {
 +    parser.finish();
 +    freeParser(parser, req);
 +  }
 +  socket.destroy();
 +}
 +
 +function socketOnData(d) {
 +  var socket = this;
 +  var req = this._httpMessage;
 +  var parser = this.parser;
 +
 +  var ret = parser.execute(d);
 +  if (ret instanceof Error) {
 +    debug('parse error');
 +    freeParser(parser, req);
 +    socket.destroy();
 +    req.emit('error', ret);
 +    req.socket._hadError = true;
 +  } else if (parser.incoming && parser.incoming.upgrade) {
 +    // Upgrade or CONNECT
 +    var bytesParsed = ret;
 +    var res = parser.incoming;
 +    req.res = res;
 +
 +    socket.ondata = null;
 +    socket.onend = null;
 +    parser.finish();
 +
 +    var bodyHead = d.slice(bytesParsed, d.length);
 +
 +    var eventName = req.method === 'CONNECT' ? 'connect' : 'upgrade';
 +    if (EventEmitter.listenerCount(req, eventName) > 0) {
 +      req.upgradeOrConnect = true;
 +
 +      // detach the socket
 +      socket.emit('agentRemove');
 +      socket.removeListener('close', socketCloseListener);
 +      socket.removeListener('error', socketErrorListener);
 +
 +      req.emit(eventName, res, socket, bodyHead);
 +      req.emit('close');
 +    } else {
 +      // Got Upgrade header or CONNECT method, but have no handler.
 +      socket.destroy();
 +    }
 +    freeParser(parser, req);
 +  } else if (parser.incoming && parser.incoming.complete &&
 +             // When the status code is 100 (Continue), the server will
 +             // send a final response after this client sends a request
 +             // body. So, we must not free the parser.
 +             parser.incoming.statusCode !== 100) {
 +    freeParser(parser, req);
 +  }
 +}
 +
 +
 +// client
 +function parserOnIncomingClient(res, shouldKeepAlive) {
 +  var parser = this;
 +  var socket = this.socket;
 +  var req = socket._httpMessage;
 +
 +
 +  // propogate "domain" setting...
 +  if (req.domain && !res.domain) {
 +    debug('setting "res.domain"');
 +    res.domain = req.domain;
 +  }
 +
 +  debug('AGENT incoming response!');
 +
 +  if (req.res) {
 +    // We already have a response object, this means the server
 +    // sent a double response.
 +    socket.destroy();
 +    return;
 +  }
 +  req.res = res;
 +
 +  // Responses to CONNECT request is handled as Upgrade.
 +  if (req.method === 'CONNECT') {
 +    res.upgrade = true;
 +    return true; // skip body
 +  }
 +
 +  // Responses to HEAD requests are crazy.
 +  // HEAD responses aren't allowed to have an entity-body
 +  // but *can* have a content-length which actually corresponds
 +  // to the content-length of the entity-body had the request
 +  // been a GET.
 +  var isHeadResponse = req.method == 'HEAD';
 +  debug('AGENT isHeadResponse', isHeadResponse);
 +
 +  if (res.statusCode == 100) {
 +    // restart the parser, as this is a continue message.
 +    delete req.res; // Clear res so that we don't hit double-responses.
 +    req.emit('continue');
 +    return true;
 +  }
 +
 +  if (req.shouldKeepAlive && !shouldKeepAlive && !req.upgradeOrConnect) {
 +    // Server MUST respond with Connection:keep-alive for us to enable it.
 +    // If we've been upgraded (via WebSockets) we also shouldn't try to
 +    // keep the connection open.
 +    req.shouldKeepAlive = false;
 +  }
 +
 +
 +  DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
 +  COUNTER_HTTP_CLIENT_RESPONSE();
 +  req.res = res;
 +  res.req = req;
 +
 +  // add our listener first, so that we guarantee socket cleanup
 +  res.on('end', responseOnEnd);
 +  var handled = req.emit('response', res);
 +
 +  // If the user did not listen for the 'response' event, then they
 +  // can't possibly read the data, so we ._dump() it into the void
 +  // so that the socket doesn't hang there in a paused state.
 +  if (!handled)
 +    res._dump();
 +
 +  return isHeadResponse;
 +}
 +
 +// client
 +function responseOnEnd() {
 +  var res = this;
 +  var req = res.req;
 +  var socket = req.socket;
 +
 +  if (!req.shouldKeepAlive) {
 +    if (socket.writable) {
 +      debug('AGENT socket.destroySoon()');
 +      socket.destroySoon();
 +    }
 +    assert(!socket.writable);
 +  } else {
 +    debug('AGENT socket keep-alive');
 +    if (req.timeoutCb) {
 +      socket.setTimeout(0, req.timeoutCb);
 +      req.timeoutCb = null;
 +    }
 +    socket.removeListener('close', socketCloseListener);
 +    socket.removeListener('error', socketErrorListener);
 +    // Mark this socket as available, AFTER user-added end
 +    // handlers have a chance to run.
 +    process.nextTick(function() {
 +      socket.emit('free');
 +    });
 +  }
 +}
 +
 +ClientRequest.prototype.onSocket = function(socket) {
 +  var req = this;
 +
 +  process.nextTick(function() {
 +    var parser = parsers.alloc();
 +    req.socket = socket;
 +    req.connection = socket;
 +    parser.reinitialize(HTTPParser.RESPONSE);
 +    parser.socket = socket;
 +    parser.incoming = null;
 +    req.parser = parser;
 +
 +    socket.parser = parser;
 +    socket._httpMessage = req;
 +
 +    // Setup "drain" propogation.
 +    httpSocketSetup(socket);
 +
 +    // Propagate headers limit from request object to parser
 +    if (typeof req.maxHeadersCount === 'number') {
 +      parser.maxHeaderPairs = req.maxHeadersCount << 1;
 +    } else {
 +      // Set default value because parser may be reused from FreeList
 +      parser.maxHeaderPairs = 2000;
 +    }
 +
 +    socket.on('error', socketErrorListener);
 +    socket.ondata = socketOnData;
 +    socket.onend = socketOnEnd;
 +    socket.on('close', socketCloseListener);
 +    parser.onIncoming = parserOnIncomingClient;
 +    req.emit('socket', socket);
 +  });
 +
 +};
 +
 +ClientRequest.prototype._deferToConnect = function(method, arguments_, cb) {
 +  // This function is for calls that need to happen once the socket is
 +  // connected and writable. It's an important promisy thing for all the socket
 +  // calls that happen either now (when a socket is assigned) or
 +  // in the future (when a socket gets assigned out of the pool and is
 +  // eventually writable).
 +  var self = this;
 +  var onSocket = function() {
 +    if (self.socket.writable) {
 +      if (method) {
 +        self.socket[method].apply(self.socket, arguments_);
 +      }
 +      if (cb) { cb(); }
 +    } else {
 +      self.socket.once('connect', function() {
 +        if (method) {
 +          self.socket[method].apply(self.socket, arguments_);
 +        }
 +        if (cb) { cb(); }
 +      });
 +    }
 +  }
 +  if (!self.socket) {
 +    self.once('socket', onSocket);
 +  } else {
 +    onSocket();
 +  }
 +};
 +
 +ClientRequest.prototype.setTimeout = function(msecs, callback) {
 +  if (callback) this.once('timeout', callback);
 +
 +  var self = this;
 +  function emitTimeout() {
 +    self.emit('timeout');
 +  }
 +
 +  if (this.socket && this.socket.writable) {
 +    if (this.timeoutCb)
 +      this.socket.setTimeout(0, this.timeoutCb);
 +    this.timeoutCb = emitTimeout;
 +    this.socket.setTimeout(msecs, emitTimeout);
 +    return;
 +  }
 +
 +  // Set timeoutCb so that it'll get cleaned up on request end
 +  this.timeoutCb = emitTimeout;
 +  if (this.socket) {
 +    var sock = this.socket;
 +    this.socket.once('connect', function() {
 +      sock.setTimeout(msecs, emitTimeout);
 +    });
 +    return;
 +  }
 +
 +  this.once('socket', function(sock) {
 +    sock.setTimeout(msecs, emitTimeout);
 +  });
 +};
 +
 +ClientRequest.prototype.setNoDelay = function() {
 +  this._deferToConnect('setNoDelay', arguments);
 +};
 +ClientRequest.prototype.setSocketKeepAlive = function() {
 +  this._deferToConnect('setKeepAlive', arguments);
 +};
 +
 +ClientRequest.prototype.clearTimeout = function(cb) {
 +  this.setTimeout(0, cb);
 +};
index 6c5653e,0000000..4acabe3
mode 100644,000000..100644
--- /dev/null
@@@ -1,802 -1,0 +1,805 @@@
-     var waiting = 2;
 +var assert = require('assert');
 +var crypto = require('crypto');
 +var events = require('events');
 +var stream = require('stream');
 +var tls = require('tls');
 +var util = require('util');
 +
 +var Timer = process.binding('timer_wrap').Timer;
 +var Connection = null;
 +try {
 +  Connection = process.binding('crypto').Connection;
 +} catch (e) {
 +  throw new Error('node.js not compiled with openssl crypto support.');
 +}
 +
 +var debug = util.debuglog('tls');
 +
 +function SlabBuffer() {
 +  this.create();
 +}
 +
 +
 +SlabBuffer.prototype.create = function create() {
 +  this.isFull = false;
 +  this.pool = new Buffer(tls.SLAB_BUFFER_SIZE);
 +  this.offset = 0;
 +  this.remaining = this.pool.length;
 +};
 +
 +
 +SlabBuffer.prototype.use = function use(context, fn, size) {
 +  if (this.remaining === 0) {
 +    this.isFull = true;
 +    return 0;
 +  }
 +
 +  var actualSize = this.remaining;
 +
 +  if (size !== null) actualSize = Math.min(size, actualSize);
 +
 +  var bytes = fn.call(context, this.pool, this.offset, actualSize);
 +  if (bytes > 0) {
 +    this.offset += bytes;
 +    this.remaining -= bytes;
 +  }
 +
 +  assert(this.remaining >= 0);
 +
 +  return bytes;
 +};
 +
 +
 +var slabBuffer = null;
 +
 +
 +// Base class of both CleartextStream and EncryptedStream
 +function CryptoStream(pair, options) {
 +  stream.Duplex.call(this, options);
 +
 +  this.pair = pair;
 +  this._pending = null;
 +  this._pendingEncoding = '';
 +  this._pendingCallback = null;
 +  this._doneFlag = false;
 +  this._retryAfterPartial = false;
 +  this._halfRead = false;
 +  this._sslOutCb = null;
 +  this._resumingSession = false;
 +  this._reading = true;
 +  this._destroyed = false;
 +  this._ended = false;
 +  this._finished = false;
 +  this._opposite = null;
 +
 +  if (slabBuffer === null) slabBuffer = new SlabBuffer();
 +  this._buffer = slabBuffer;
 +
 +  this.once('finish', onCryptoStreamFinish);
 +
 +  // net.Socket calls .onend too
 +  this.once('end', onCryptoStreamEnd);
 +}
 +util.inherits(CryptoStream, stream.Duplex);
 +
 +
 +function onCryptoStreamFinish() {
 +  this._finished = true;
 +
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.onfinish');
 +    if (this.pair.ssl) {
 +      // Generate close notify
 +      // NOTE: first call checks if client has sent us shutdown,
 +      // second call enqueues shutdown into the BIO.
 +      if (this.pair.ssl.shutdown() !== 1) {
 +        if (this.pair.ssl && this.pair.ssl.error)
 +          return this.pair.error();
 +
 +        this.pair.ssl.shutdown();
 +      }
 +
 +      if (this.pair.ssl && this.pair.ssl.error)
 +        return this.pair.error();
 +    }
 +  } else {
 +    debug('encrypted.onfinish');
 +  }
 +
 +  // Try to read just to get sure that we won't miss EOF
 +  if (this._opposite.readable) this._opposite.read(0);
 +
 +  if (this._opposite._ended) {
 +    this._done();
 +
 +    // No half-close, sorry
 +    if (this === this.pair.cleartext) this._opposite._done();
 +  }
 +}
 +
 +
 +function onCryptoStreamEnd() {
 +  this._ended = true;
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.onend');
 +  } else {
 +    debug('encrypted.onend');
 +  }
 +
 +  if (this.onend) this.onend();
 +}
 +
 +
 +// NOTE: Called once `this._opposite` is set.
 +CryptoStream.prototype.init = function init() {
 +  var self = this;
 +  this._opposite.on('sslOutEnd', function() {
 +    if (self._sslOutCb) {
 +      var cb = self._sslOutCb;
 +      self._sslOutCb = null;
 +      cb(null);
 +    }
 +  });
 +};
 +
 +
 +CryptoStream.prototype._write = function write(data, encoding, cb) {
 +  assert(this._pending === null);
 +
 +  // Black-hole data
 +  if (!this.pair.ssl) return cb(null);
 +
 +  // When resuming session don't accept any new data.
 +  // And do not put too much data into openssl, before writing it from encrypted
 +  // side.
 +  //
 +  // TODO(indutny): Remove magic number, use watermark based limits
 +  if (!this._resumingSession &&
 +      this._opposite._internallyPendingBytes() < 128 * 1024) {
 +    // Write current buffer now
 +    var written;
 +    if (this === this.pair.cleartext) {
 +      debug('cleartext.write called with %d bytes', data.length);
 +      written = this.pair.ssl.clearIn(data, 0, data.length);
 +    } else {
 +      debug('encrypted.write called with %d bytes', data.length);
 +      written = this.pair.ssl.encIn(data, 0, data.length);
 +    }
 +
 +    // Handle and report errors
 +    if (this.pair.ssl && this.pair.ssl.error) {
 +      return cb(this.pair.error(true));
 +    }
 +
 +    // Force SSL_read call to cycle some states/data inside OpenSSL
 +    this.pair.cleartext.read(0);
 +
 +    // Cycle encrypted data
 +    if (this.pair.encrypted._internallyPendingBytes())
 +      this.pair.encrypted.read(0);
 +
 +    // Get NPN and Server name when ready
 +    this.pair.maybeInitFinished();
 +
 +    // Whole buffer was written
 +    if (written === data.length) {
 +      if (this === this.pair.cleartext) {
 +        debug('cleartext.write succeed with ' + written + ' bytes');
 +      } else {
 +        debug('encrypted.write succeed with ' + written + ' bytes');
 +      }
 +
 +      // Invoke callback only when all data read from opposite stream
 +      if (this._opposite._halfRead) {
 +        assert(this._sslOutCb === null);
 +        this._sslOutCb = cb;
 +      } else {
 +        cb(null);
 +      }
 +      return;
 +    } else if (written !== 0 && written !== -1) {
 +      assert(!this._retryAfterPartial);
 +      this._retryAfterPartial = true;
 +      this._write(data.slice(written), encoding, cb);
 +      this._retryAfterPartial = false;
 +      return;
 +    }
 +  } else {
 +    debug('cleartext.write queue is full');
 +
 +    // Force SSL_read call to cycle some states/data inside OpenSSL
 +    this.pair.cleartext.read(0);
 +  }
 +
 +  // No write has happened
 +  this._pending = data;
 +  this._pendingEncoding = encoding;
 +  this._pendingCallback = cb;
 +
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.write queued with %d bytes', data.length);
 +  } else {
 +    debug('encrypted.write queued with %d bytes', data.length);
 +  }
 +};
 +
 +
 +CryptoStream.prototype._writePending = function writePending() {
 +  var data = this._pending,
 +      encoding = this._pendingEncoding,
 +      cb = this._pendingCallback;
 +
 +  this._pending = null;
 +  this._pendingEncoding = '';
 +  this._pendingCallback = null;
 +  this._write(data, encoding, cb);
 +};
 +
 +
 +CryptoStream.prototype._read = function read(size) {
 +  // XXX: EOF?!
 +  if (!this.pair.ssl) return this.push(null);
 +
 +  // Wait for session to be resumed
 +  // Mark that we're done reading, but don't provide data or EOF
 +  if (this._resumingSession || !this._reading) return this.push('');
 +
 +  var out;
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.read called with %d bytes', size);
 +    out = this.pair.ssl.clearOut;
 +  } else {
 +    debug('encrypted.read called with %d bytes', size);
 +    out = this.pair.ssl.encOut;
 +  }
 +
 +  var bytesRead = 0,
 +      start = this._buffer.offset;
 +  do {
 +    var read = this._buffer.use(this.pair.ssl, out, size);
 +    if (read > 0) {
 +      bytesRead += read;
 +      size -= read;
 +    }
 +
 +    // Handle and report errors
 +    if (this.pair.ssl && this.pair.ssl.error) {
 +      this.pair.error();
 +      break;
 +    }
 +
 +    // Get NPN and Server name when ready
 +    this.pair.maybeInitFinished();
 +  } while (read > 0 && !this._buffer.isFull && bytesRead < size);
 +
 +  // Create new buffer if previous was filled up
 +  var pool = this._buffer.pool;
 +  if (this._buffer.isFull) this._buffer.create();
 +
 +  assert(bytesRead >= 0);
 +
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.read succeed with %d bytes', bytesRead);
 +  } else {
 +    debug('encrypted.read succeed with %d bytes', bytesRead);
 +  }
 +
 +  // Try writing pending data
 +  if (this._pending !== null) this._writePending();
 +  if (this._opposite._pending !== null) this._opposite._writePending();
 +
 +  if (bytesRead === 0) {
 +    // EOF when cleartext has finished and we have nothing to read
 +    if (this._opposite._finished && this._internallyPendingBytes() === 0) {
 +      // Perform graceful shutdown
 +      this._done();
 +
 +      // No half-open, sorry!
 +      if (this === this.pair.cleartext)
 +        this._opposite._done();
 +
 +      // EOF
 +      this.push(null);
 +    } else {
 +      // Bail out
 +      this.push('');
 +    }
 +  } else {
 +    // Give them requested data
 +    if (this.ondata) {
 +      var self = this;
 +      this.ondata(pool, start, start + bytesRead);
 +
 +      // Consume data automatically
 +      // simple/test-https-drain fails without it
 +      process.nextTick(function() {
 +        self.read(bytesRead);
 +      });
 +    }
 +    this.push(pool.slice(start, start + bytesRead));
 +  }
 +
 +  // Let users know that we've some internal data to read
 +  var halfRead = this._internallyPendingBytes() !== 0;
 +
 +  // Smart check to avoid invoking 'sslOutEnd' in the most of the cases
 +  if (this._halfRead !== halfRead) {
 +    this._halfRead = halfRead;
 +
 +    // Notify listeners about internal data end
 +    if (!halfRead) {
 +      if (this === this.pair.cleartext) {
 +        debug('cleartext.sslOutEnd');
 +      } else {
 +        debug('encrypted.sslOutEnd');
 +      }
 +
 +      this.emit('sslOutEnd');
 +    }
 +  }
 +};
 +
 +
 +CryptoStream.prototype.setTimeout = function(timeout, callback) {
 +  if (this.socket) this.socket.setTimeout(timeout, callback);
 +};
 +
 +
 +CryptoStream.prototype.setNoDelay = function(noDelay) {
 +  if (this.socket) this.socket.setNoDelay(noDelay);
 +};
 +
 +
 +CryptoStream.prototype.setKeepAlive = function(enable, initialDelay) {
 +  if (this.socket) this.socket.setKeepAlive(enable, initialDelay);
 +};
 +
 +CryptoStream.prototype.__defineGetter__('bytesWritten', function() {
 +  return this.socket ? this.socket.bytesWritten : 0;
 +});
 +
 +CryptoStream.prototype.getPeerCertificate = function() {
 +  if (this.pair.ssl) {
 +    var c = this.pair.ssl.getPeerCertificate();
 +
 +    if (c) {
 +      if (c.issuer) c.issuer = tls.parseCertString(c.issuer);
 +      if (c.subject) c.subject = tls.parseCertString(c.subject);
 +      return c;
 +    }
 +  }
 +
 +  return null;
 +};
 +
 +CryptoStream.prototype.getSession = function() {
 +  if (this.pair.ssl) {
 +    return this.pair.ssl.getSession();
 +  }
 +
 +  return null;
 +};
 +
 +CryptoStream.prototype.isSessionReused = function() {
 +  if (this.pair.ssl) {
 +    return this.pair.ssl.isSessionReused();
 +  }
 +
 +  return null;
 +};
 +
 +CryptoStream.prototype.getCipher = function(err) {
 +  if (this.pair.ssl) {
 +    return this.pair.ssl.getCurrentCipher();
 +  } else {
 +    return null;
 +  }
 +};
 +
 +
 +CryptoStream.prototype.end = function(chunk, encoding) {
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.end');
 +  } else {
 +    debug('encrypted.end');
 +  }
 +
 +  // Write pending data first
 +  if (this._pending !== null) this._writePending();
 +
 +  this.writable = false;
 +
 +  stream.Duplex.prototype.end.call(this, chunk, encoding);
 +};
 +
 +
 +CryptoStream.prototype.destroySoon = function(err) {
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.destroySoon');
 +  } else {
 +    debug('encrypted.destroySoon');
 +  }
 +
 +  if (this.writable)
 +    this.end();
 +
 +  if (this._writableState.finished && this._opposite._ended) {
 +    this.destroy();
 +  } else {
 +    // Wait for both `finish` and `end` events to ensure that all data that
 +    // was written on this side was read from the other side.
 +    var self = this;
-     this.once('finish', finish);
++    var waiting = 1;
 +    function finish() {
 +      if (--waiting === 0) self.destroy();
 +    }
 +    this._opposite.once('end', finish);
++    if (!this._finished) {
++      this.once('finish', finish);
++      ++waiting;
++    }
 +  }
 +};
 +
 +
 +CryptoStream.prototype.destroy = function(err) {
 +  if (this._destroyed) return;
 +  this._destroyed = true;
 +  this.readable = this.writable = false;
 +
 +  // Destroy both ends
 +  if (this === this.pair.cleartext) {
 +    debug('cleartext.destroy');
 +  } else {
 +    debug('encrypted.destroy');
 +  }
 +  this._opposite.destroy();
 +
 +  var self = this;
 +  process.nextTick(function() {
 +    // Force EOF
 +    self.push(null);
 +
 +    // Emit 'close' event
 +    self.emit('close', err ? true : false);
 +  });
 +};
 +
 +
 +CryptoStream.prototype._done = function() {
 +  this._doneFlag = true;
 +
 +  if (this === this.pair.encrypted && !this.pair._secureEstablished)
 +    return this.pair.error();
 +
 +  if (this.pair.cleartext._doneFlag &&
 +      this.pair.encrypted._doneFlag &&
 +      !this.pair._doneFlag) {
 +    // If both streams are done:
 +    this.pair.destroy();
 +  }
 +};
 +
 +
 +// readyState is deprecated. Don't use it.
 +Object.defineProperty(CryptoStream.prototype, 'readyState', {
 +  get: function() {
 +    if (this._connecting) {
 +      return 'opening';
 +    } else if (this.readable && this.writable) {
 +      return 'open';
 +    } else if (this.readable && !this.writable) {
 +      return 'readOnly';
 +    } else if (!this.readable && this.writable) {
 +      return 'writeOnly';
 +    } else {
 +      return 'closed';
 +    }
 +  }
 +});
 +
 +
 +function CleartextStream(pair, options) {
 +  CryptoStream.call(this, pair, options);
 +
 +  // This is a fake kludge to support how the http impl sits
 +  // on top of net Sockets
 +  var self = this;
 +  this._handle = {
 +    readStop: function() {
 +      self._reading = false;
 +    },
 +    readStart: function() {
 +      if (self._reading && self._readableState.length > 0) return;
 +      self._reading = true;
 +      self.read(0);
 +      if (self._opposite.readable) self._opposite.read(0);
 +    }
 +  };
 +}
 +util.inherits(CleartextStream, CryptoStream);
 +
 +
 +CleartextStream.prototype._internallyPendingBytes = function() {
 +  if (this.pair.ssl) {
 +    return this.pair.ssl.clearPending();
 +  } else {
 +    return 0;
 +  }
 +};
 +
 +
 +CleartextStream.prototype.address = function() {
 +  return this.socket && this.socket.address();
 +};
 +
 +
 +CleartextStream.prototype.__defineGetter__('remoteAddress', function() {
 +  return this.socket && this.socket.remoteAddress;
 +});
 +
 +
 +CleartextStream.prototype.__defineGetter__('remotePort', function() {
 +  return this.socket && this.socket.remotePort;
 +});
 +
 +
 +CleartextStream.prototype.__defineGetter__('localAddress', function() {
 +  return this.socket && this.socket.localAddress;
 +});
 +
 +
 +CleartextStream.prototype.__defineGetter__('localPort', function() {
 +  return this.socket && this.socket.localPort;
 +});
 +
 +
 +function EncryptedStream(pair, options) {
 +  CryptoStream.call(this, pair, options);
 +}
 +util.inherits(EncryptedStream, CryptoStream);
 +
 +
 +EncryptedStream.prototype._internallyPendingBytes = function() {
 +  if (this.pair.ssl) {
 +    return this.pair.ssl.encPending();
 +  } else {
 +    return 0;
 +  }
 +};
 +
 +
 +function onhandshakestart() {
 +  debug('onhandshakestart');
 +
 +  var self = this;
 +  var ssl = self.ssl;
 +  var now = Timer.now();
 +
 +  assert(now >= ssl.lastHandshakeTime);
 +
 +  if ((now - ssl.lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000) {
 +    ssl.handshakes = 0;
 +  }
 +
 +  var first = (ssl.lastHandshakeTime === 0);
 +  ssl.lastHandshakeTime = now;
 +  if (first) return;
 +
 +  if (++ssl.handshakes > tls.CLIENT_RENEG_LIMIT) {
 +    // Defer the error event to the next tick. We're being called from OpenSSL's
 +    // state machine and OpenSSL is not re-entrant. We cannot allow the user's
 +    // callback to destroy the connection right now, it would crash and burn.
 +    setImmediate(function() {
 +      var err = new Error('TLS session renegotiation attack detected.');
 +      if (self.cleartext) self.cleartext.emit('error', err);
 +    });
 +  }
 +}
 +
 +
 +function onhandshakedone() {
 +  // for future use
 +  debug('onhandshakedone');
 +}
 +
 +
 +function onclienthello(hello) {
 +  var self = this,
 +      once = false;
 +
 +  this._resumingSession = true;
 +  function callback(err, session) {
 +    if (once) return;
 +    once = true;
 +
 +    if (err) return self.socket.destroy(err);
 +
 +    self.ssl.loadSession(session);
 +
 +    // Cycle data
 +    self._resumingSession = false;
 +    self.cleartext.read(0);
 +    self.encrypted.read(0);
 +  }
 +
 +  if (hello.sessionId.length <= 0 ||
 +      !this.server ||
 +      !this.server.emit('resumeSession', hello.sessionId, callback)) {
 +    callback(null, null);
 +  }
 +}
 +
 +
 +function onnewsession(key, session) {
 +  if (!this.server) return;
 +  this.server.emit('newSession', key, session);
 +}
 +
 +
 +/**
 + * Provides a pair of streams to do encrypted communication.
 + */
 +
 +function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
 +                    options) {
 +  if (!(this instanceof SecurePair)) {
 +    return new SecurePair(credentials,
 +                          isServer,
 +                          requestCert,
 +                          rejectUnauthorized,
 +                          options);
 +  }
 +
 +  var self = this;
 +
 +  options || (options = {});
 +
 +  events.EventEmitter.call(this);
 +
 +  this.server = options.server;
 +  this._secureEstablished = false;
 +  this._isServer = isServer ? true : false;
 +  this._encWriteState = true;
 +  this._clearWriteState = true;
 +  this._doneFlag = false;
 +  this._destroying = false;
 +
 +  if (!credentials) {
 +    this.credentials = crypto.createCredentials();
 +  } else {
 +    this.credentials = credentials;
 +  }
 +
 +  if (!this._isServer) {
 +    // For clients, we will always have either a given ca list or be using
 +    // default one
 +    requestCert = true;
 +  }
 +
 +  this._rejectUnauthorized = rejectUnauthorized ? true : false;
 +  this._requestCert = requestCert ? true : false;
 +
 +  this.ssl = new Connection(this.credentials.context,
 +                            this._isServer ? true : false,
 +                            this._isServer ? this._requestCert :
 +                                             options.servername,
 +                            this._rejectUnauthorized);
 +
 +  if (this._isServer) {
 +    this.ssl.onhandshakestart = onhandshakestart.bind(this);
 +    this.ssl.onhandshakedone = onhandshakedone.bind(this);
 +    this.ssl.onclienthello = onclienthello.bind(this);
 +    this.ssl.onnewsession = onnewsession.bind(this);
 +    this.ssl.lastHandshakeTime = 0;
 +    this.ssl.handshakes = 0;
 +  }
 +
 +  if (process.features.tls_sni) {
 +    if (this._isServer && options.SNICallback) {
 +      this.ssl.setSNICallback(options.SNICallback);
 +    }
 +    this.servername = null;
 +  }
 +
 +  if (process.features.tls_npn && options.NPNProtocols) {
 +    this.ssl.setNPNProtocols(options.NPNProtocols);
 +    this.npnProtocol = null;
 +  }
 +
 +  /* Acts as a r/w stream to the cleartext side of the stream. */
 +  this.cleartext = new CleartextStream(this, options.cleartext);
 +
 +  /* Acts as a r/w stream to the encrypted side of the stream. */
 +  this.encrypted = new EncryptedStream(this, options.encrypted);
 +
 +  /* Let streams know about each other */
 +  this.cleartext._opposite = this.encrypted;
 +  this.encrypted._opposite = this.cleartext;
 +  this.cleartext.init();
 +  this.encrypted.init();
 +
 +  process.nextTick(function() {
 +    /* The Connection may be destroyed by an abort call */
 +    if (self.ssl) {
 +      self.ssl.start();
 +    }
 +  });
 +}
 +
 +util.inherits(SecurePair, events.EventEmitter);
 +
 +
 +exports.createSecurePair = function(credentials,
 +                                    isServer,
 +                                    requestCert,
 +                                    rejectUnauthorized) {
 +  var pair = new SecurePair(credentials,
 +                            isServer,
 +                            requestCert,
 +                            rejectUnauthorized);
 +  return pair;
 +};
 +
 +
 +SecurePair.prototype.maybeInitFinished = function() {
 +  if (this.ssl && !this._secureEstablished && this.ssl.isInitFinished()) {
 +    if (process.features.tls_npn) {
 +      this.npnProtocol = this.ssl.getNegotiatedProtocol();
 +    }
 +
 +    if (process.features.tls_sni) {
 +      this.servername = this.ssl.getServername();
 +    }
 +
 +    this._secureEstablished = true;
 +    debug('secure established');
 +    this.emit('secure');
 +  }
 +};
 +
 +
 +SecurePair.prototype.destroy = function() {
 +  if (this._destroying) return;
 +
 +  if (!this._doneFlag) {
 +    debug('SecurePair.destroy');
 +    this._destroying = true;
 +
 +    // SecurePair should be destroyed only after it's streams
 +    this.cleartext.destroy();
 +    this.encrypted.destroy();
 +
 +    this._doneFlag = true;
 +    this.ssl.error = null;
 +    this.ssl.close();
 +    this.ssl = null;
 +  }
 +};
 +
 +
 +SecurePair.prototype.error = function(returnOnly) {
 +  var err = this.ssl.error;
 +  this.ssl.error = null;
 +
 +  if (!this._secureEstablished) {
 +    // Emit ECONNRESET instead of zero return
 +    if (!err || err.message === 'ZERO_RETURN') {
 +      var connReset = new Error('socket hang up');
 +      connReset.code = 'ECONNRESET';
 +      connReset.sslError = err && err.message;
 +
 +      err = connReset;
 +    }
 +    this.destroy();
 +    if (!returnOnly) this.emit('error', err);
 +  } else if (this._isServer &&
 +             this._rejectUnauthorized &&
 +             /peer did not return a certificate/.test(err.message)) {
 +    // Not really an error.
 +    this.destroy();
 +  } else {
 +    if (!returnOnly) this.cleartext.emit('error', err);
 +  }
 +  return err;
 +};
diff --cc src/node.cc
@@@ -1009,8 -1006,10 +1009,11 @@@ MakeCallback(const Handle<Object> objec
               int argc,
               Handle<Value> argv[]) {
    // TODO Hook for long stack traces to be made here.
 +  Local<Object> process = PersistentToLocal(process_p);
  
+   if (using_domains)
+     return MakeDomainCallback(object, callback, argc, argv);
    // lazy load no domain next tick callbacks
    if (process_tickCallback.IsEmpty()) {
      Local<Value> cb_v = process->Get(String::New("_tickCallback"));
  #define NODE_VERSION_H
  
  #define NODE_MAJOR_VERSION 0
 -#define NODE_MINOR_VERSION 10
 -#define NODE_PATCH_VERSION 14
 +#define NODE_MINOR_VERSION 11
- #define NODE_PATCH_VERSION 3
++#define NODE_PATCH_VERSION 4
  
 -#define NODE_VERSION_IS_RELEASE 0
 +#define NODE_VERSION_IS_RELEASE 1
  
  #ifndef NODE_TAG
  # define NODE_TAG ""