dns: fix c-ares error reporting regression
authorBen Noordhuis <info@bnoordhuis.nl>
Thu, 19 Sep 2013 04:38:37 +0000 (06:38 +0200)
committerTimothy J Fontaine <tjfontaine@gmail.com>
Fri, 20 Sep 2013 16:39:14 +0000 (09:39 -0700)
The test case from the previous commit exposed a regression in the way
that c-ares errors are reported to JS land.  Said regression was
introduced in commit 756b622 ("src: add multi-context support").

Fixes the following test failure:

    $ out/Release/node test/simple/test-dns-regress-6244
    util.js:675
      var errname = uv.errname(err);
                       ^
    Error: err >= 0
        at Object.exports._errnoException (util.js:675:20)
        at errnoException (dns.js:43:15)
        at Object.onresolve [as oncomplete] (dns.js:145:19)

lib/dns.js erroneously assumed that the error code was a libuv error
code when it's really a c-ares status code.  Libuv handles getaddrinfo()
style lookups (which is by far the most common type of lookup), that's
why this bug wasn't discovered earlier.

lib/dns.js
src/cares_wrap.cc

index dd27482..3e4b90f 100644 (file)
@@ -34,9 +34,12 @@ function errnoException(err, syscall) {
   if (err === uv.UV_EAI_MEMORY ||
       err === uv.UV_EAI_NODATA ||
       err === uv.UV_EAI_NONAME) {
-    var ex = new Error(syscall + ' ENOTFOUND');
-    ex.code = 'ENOTFOUND';
-    ex.errno = 'ENOTFOUND';
+    err = 'ENOTFOUND';
+  }
+  if (typeof err === 'string') {  // c-ares error code.
+    var ex = new Error(syscall + ' ' + err);
+    ex.code = err;
+    ex.errno = err;
     ex.syscall = syscall;
     return ex;
   }
index 0023878..fd25a29 100644 (file)
@@ -313,14 +313,42 @@ class QueryWrap {
     assert(status != ARES_SUCCESS);
     Context::Scope context_scope(env()->context());
     HandleScope handle_scope(env()->isolate());
-    Local<Value> argv[] = {
-      Integer::New(status, env()->isolate())
-    };
-    MakeCallback(env(),
-                 object(),
-                 env()->oncomplete_string(),
-                 ARRAY_SIZE(argv),
-                 argv);
+    Local<Value> arg;
+    switch (status) {
+#define V(code)                                                               \
+      case ARES_ ## code:                                                     \
+        arg = FIXED_ONE_BYTE_STRING(env()->isolate(), #code);                 \
+        break;
+      V(ENODATA)
+      V(EFORMERR)
+      V(ESERVFAIL)
+      V(ENOTFOUND)
+      V(ENOTIMP)
+      V(EREFUSED)
+      V(EBADQUERY)
+      V(EBADNAME)
+      V(EBADFAMILY)
+      V(EBADRESP)
+      V(ECONNREFUSED)
+      V(ETIMEOUT)
+      V(EOF)
+      V(EFILE)
+      V(ENOMEM)
+      V(EDESTRUCTION)
+      V(EBADSTR)
+      V(EBADFLAGS)
+      V(ENONAME)
+      V(EBADHINTS)
+      V(ENOTINITIALIZED)
+      V(ELOADIPHLPAPI)
+      V(EADDRGETNETWORKPARAMS)
+      V(ECANCELLED)
+#undef V
+      default:
+        arg = FIXED_ONE_BYTE_STRING(env()->isolate(), "UNKNOWN_ARES_ERROR");
+        break;
+    }
+    MakeCallback(env(), object(), env()->oncomplete_string(), 1, &arg);
   }
 
   // Subclasses should implement the appropriate Parse method.