Skip to content

Commit fd8c8f0

Browse files
committed
address review feedback
1 parent 2e05248 commit fd8c8f0

3 files changed

Lines changed: 29 additions & 27 deletions

File tree

packet.js

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ Packet.prototype.toBuffer = function(writer) {
263263
]).forEach(function(def) {
264264
const section = def[0];
265265
const Encoder = def[1];
266-
(this[section] || []).map(function(resource) {
267-
return Encoder.encode(resource, writer);
266+
(this[section] || []).forEach(function(resource) {
267+
Encoder.encode(resource, writer);
268268
});
269269
}.bind(this));
270270
return writer.toBuffer();
@@ -400,11 +400,12 @@ Packet.Question.decode = function(reader) {
400400
};
401401

402402
Packet.Question.encode = function(question, writer) {
403+
const ownsWriter = !writer;
403404
writer = writer || new Packet.Writer();
404405
Packet.Name.encode(question.name, writer);
405406
writer.write(question.type, 16);
406407
writer.write(question.class, 16);
407-
return writer.toBuffer();
408+
return ownsWriter ? writer.toBuffer() : undefined;
408409
};
409410

410411
/**
@@ -572,6 +573,10 @@ Packet.Name = {
572573
return name.join('.');
573574
},
574575
encode: function(domain, writer) {
576+
// Only materialize a Buffer when we created the writer; if the caller
577+
// passed one, they own the final toBuffer() and we avoid an O(buffer)
578+
// materialization per name (a big deal once many records share a suffix).
579+
const ownsWriter = !writer;
575580
writer = writer || new Packet.Writer();
576581
const parts = (domain || '').split('.').filter(part => !!part);
577582
let totalOctets = 1; // root terminator
@@ -598,7 +603,7 @@ Packet.Name = {
598603
const suffix = parts.slice(i).join('.').toLowerCase();
599604
if (compress && writer.names.has(suffix)) {
600605
writer.write(0xC000 | writer.names.get(suffix), 16);
601-
return writer.toBuffer();
606+
return ownsWriter ? writer.toBuffer() : undefined;
602607
}
603608
if (compress) {
604609
const byteOffset = writer.byteLength();
@@ -610,7 +615,7 @@ Packet.Name = {
610615
}
611616
}
612617
writer.write(0, 8);
613-
return writer.toBuffer();
618+
return ownsWriter ? writer.toBuffer() : undefined;
614619
},
615620
};
616621

@@ -629,10 +634,11 @@ Packet.Resource.A = function(address) {
629634
Packet.Resource.A.encode = function(record, writer) {
630635
writer = writer || new Packet.Writer();
631636
// RDLENGTH is written by Packet.Resource.encode; only emit the rdata here.
637+
// No toBuffer() — the caller owns materialization (avoids O(N) re-walks of
638+
// the message bit-array per record).
632639
record.address.split('.').forEach(function(part) {
633640
writer.write(parseInt(part, 10), 8);
634641
});
635-
return writer.toBuffer();
636642
};
637643

638644
Packet.Resource.A.decode = function(reader, length) {
@@ -665,7 +671,6 @@ Packet.Resource.MX.encode = function(record, writer) {
665671
writer = writer || new Packet.Writer();
666672
writer.write(record.priority, 16);
667673
Packet.Name.encode(record.exchange, writer);
668-
return writer.toBuffer();
669674
};
670675
/**
671676
* [decode description]
@@ -698,7 +703,6 @@ Packet.Resource.AAAA = {
698703
fromIPv6(record.address).forEach(function(part) {
699704
writer.write(parseInt(part, 16), 16);
700705
});
701-
return writer.toBuffer();
702706
},
703707
};
704708
/**
@@ -714,7 +718,6 @@ Packet.Resource.NS = {
714718
encode: function(record, writer) {
715719
writer = writer || new Packet.Writer();
716720
Packet.Name.encode(record.ns, writer);
717-
return writer.toBuffer();
718721
},
719722
};
720723
/**
@@ -731,7 +734,6 @@ Packet.Resource.CNAME = {
731734
encode: function(record, writer) {
732735
writer = writer || new Packet.Writer();
733736
Packet.Name.encode(record.domain, writer);
734-
return writer.toBuffer();
735737
},
736738
};
737739
/**
@@ -784,8 +786,6 @@ Packet.Resource.TXT = {
784786
writer.write(c, 8);
785787
});
786788
});
787-
788-
return writer.toBuffer();
789789
},
790790
};
791791
/**
@@ -814,7 +814,6 @@ Packet.Resource.SOA = {
814814
writer.write(record.expiration, 32);
815815
// RFC 2308 §4: the SOA minimum field is also a TTL; same 31-bit ceiling.
816816
writer.write(Math.min(record.minimum >>> 0, 0x7FFFFFFF), 32);
817-
return writer.toBuffer();
818817
},
819818
};
820819
/**
@@ -836,7 +835,6 @@ Packet.Resource.SRV = {
836835
writer.write(record.weight, 16);
837836
writer.write(record.port, 16);
838837
Packet.Name.encode(record.target, writer);
839-
return writer.toBuffer();
840838
},
841839
};
842840

@@ -921,7 +919,6 @@ Packet.Resource.EDNS.encode = function(record, writer) {
921919
debug('node-dns > unknown EDNS rdata encoder %s(%j)', encoder, rdata.ednsCode);
922920
}
923921
}
924-
return writer.toBuffer();
925922
};
926923

927924
Packet.Resource.EDNS.ECS = function(clientIp) {
@@ -1024,7 +1021,6 @@ Packet.Resource.CAA = {
10241021
buffer.forEach(function(c) {
10251022
writer.write(c, 8);
10261023
});
1027-
return writer.toBuffer();
10281024
},
10291025
decode: function(reader, length) {
10301026
this.flags = reader.read(8);
@@ -1083,7 +1079,6 @@ Packet.Resource.DNSKEY = {
10831079
buffer.forEach(function(c) {
10841080
writer.write(c, 8);
10851081
});
1086-
return writer.toBuffer();
10871082
},
10881083
};
10891084

server/tcp.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ function readPipelinedMessages(socket, state, onMessage, onError) {
158158

159159
// Read and consume the PROXY header from the front of the socket's stream.
160160
// Any bytes that arrive past the header are unshifted back into the socket
161-
// so the next reader (Packet.readStream) sees them.
161+
// so the pipelined message reader (readPipelinedMessages) sees them in its
162+
// initial drain.
162163
function consumeProxyHeader(socket) {
163164
return new Promise((resolve, reject) => {
164165
const chunks = [];

test/server.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -586,12 +586,14 @@ test('server/doh#GET with Accept: */* is accepted (RFC 8484 §4.1)', async() =>
586586

587587
test('server/doh#POST 415 on missing or wrong Content-Type (RFC 8484 §4.1)', async() => {
588588
const server = createDOHServer();
589+
const requestErrors = [];
589590
server.on('request', (request, send) => send(Packet.createResponseFromRequest(request)));
591+
server.on('requestError', e => requestErrors.push(e));
590592
const { port } = await new Promise(resolve => {
591593
server.on('listening', resolve);
592594
server.listen();
593595
});
594-
const sendPost = contentType => new Promise((resolve, reject) => {
596+
const sendPost = (contentType, body = Buffer.alloc(12)) => new Promise((resolve, reject) => {
595597
const headers = { accept: 'application/dns-message' };
596598
if (contentType) headers['content-type'] = contentType;
597599
const req = http.request({
@@ -600,14 +602,18 @@ test('server/doh#POST 415 on missing or wrong Content-Type (RFC 8484 §4.1)', as
600602
path : '/dns-query',
601603
method : 'POST',
602604
headers,
603-
}, res => resolve(res.statusCode));
604-
req.on('error', reject);
605-
req.end(Buffer.alloc(12));
606-
});
607-
assert.equal(await sendPost(undefined), 415, 'missing Content-Type');
608-
assert.equal(await sendPost('application/json'), 415, 'wrong Content-Type');
609-
// Sanity: with the correct Content-Type a malformed body still surfaces as
610-
// a server-side parse error (the connection is destroyed), not 415.
605+
}, res => resolve({ status: res.statusCode }));
606+
req.on('error', err => resolve({ error: err }));
607+
req.end(body);
608+
});
609+
assert.equal((await sendPost(undefined)).status, 415, 'missing Content-Type');
610+
assert.equal((await sendPost('application/json')).status, 415, 'wrong Content-Type');
611+
// With the correct Content-Type the 415 check passes, so a body too short
612+
// for a DNS header surfaces as a server-side parse error (handler destroys
613+
// the connection); the client sees a socket-level error, not a 415.
614+
const malformed = await sendPost('application/dns-message', Buffer.alloc(0));
615+
assert.ok(malformed.error, 'malformed body should fail at the socket, not return 415');
616+
assert.ok(requestErrors.length >= 1, 'requestError should have fired for the malformed body');
611617
server.close();
612618
});
613619

0 commit comments

Comments
 (0)