Skip to content

Commit

Permalink
Merge pull request #49 from byu-imaal/kl/support-node8
Browse files Browse the repository at this point in the history
support node8 by including require('url').URL (fix #48, fix #42)
  • Loading branch information
kimbo committed Jul 16, 2020
2 parents ad97938 + 971c848 commit 736a369
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

strategy:
matrix:
node-version: [10.x, 12.x]
node-version: [8.x, 10.x, 12.x]

steps:
- uses: actions/checkout@v2
Expand Down
9 changes: 7 additions & 2 deletions examples/basic/resolver.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<title>dohjs example</title>

<!-- Load dohjs -->
<script src="https://cdn.jsdelivr.net/npm/dohjs@latest/dist/doh.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dohjs@latest/dist/doh.js"></script>
</head>
<body>
<table>
Expand All @@ -33,6 +33,10 @@
<td>Request method</td>
<td><input type="text" id="method" value="GET"></td>
</tr>
<tr>
<td>Timeout (ms)</td>
<td><input type="number" id="timeout" value="1000"></td>
</tr>
</table>

<input type="button" id="send-query" value="Send query">
Expand All @@ -46,13 +50,14 @@
const qname = document.getElementById('qname').value || '.';
const qtype = document.getElementById('qtype').value || 'A';
const method = document.getElementById('method').value || 'POST';
const timeout = parseInt(document.getElementById('timeout').value) || 1000;
const url = document.getElementById('url').value;
if (!url) {
alert('You forgot to provide a URL!');
return;
}
const resolver = new doh.DohResolver(url);
resolver.query(qname, qtype, method)
resolver.query(qname, qtype, method, null, timeout)
.then(response => {
document.getElementById('output').innerHTML = JSON.stringify(response, null, 4);
})
Expand Down
29 changes: 18 additions & 11 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const dnsPacket = require('dns-packet');
const https = require('https');
const http = require('http');
const base32Encode = require('base32-encode')
const base32Encode = require('base32-encode');
var URL = require('url').URL;
if (typeof window !== "undefined") {
URL = window.URL;
}

/**
* Allowed request methods for sending DNS over HTTPS requests.
Expand Down Expand Up @@ -72,7 +76,7 @@ resolver.query('example.com', 'A')
* @throws {MethodNotAllowedError} If the method is not allowed (i.e. if it's not "GET" or "POST"), a MethodNotAllowedError will be thrown.
* @returns {Promise<object>} The DNS response received
*/
query(qname, qtype='A', method='POST', headers=null, timeout) {
query(qname, qtype='A', method='POST', headers=null, timeout=null) {
return new Promise((resolve, reject) => {
if (!isMethodAllowed(method)) {
return reject(new MethodNotAllowedError(`Request method ${method} not allowed. Must be either 'GET' or 'POST'`))
Expand Down Expand Up @@ -152,7 +156,7 @@ function makeQuery(qname, qtype='A') {
*/
function sendDohMsg(packet, url, method, headers, timeout) {
return new Promise((resolve, reject) => {
const transportModule = url.startsWith('https://') ? https : http;
const transport = url.startsWith('https://') ? https : http;
const buf = dnsPacket.encode(packet);
let requestOptions;
if (!headers) {
Expand All @@ -178,11 +182,9 @@ function sendDohMsg(packet, url, method, headers, timeout) {
path: url.pathname + url.search,
headers: headers
};
if (timeout) {
requestOptions.timeout = timeout;
}
let data;
const request = transportModule.request(requestOptions, (response) => {
let timer;
const request = transport.request(requestOptions, (response) => {
response.on('data', (d) => {
if (!data) {
data = d;
Expand All @@ -191,6 +193,9 @@ function sendDohMsg(packet, url, method, headers, timeout) {
}
});
response.on('end', () => {
if (timer) {
clearTimeout(timer);
}
const decoded = dnsPacket.decode(data);
resolve(decoded);
});
Expand All @@ -199,10 +204,12 @@ function sendDohMsg(packet, url, method, headers, timeout) {
request.abort();
return reject(err);
});
request.on('timeout', () => {
request.abort();
return reject(`Query timed out after ${timeout} milliseconds`);
});
if (timeout) {
timer = setTimeout(() => {
request.abort();
return reject(`Query timed out after ${timeout} milliseconds of inactivity`);
}, timeout);
}
if (method === 'POST') {
request.write(buf)
}
Expand Down
68 changes: 35 additions & 33 deletions lib/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,58 +22,60 @@ test('DNS query message for example.com matches expected', () => {
questions: [ { type: 'A', name: 'example.com' } ]});
});

test('sendDohMsg() works (and the example.com zone still has an A record)', () => {
test('sendDohMsg() works (and the example.com zone still has an A record)', async () => {
let msg = makeQuery('example.com', 'A');
sendDohMsg(msg, 'https://1.1.1.1/dns-query', 'GET')
.then(response => {
expect(response).toHaveProperty('answers');
})
.catch(err => {
throw err;
});
try {
let response = await sendDohMsg(msg, 'https://1.1.1.1/dns-query', 'GET');
expect(response).toHaveProperty('answers');
} catch(e) {
throw e;
}
});

test('DohResolver should be created', () => {
expect(new DohResolver("https://example.com/dns-query")).toBeTruthy()
expect(new DohResolver("https://example.com/dns-query")).toBeTruthy();
});

test('DohResolver should have assigned nameserver url', () => {
expect(new DohResolver("https://example.com/dns-query").nameserver_url).toEqual("https://example.com/dns-query")
expect(new DohResolver("https://example.com/dns-query").nameserver_url).toEqual("https://example.com/dns-query");
});

test('PUT is not a valid request method', () => {
expect(isMethodAllowed('PUT')).toBeFalsy()
expect(isMethodAllowed('PUT')).toBeFalsy();
});

test('Resolving with invalid methods causes error', () => {
test('Resolving with invalid methods causes error', async () => {
const resolver = new DohResolver("https://dns.google/dns-query");
resolver.query('example.com', 'A', 'PUT')
.then(console.log)
.catch(err => {
expect(err).toBeInstanceOf(MethodNotAllowedError);
});
try {
await resolver.query('example.com', 'A', 'PUT');
} catch (e) {
console.log('[INFO] got error:', e);
expect(e).toBeInstanceOf(MethodNotAllowedError);
return;
}
throw new Error('test succeeded with PUT method, want it to fail with MethodNotAllowedError');
});

test('DohResolver.query() for example.com TXT contains answers', () => {
test('DohResolver.query() for example.com TXT contains answers', async () => {
const resolver = new DohResolver("https://dns.google/dns-query");
resolver.query('example.com', 'TXT')
.then(response => {
expect(response).toHaveProperty('answers')
})
.catch(err => {
try {
let response = await resolver.query('example.com', 'TXT');
expect(response).toHaveProperty('answers');
} catch(err) {
throw err;
});
}
});

test('timeout works properly (and cloudflare doesn\'t respond within 1 millisecond)', () => {
let msg = makeQuery('example.com');
sendDohMsg(msg, 'https://1.1.1.1/dns-query', 'GET', null, 1)
.then(ans => {
throw Error("Test should have failed");
})
.catch(err => {
expect(err).toMatch(/.*timed out.*/);
});
test('timeout works properly (and cloudflare doesn\'t respond within 1 millisecond)', async () => {
let msg = makeQuery('example.org');
try {
await sendDohMsg(msg, 'https://1.1.1.1/dns-query', 'GET', null, 1)
} catch (e) {
console.log('[INFO] got error:', e);
expect(e.toString()).toMatch(/.*timed out.*/);
return;
}
throw new Error("sendDohMsg succeeded, wanted it to time out");
});

test('dnsPacket is exposed in dohjs', () => {
Expand Down
10 changes: 4 additions & 6 deletions test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#!/usr/bin/env bash

# exit if anything fails
set -e

# run integrated tests
jest

Expand All @@ -11,13 +8,14 @@ echo -e "\nRunning command line tests...\n"

doh_bin="./bin/doh.js"
doh_test() {
printf "Running \"$doh_bin $*\"..."
output=$("$doh_bin" $@ 2>&1)
exit_code="$?"
if [ "$exit_code" -eq 0 ]; then
echo "Command \"$doh_bin $@\" PASSED"
printf "PASSED ✔️\n"
else
echo -e "Command \"$doh_bin $@\" FAILED"
echo -e "OUTPUT:\n$output" >&2
echo -e "FAILED"
echo -e "OUTPUT:\n$output"
exit "$exit_code"
fi
}
Expand Down

0 comments on commit 736a369

Please sign in to comment.