Browse Source

tls_wrap: reach error reporting for UV_EPROTO

Do not swallow error details when reporting UV_EPROTO asynchronously,
and when creating artificial errors.

Fix: #3692
PR-URL: https://github.com/nodejs/node/pull/4885
Reviewed-By: Shigeki Ohtsu <ohtsu@iij.ad.jp>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
process-exit-stdio-flushing
Fedor Indutny 9 years ago
parent
commit
ff4006c7b0
  1. 2
      lib/net.js
  2. 11
      src/stream_base.h
  3. 22
      src/tls_wrap.cc
  4. 2
      src/tls_wrap.h
  5. 29
      test/parallel/test-tls-junk-server.js

2
lib/net.js

@ -760,7 +760,7 @@ function afterWrite(status, handle, req, err) {
} }
if (status < 0) { if (status < 0) {
var ex = exceptionWithHostPort(status, 'write', req.address, req.port); var ex = errnoException(status, 'write', req.error);
debug('write failure', ex); debug('write failure', ex);
self._destroy(ex, req.cb); self._destroy(ex, req.cb);
return; return;

11
src/stream_base.h

@ -22,8 +22,15 @@ class StreamReq {
explicit StreamReq(DoneCb cb) : cb_(cb) { explicit StreamReq(DoneCb cb) : cb_(cb) {
} }
inline void Done(int status) { inline void Done(int status, const char* error_str = nullptr) {
cb_(static_cast<Req*>(this), status); Req* req = static_cast<Req*>(this);
Environment* env = req->env();
if (error_str != nullptr) {
req->object()->Set(env->error_string(),
OneByteString(env->isolate(), error_str));
}
cb_(req, status);
} }
private: private:

22
src/tls_wrap.cc

@ -92,7 +92,7 @@ void TLSWrap::MakePending() {
} }
bool TLSWrap::InvokeQueued(int status) { bool TLSWrap::InvokeQueued(int status, const char* error_str) {
if (pending_write_items_.IsEmpty()) if (pending_write_items_.IsEmpty())
return false; return false;
@ -100,7 +100,7 @@ bool TLSWrap::InvokeQueued(int status) {
WriteItemList queue; WriteItemList queue;
pending_write_items_.MoveBack(&queue); pending_write_items_.MoveBack(&queue);
while (WriteItem* wi = queue.PopFront()) { while (WriteItem* wi = queue.PopFront()) {
wi->w_->Done(status); wi->w_->Done(status, error_str);
delete wi; delete wi;
} }
@ -484,11 +484,12 @@ bool TLSWrap::ClearIn() {
// Error or partial write // Error or partial write
int err; int err;
Local<Value> arg = GetSSLError(written, &err, &error_); const char* error_str = nullptr;
Local<Value> arg = GetSSLError(written, &err, &error_str);
if (!arg.IsEmpty()) { if (!arg.IsEmpty()) {
MakePending(); MakePending();
if (!InvokeQueued(UV_EPROTO)) InvokeQueued(UV_EPROTO, error_str);
ClearError(); delete[] error_str;
clear_in_->Reset(); clear_in_->Reset();
} }
@ -589,8 +590,15 @@ int TLSWrap::DoWrite(WriteWrap* w,
return 0; return 0;
} }
if (ssl_ == nullptr) if (ssl_ == nullptr) {
ClearError();
static char msg[] = "Write after DestroySSL";
char* tmp = new char[sizeof(msg)];
memcpy(tmp, msg, sizeof(msg));
error_ = tmp;
return UV_EPROTO; return UV_EPROTO;
}
crypto::MarkPopErrorOnReturn mark_pop_error_on_return; crypto::MarkPopErrorOnReturn mark_pop_error_on_return;
@ -775,7 +783,7 @@ void TLSWrap::DestroySSL(const FunctionCallbackInfo<Value>& args) {
wrap->MakePending(); wrap->MakePending();
// And destroy // And destroy
wrap->InvokeQueued(UV_ECANCELED); wrap->InvokeQueued(UV_ECANCELED, "Canceled because of SSL destruction");
// Destroy the SSL structure and friends // Destroy the SSL structure and friends
wrap->SSLWrap<TLSWrap>::DestroySSL(); wrap->SSLWrap<TLSWrap>::DestroySSL();

2
src/tls_wrap.h

@ -89,7 +89,7 @@ class TLSWrap : public AsyncWrap,
bool ClearIn(); bool ClearIn();
void ClearOut(); void ClearOut();
void MakePending(); void MakePending();
bool InvokeQueued(int status); bool InvokeQueued(int status, const char* error_str = nullptr);
inline void Cycle() { inline void Cycle() {
// Prevent recursion // Prevent recursion

29
test/parallel/test-tls-junk-server.js

@ -0,0 +1,29 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto) {
console.log('1..0 # Skipped: missing crypto');
return;
}
const assert = require('assert');
const https = require('https');
const net = require('net');
const server = net.createServer(function(s) {
s.once('data', function() {
s.end('I was waiting for you, hello!', function() {
s.destroy();
});
});
});
server.listen(common.PORT, function() {
const req = https.request({ port: common.PORT });
req.end();
req.once('error', common.mustCall(function(err) {
assert(/unknown protocol/.test(err.message));
server.close();
}));
});
Loading…
Cancel
Save