diff --git a/ChangeLog b/ChangeLog index b66faae59e..20394bec1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -255,6 +255,35 @@ * Bug fixes +2012.05.15 Version 0.6.18 (stable), 4bc1d395de6abed2cf1e4d0b7b3a1480a21c368f + +* windows: skip GetFileAttributes call when opening a file (Bert Belder) + +* crypto: add PKCS12/PFX support (Sambasiva Suda) + +* #3240: child_process: delete NODE_CHANNEL_FD from env in spawn (Ben Noordhuis) + +* windows: add test for path.normalize with UNC paths (Bert Belder) + +* windows: make path.normalize convert all slashes to backslashes (Bert Belder) + +* fs: Automatically close FSWatcher on error (Bert Belder) + +* #3258: fs.ReadStream.pause() emits duplicate data event (koichik) + +* pipe_wrap: don't assert() on pipe accept errors (Ben Noordhuis) + +* Better exception output for module load and process.nextTick (Felix Geisendörfer) + +* zlib: fix error reporting (Ben Noordhuis) + +* http: Don't destroy on timeout (isaacs) + +* #3231: http: Don't try to emit error on a null'ed req object (isaacs) + +* #3236: http: Refactor ClientRequest.onSocket (isaacs) + + 2012.05.04 Version 0.6.17 (stable), 4ced23deaf36493f4303a18f6fdce768c58becc0 * Upgrade npm to 1.1.21 diff --git a/Makefile b/Makefile index cc913ff75d..a80da5141f 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,7 @@ out/doc/api/%.html: doc/api/%.markdown out/Release/node tools/doc/generate.js --format=html --template=doc/template.html $< > $@ email.md: ChangeLog tools/email-footer.md - bash tools/changelog-head.sh > $@ + bash tools/changelog-head.sh | sed 's|^\* #|* \\#|g' > $@ cat tools/email-footer.md | sed -e 's|__VERSION__|'$(VERSION)'|g' >> $@ blog.html: email.md diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index a444adb67d..11c7097a89 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -70,7 +70,7 @@ Allocates a new buffer containing the given `str`. * `string` String - data to be written to buffer * `offset` Number, Optional, Default: 0 -* `length` Number, Optional +* `length` Number, Optional, Default: `buffer.length - offset` * `encoding` String, Optional, Default: 'utf8' Writes `string` to the buffer at `offset` using the given encoding. @@ -93,7 +93,7 @@ next time `buf.write()` is called. * `encoding` String, Optional, Default: 'utf8' * `start` Number, Optional, Default: 0 -* `end` Number, Optional +* `end` Number, Optional, Default: `buffer.length` Decodes and returns a string from buffer data encoded with `encoding` (defaults to `'utf8'`) beginning at `start` (defaults to `0`) and ending at @@ -171,7 +171,7 @@ buffer object. It does not change when the contents of the buffer are changed. * `targetBuffer` Buffer object - Buffer to copy into * `targetStart` Number, Optional, Default: 0 * `sourceStart` Number, Optional, Default: 0 -* `sourceEnd` Number, Optional, Default: 0 +* `sourceEnd` Number, Optional, Default: `buffer.length` Does copy between buffers. The source and target regions can be overlapped. `targetStart` and `sourceStart` default to `0`. @@ -197,7 +197,7 @@ into `buf2`, starting at the 8th byte in `buf2`. ### buf.slice([start], [end]) * `start` Number, Optional, Default: 0 -* `end` Number, Optional, Default: 0 +* `end` Number, Optional, Default: `buffer.length` Returns a new buffer which references the same memory as the old, but offset and cropped by the `start` (defaults to `0`) and `end` (defaults to diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index 610154c7b3..3537fc13b9 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -14,8 +14,9 @@ It also offers a set of wrappers for OpenSSL's hash, hmac, cipher, decipher, sig Creates a credentials object, with the optional details being a dictionary with keys: +* `pfx` : A string or buffer holding the PFX or PKCS12 encoded private key, certificate and CA certificates * `key` : A string holding the PEM encoded private key -* `passphrase` : A string of passphrase for the private key +* `passphrase` : A string of passphrase for the private key or pfx * `cert` : A string holding the PEM encoded certificate * `ca` : Either a string or list of strings of PEM encoded CA certificates to trust. * `crl` : Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List) diff --git a/doc/api/https.markdown b/doc/api/https.markdown index 9f51e5fc5e..10c9a3e3ba 100644 --- a/doc/api/https.markdown +++ b/doc/api/https.markdown @@ -32,6 +32,19 @@ Example: res.end("hello world\n"); }).listen(8000); +Or + + var https = require('https'); + var fs = require('fs'); + + var options = { + pfx: fs.readFileSync('server.pfx') + }; + + https.createServer(options, function (req, res) { + res.writeHead(200); + res.end("hello world\n"); + }).listen(8000); ## https.request(options, callback) @@ -91,8 +104,9 @@ The options argument has the following options The following options from [tls.connect()](tls.html#tls.connect) can also be specified. However, a [globalAgent](#https.globalAgent) silently ignores these. +- `pfx`: Certificate, Private key and CA certificates to use for SSL. Default `null`. - `key`: Private key to use for SSL. Default `null`. -- `passphrase`: A string of passphrase for the private key. Default `null`. +- `passphrase`: A string of passphrase for the private key or pfx. Default `null`. - `cert`: Public x509 certificate to use. Default `null`. - `ca`: An authority certificate or array of authority certificates to check the remote host against. diff --git a/doc/api/stream.markdown b/doc/api/stream.markdown index cd43c77e7a..7ddca6cc99 100644 --- a/doc/api/stream.markdown +++ b/doc/api/stream.markdown @@ -74,11 +74,6 @@ Resumes the incoming `'data'` events after a `pause()`. Closes the underlying file descriptor. Stream will not emit any more events. - -### stream.destroySoon() - -After the write queue is drained, close the file descriptor. - ### stream.pipe(destination, [options]) This is a `Stream.prototype` method available on all `Stream`s. diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index a659006479..f5283c3f95 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -28,6 +28,17 @@ Alternatively you can send the CSR to a Certificate Authority for signing. (TODO: docs on creating a CA, for now interested users should just look at `test/fixtures/keys/Makefile` in the Node source code) +To create .pfx or .p12, do this: + + openssl pkcs12 -export -in agent5-cert.pem -inkey agent5-key.pem \ + -certfile ca-cert.pem -out agent5.pfx + + - `in`: certificate + - `inkey`: private key + - `certfile`: all CA certs concatenated in one file like + `cat ca1-cert.pem ca2-cert.pem > ca-cert.pem` + + ## Client-initiated renegotiation attack mitigation @@ -72,10 +83,14 @@ The `connectionListener` argument is automatically set as a listener for the [secureConnection](#event_secureConnection_) event. The `options` object has these possibilities: + - `pfx`: A string or `Buffer` containing the private key, certificate and + CA certs of the server in PFX or PKCS12 format. (Mutually exclusive with + the `key`, `cert` and `ca` options.) + - `key`: A string or `Buffer` containing the private key of the server in PEM format. (Required) - - `passphrase`: A string of passphrase for the private key. + - `passphrase`: A string of passphrase for the private key or pfx. - `cert`: A string or `Buffer` containing the certificate key of the server in PEM format. (Required) @@ -155,7 +170,29 @@ Here is a simple example echo server: console.log('server bound'); }); +Or + + var tls = require('tls'); + var fs = require('fs'); + + var options = { + pfx: fs.readFileSync('server.pfx'), + // This is necessary only if using the client certificate authentication. + requestCert: true, + + }; + + var server = tls.createServer(options, function(cleartextStream) { + console.log('server connected', + cleartextStream.authorized ? 'authorized' : 'unauthorized'); + cleartextStream.write("welcome!\n"); + cleartextStream.setEncoding('utf8'); + cleartextStream.pipe(cleartextStream); + }); + server.listen(8000, function() { + console.log('server bound'); + }); You can test this server by connecting to it with `openssl s_client`: @@ -177,10 +214,13 @@ Creates a new client connection to the given `port` and `host` (old API) or creating a new socket. If this option is specified, `host` and `port` are ignored. + - `pfx`: A string or `Buffer` containing the private key, certificate and + CA certs of the server in PFX or PKCS12 format. + - `key`: A string or `Buffer` containing the private key of the client in PEM format. - - `passphrase`: A string of passphrase for the private key. + - `passphrase`: A string of passphrase for the private key or pfx. - `cert`: A string or `Buffer` containing the certificate key of the client in PEM format. @@ -233,6 +273,28 @@ Here is an example of a client of echo server as described previously: server.close(); }); +Or + + var tls = require('tls'); + var fs = require('fs'); + + var options = { + pfx: fs.readFileSync('client.pfx') + }; + + var cleartextStream = tls.connect(8000, options, function() { + console.log('client connected', + cleartextStream.authorized ? 'authorized' : 'unauthorized'); + process.stdin.pipe(cleartextStream); + process.stdin.resume(); + }); + cleartextStream.setEncoding('utf8'); + cleartextStream.on('data', function(data) { + console.log(data); + }); + cleartextStream.on('end', function() { + server.close(); + }); ## tls.createSecurePair([credentials], [isServer], [requestCert], [rejectUnauthorized]) diff --git a/lib/crypto.js b/lib/crypto.js index 05b19755be..67d9ab7cf7 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -115,6 +115,14 @@ exports.createCredentials = function(options, context) { c.context.setSessionIdContext(options.sessionIdContext); } + if (options.pfx) { + if (options.passphrase) { + c.context.loadPKCS12(options.pfx, options.passphrase); + } else { + c.context.loadPKCS12(options.pfx); + } + } + return c; }; diff --git a/lib/fs.js b/lib/fs.js index a3e68cb06b..f943719665 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -740,6 +740,7 @@ function FSWatcher() { this._handle.onchange = function(status, event, filename) { if (status) { + self._handle.close(); self.emit('error', errnoException(errno, 'watch')); } else { self.emit('change', event, filename); @@ -1286,8 +1287,9 @@ ReadStream.prototype.resume = function() { this.paused = false; if (this.buffer) { - this._emitData(this.buffer); + var buffer = this.buffer; this.buffer = null; + this._emitData(buffer); } // hasn't opened yet. diff --git a/lib/http.js b/lib/http.js index ec562da86f..ff9b3cfc03 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1315,6 +1315,7 @@ function socketErrorListener(err) { socket.destroy(); } + function responseOnEnd() { var req = this.req; var socket = req.socket; @@ -1397,7 +1398,6 @@ function socketOnEnd() { socket.destroy(); } - function socketOnData(d, start, end) { var socket = this; var req = this._httpMessage; @@ -1461,7 +1461,6 @@ ClientRequest.prototype.onSocket = function(socket) { socket._httpMessage = req; - // Setup "drain" propogation. httpSocketSetup(socket); socket.ondata = socketOnData; diff --git a/lib/path.js b/lib/path.js index ad8fd8d787..961dc400a5 100644 --- a/lib/path.js +++ b/lib/path.js @@ -179,6 +179,9 @@ if (isWindows) { tail += '\\'; } + // Convert slashes to backslashes when `device` points to an UNC root. + device = device.replace(/\//g, '\\'); + return device + (isAbsolute ? '\\' : '') + tail; }; diff --git a/lib/tls.js b/lib/tls.js index c7b0825873..9977233563 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -932,6 +932,7 @@ function Server(/* [options], listener */) { this.setOptions(options); var sharedCreds = crypto.createCredentials({ + pfx : self.pfx, key: self.key, passphrase: self.passphrase, cert: self.cert, @@ -1016,6 +1017,7 @@ Server.prototype.setOptions = function(options) { this.rejectUnauthorized = false; } + if (options.pfx) this.pfx = options.pfx; if (options.key) this.key = options.key; if (options.passphrase) this.passphrase = options.passphrase; if (options.cert) this.cert = options.cert; diff --git a/src/node.js b/src/node.js index 5f2dd87bda..ef0301267f 100644 --- a/src/node.js +++ b/src/node.js @@ -480,6 +480,10 @@ // start parsing data from that stream. if (process.env.NODE_CHANNEL_FD) { assert(parseInt(process.env.NODE_CHANNEL_FD) >= 0); + + // Make sure it's not accidentally inherited by child processes. + delete process.env.NODE_CHANNEL_FD; + var cp = NativeModule.require('child_process'); // Load tcp_wrap to avoid situation where we might immediately receive diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 134e58800e..14269d5507 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -43,6 +43,7 @@ # include #endif + #if OPENSSL_VERSION_NUMBER >= 0x10000000L # define OPENSSL_CONST const #else @@ -150,6 +151,7 @@ void SecureContext::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "setSessionIdContext", SecureContext::SetSessionIdContext); NODE_SET_PROTOTYPE_METHOD(t, "close", SecureContext::Close); + NODE_SET_PROTOTYPE_METHOD(t, "loadPKCS12", SecureContext::LoadPKCS12); target->Set(String::NewSymbol("SecureContext"), t->GetFunction()); } @@ -576,6 +578,83 @@ Handle SecureContext::Close(const Arguments& args) { return False(); } +//Takes .pfx or .p12 and password in string or buffer format +Handle SecureContext::LoadPKCS12(const Arguments& args) { + HandleScope scope; + + BIO* in = NULL; + PKCS12* p12 = NULL; + EVP_PKEY* pkey = NULL; + X509* cert = NULL; + STACK_OF(X509)* extraCerts = NULL; + char* pass = NULL; + bool ret = false; + + SecureContext *sc = ObjectWrap::Unwrap(args.Holder()); + + if (args.Length() < 1) { + return ThrowException(Exception::TypeError( + String::New("Bad parameter"))); + } + + in = LoadBIO(args[0]); + if (in == NULL) { + return ThrowException(Exception::Error( + String::New("Unable to load BIO"))); + } + + if (args.Length() >= 2) { + ASSERT_IS_STRING_OR_BUFFER(args[1]); + + int passlen = DecodeBytes(args[1], BINARY); + if (passlen < 0) { + BIO_free(in); + return ThrowException(Exception::TypeError( + String::New("Bad password"))); + } + pass = new char[passlen + 1]; + int pass_written = DecodeWrite(pass, passlen, args[1], BINARY); + + assert(pass_written == passlen); + pass[passlen] = '\0'; + } + + if (d2i_PKCS12_bio(in, &p12) && + PKCS12_parse(p12, pass, &pkey, &cert, &extraCerts) && + SSL_CTX_use_certificate(sc->ctx_, cert) && + SSL_CTX_use_PrivateKey(sc->ctx_, pkey)) + { + // set extra certs + while (X509* x509 = sk_X509_pop(extraCerts)) { + if (!sc->ca_store_) { + sc->ca_store_ = X509_STORE_new(); + SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); + } + + X509_STORE_add_cert(sc->ca_store_, x509); + SSL_CTX_add_client_CA(sc->ctx_, x509); + } + + EVP_PKEY_free(pkey); + X509_free(cert); + sk_X509_free(extraCerts); + + ret = true; + } + + PKCS12_free(p12); + BIO_free(in); + delete[] pass; + + if (!ret) { + unsigned long err = ERR_get_error(); + const char *str = ERR_reason_error_string(err); + return ThrowException(Exception::Error(String::New(str))); + } + + return True(); +} + #ifdef SSL_PRINT_DEBUG # define DEBUG_PRINT(...) fprintf (stderr, __VA_ARGS__) diff --git a/src/node_crypto.h b/src/node_crypto.h index 9fcddf0133..1ee23c8a74 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef OPENSSL_NPN_NEGOTIATED #include "node_buffer.h" @@ -68,6 +69,7 @@ class SecureContext : ObjectWrap { static v8::Handle SetOptions(const v8::Arguments& args); static v8::Handle SetSessionIdContext(const v8::Arguments& args); static v8::Handle Close(const v8::Arguments& args); + static v8::Handle LoadPKCS12(const v8::Arguments& args); SecureContext() : ObjectWrap() { ctx_ = NULL; diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 023a009196..f984d3bb3f 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -205,8 +205,8 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) { assert(wrap->object_.IsEmpty() == false); if (status != 0) { - // TODO Handle server error (set errno and call onconnection with NULL) - assert(0); + SetErrno(uv_last_error(uv_default_loop())); + MakeCallback(wrap->object_, "onconnection", 0, NULL); return; } diff --git a/test/fixtures/test_cert.pfx b/test/fixtures/test_cert.pfx new file mode 100644 index 0000000000..fd28781a05 Binary files /dev/null and b/test/fixtures/test_cert.pfx differ diff --git a/test/gc/test-http-client-timeout.js b/test/gc/test-http-client-timeout.js index cdf5019fc0..6d705b47eb 100644 --- a/test/gc/test-http-client-timeout.js +++ b/test/gc/test-http-client-timeout.js @@ -13,7 +13,7 @@ var http = require('http'), done = 0, count = 0, countGC = 0, - todo = 400, + todo = 550, common = require('../common.js'), assert = require('assert'), PORT = common.PORT; diff --git a/test/simple/test-child-process-fork-and-spawn.js b/test/simple/test-child-process-fork-and-spawn.js new file mode 100644 index 0000000000..989bf7ee3a --- /dev/null +++ b/test/simple/test-child-process-fork-and-spawn.js @@ -0,0 +1,53 @@ +// 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 common = require('../common'); +var assert = require('assert'); +var spawn = require('child_process').spawn; +var fork = require('child_process').fork; + +// Fork, then spawn. The spawned process should not hang. +switch (process.argv[2] || '') { +case '': + fork(__filename, ['fork']).on('exit', checkExit); + process.on('exit', haveExit); + break; +case 'fork': + spawn(process.execPath, [__filename, 'spawn']).on('exit', checkExit); + process.on('exit', haveExit); + break; +case 'spawn': + break; +default: + assert(0); +} + +var seenExit = false; + +function checkExit(statusCode) { + seenExit = true; + assert.equal(statusCode, 0); + process.nextTick(process.exit); +} + +function haveExit() { + assert.equal(seenExit, true); +} diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index 800e3eb5ae..7a23cdf494 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -38,6 +38,7 @@ var path = require('path'); // Test Certificates var caPem = fs.readFileSync(common.fixturesDir + '/test_ca.pem', 'ascii'); var certPem = fs.readFileSync(common.fixturesDir + '/test_cert.pem', 'ascii'); +var certPfx = fs.readFileSync(common.fixturesDir + '/test_cert.pfx'); var keyPem = fs.readFileSync(common.fixturesDir + '/test_key.pem', 'ascii'); var rsaPubPem = fs.readFileSync(common.fixturesDir + '/test_rsa_pubkey.pem', 'ascii'); @@ -54,8 +55,24 @@ try { process.exit(); } -// Test HMAC +// PFX tests +assert.doesNotThrow(function() { + crypto.createCredentials({pfx:certPfx, passphrase:'sample'}); +}); +assert.throws(function() { + crypto.createCredentials({pfx:certPfx}); +}, 'mac verify failure'); + +assert.throws(function() { + crypto.createCredentials({pfx:certPfx, passphrase:'test'}); +}, 'mac verify failure'); + +assert.throws(function() { + crypto.createCredentials({pfx:'sample', passphrase:'test'}); +}, 'not enough data'); + +// Test HMAC var h1 = crypto.createHmac('sha1', 'Node') .update('some data') .update('to hmac') diff --git a/test/simple/test-fs-read-stream-resume.js b/test/simple/test-fs-read-stream-resume.js new file mode 100644 index 0000000000..c3ace49e9f --- /dev/null +++ b/test/simple/test-fs-read-stream-resume.js @@ -0,0 +1,51 @@ +// 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 common = require('../common'); +var assert = require('assert'); + +var fs = require('fs'); +var path = require('path'); + +var file = path.join(common.fixturesDir, 'x.txt'); +var data = ''; +var first = true; + +var stream = fs.createReadStream(file); +stream.setEncoding('utf8'); +stream.on('data', function(chunk) { + data += chunk; + if (first) { + first = false; + stream.resume(); + } +}); + +process.nextTick(function() { + stream.pause(); + setTimeout(function() { + stream.resume(); + }, 100); +}); + +process.on('exit', function() { + assert.equal(data, 'xyz\n'); +}); diff --git a/test/simple/test-https-pfx.js b/test/simple/test-https-pfx.js new file mode 100644 index 0000000000..bfed64afd6 --- /dev/null +++ b/test/simple/test-https-pfx.js @@ -0,0 +1,56 @@ +// 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 common = require('../common'); +var assert = require('assert'); +var https = require('https'); +var fs = require('fs'); + +var pfx = fs.readFileSync(common.fixturesDir + '/test_cert.pfx'); + +var options = { + host: '127.0.0.1', + port: common.PORT, + path: '/', + pfx: pfx, + passphrase: 'sample', + requestCert: true +}; + +var server = https.createServer(options, function(req, res) { + assert.equal(req.socket.authorized, false); // not a client cert + assert.equal(req.socket.authorizationError, 'UNABLE_TO_GET_ISSUER_CERT'); + res.writeHead(200); + res.end('OK'); +}); + +server.listen(options.port, options.host, function() { + var data = ''; + + https.get(options, function(res) { + res.on('data', function(data_) { data += data_ }); + res.on('end', function() { server.close() }); + }); + + process.on('exit', function() { + assert.equal(data, 'OK'); + }); +}); diff --git a/test/simple/test-path.js b/test/simple/test-path.js index a5c7372d7d..38a8dab89c 100644 --- a/test/simple/test-path.js +++ b/test/simple/test-path.js @@ -194,6 +194,8 @@ if (isWindows) { assert.equal(path.normalize('a//b//../b'), 'a\\b'); assert.equal(path.normalize('a//b//./c'), 'a\\b\\c'); assert.equal(path.normalize('a//b//.'), 'a\\b'); + assert.equal(path.normalize('//server/share/dir/file.ext'), + '\\\\server\\share\\dir\\file.ext'); } else { assert.equal(path.normalize('./fixtures///b/../b/c.js'), 'fixtures/b/c.js');