pg 8.0.2 → 8.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/connection.js CHANGED
@@ -11,11 +11,9 @@ var net = require('net')
11
11
  var EventEmitter = require('events').EventEmitter
12
12
  var util = require('util')
13
13
 
14
- var Writer = require('buffer-writer')
15
- var Reader = require('packet-reader')
14
+ const { parse, serialize } = require('pg-protocol')
16
15
 
17
- var TEXT_MODE = 0
18
- var BINARY_MODE = 1
16
+ // TODO(bmc) support binary mode at some point
19
17
  var Connection = function (config) {
20
18
  EventEmitter.call(this)
21
19
  config = config || {}
@@ -23,20 +21,10 @@ var Connection = function (config) {
23
21
  this._keepAlive = config.keepAlive
24
22
  this._keepAliveInitialDelayMillis = config.keepAliveInitialDelayMillis
25
23
  this.lastBuffer = false
26
- this.lastOffset = 0
27
- this.buffer = null
28
- this.offset = null
29
- this.encoding = config.encoding || 'utf8'
30
24
  this.parsedStatements = {}
31
- this.writer = new Writer()
32
25
  this.ssl = config.ssl || false
33
26
  this._ending = false
34
- this._mode = TEXT_MODE
35
27
  this._emitMessage = false
36
- this._reader = new Reader({
37
- headerSize: 1,
38
- lengthPadding: -4
39
- })
40
28
  var self = this
41
29
  this.on('newListener', function (eventName) {
42
30
  if (eventName === 'message') {
@@ -50,13 +38,11 @@ util.inherits(Connection, EventEmitter)
50
38
  Connection.prototype.connect = function (port, host) {
51
39
  var self = this
52
40
 
53
- if (this.stream.readyState === 'closed') {
54
- this.stream.connect(port, host)
55
- } else if (this.stream.readyState === 'open') {
56
- this.emit('connect')
57
- }
41
+ this._connecting = true
42
+ this.stream.setNoDelay(true)
43
+ this.stream.connect(port, host)
58
44
 
59
- this.stream.on('connect', function () {
45
+ this.stream.once('connect', function () {
60
46
  if (self._keepAlive) {
61
47
  self.stream.setKeepAlive(true, self._keepAliveInitialDelayMillis)
62
48
  }
@@ -88,608 +74,140 @@ Connection.prototype.connect = function (port, host) {
88
74
  case 'N': // Server does not support SSL connections
89
75
  self.stream.end()
90
76
  return self.emit('error', new Error('The server does not support SSL connections'))
91
- default: // Any other response byte, including 'E' (ErrorResponse) indicating a server error
77
+ default:
78
+ // Any other response byte, including 'E' (ErrorResponse) indicating a server error
92
79
  self.stream.end()
93
80
  return self.emit('error', new Error('There was an error establishing an SSL connection'))
94
81
  }
95
82
  var tls = require('tls')
96
- const options = Object.assign({
97
- socket: self.stream
98
- }, self.ssl)
83
+ const options = Object.assign(
84
+ {
85
+ socket: self.stream,
86
+ },
87
+ self.ssl
88
+ )
99
89
  if (net.isIP(host) === 0) {
100
90
  options.servername = host
101
91
  }
102
92
  self.stream = tls.connect(options)
103
- self.stream.on('error', reportStreamError)
104
93
  self.attachListeners(self.stream)
94
+ self.stream.on('error', reportStreamError)
95
+
105
96
  self.emit('sslconnect')
106
97
  })
107
98
  }
108
99
 
109
100
  Connection.prototype.attachListeners = function (stream) {
110
- var self = this
111
- stream.on('data', function (buff) {
112
- self._reader.addChunk(buff)
113
- var packet = self._reader.read()
114
- while (packet) {
115
- var msg = self.parseMessage(packet)
116
- var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
117
- if (self._emitMessage) {
118
- self.emit('message', msg)
119
- }
120
- self.emit(eventName, msg)
121
- packet = self._reader.read()
122
- }
101
+ stream.on('end', () => {
102
+ this.emit('end')
123
103
  })
124
- stream.on('end', function () {
125
- self.emit('end')
104
+ parse(stream, (msg) => {
105
+ var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
106
+ if (this._emitMessage) {
107
+ this.emit('message', msg)
108
+ }
109
+ this.emit(eventName, msg)
126
110
  })
127
111
  }
128
112
 
129
113
  Connection.prototype.requestSsl = function () {
130
- var bodyBuffer = this.writer
131
- .addInt16(0x04D2)
132
- .addInt16(0x162F).flush()
133
-
134
- var length = bodyBuffer.length + 4
135
-
136
- var buffer = new Writer()
137
- .addInt32(length)
138
- .add(bodyBuffer)
139
- .join()
140
- this.stream.write(buffer)
114
+ this.stream.write(serialize.requestSsl())
141
115
  }
142
116
 
143
117
  Connection.prototype.startup = function (config) {
144
- var writer = this.writer
145
- .addInt16(3)
146
- .addInt16(0)
147
-
148
- Object.keys(config).forEach(function (key) {
149
- var val = config[key]
150
- writer.addCString(key).addCString(val)
151
- })
152
-
153
- writer.addCString('client_encoding').addCString("'utf-8'")
154
-
155
- var bodyBuffer = writer.addCString('').flush()
156
- // this message is sent without a code
157
-
158
- var length = bodyBuffer.length + 4
159
-
160
- var buffer = new Writer()
161
- .addInt32(length)
162
- .add(bodyBuffer)
163
- .join()
164
- this.stream.write(buffer)
118
+ this.stream.write(serialize.startup(config))
165
119
  }
166
120
 
167
121
  Connection.prototype.cancel = function (processID, secretKey) {
168
- var bodyBuffer = this.writer
169
- .addInt16(1234)
170
- .addInt16(5678)
171
- .addInt32(processID)
172
- .addInt32(secretKey)
173
- .flush()
174
-
175
- var length = bodyBuffer.length + 4
176
-
177
- var buffer = new Writer()
178
- .addInt32(length)
179
- .add(bodyBuffer)
180
- .join()
181
- this.stream.write(buffer)
122
+ this._send(serialize.cancel(processID, secretKey))
182
123
  }
183
124
 
184
125
  Connection.prototype.password = function (password) {
185
- // 0x70 = 'p'
186
- this._send(0x70, this.writer.addCString(password))
126
+ this._send(serialize.password(password))
187
127
  }
188
128
 
189
129
  Connection.prototype.sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
190
- // 0x70 = 'p'
191
- this.writer
192
- .addCString(mechanism)
193
- .addInt32(Buffer.byteLength(initialResponse))
194
- .addString(initialResponse)
195
-
196
- this._send(0x70)
130
+ this._send(serialize.sendSASLInitialResponseMessage(mechanism, initialResponse))
197
131
  }
198
132
 
199
133
  Connection.prototype.sendSCRAMClientFinalMessage = function (additionalData) {
200
- // 0x70 = 'p'
201
- this.writer
202
- .addString(additionalData)
203
-
204
- this._send(0x70)
134
+ this._send(serialize.sendSCRAMClientFinalMessage(additionalData))
205
135
  }
206
136
 
207
- Connection.prototype._send = function (code, more) {
137
+ Connection.prototype._send = function (buffer) {
208
138
  if (!this.stream.writable) {
209
139
  return false
210
140
  }
211
- if (more === true) {
212
- this.writer.addHeader(code)
213
- } else {
214
- return this.stream.write(this.writer.flush(code))
215
- }
141
+ return this.stream.write(buffer)
216
142
  }
217
143
 
218
144
  Connection.prototype.query = function (text) {
219
- // 0x51 = Q
220
- this.stream.write(this.writer.addCString(text).flush(0x51))
145
+ this._send(serialize.query(text))
221
146
  }
222
147
 
223
148
  // send parse message
224
- // "more" === true to buffer the message until flush() is called
225
- Connection.prototype.parse = function (query, more) {
226
- // expect something like this:
227
- // { name: 'queryName',
228
- // text: 'select * from blah',
229
- // types: ['int8', 'bool'] }
230
-
231
- // normalize missing query names to allow for null
232
- query.name = query.name || ''
233
- if (query.name.length > 63) {
234
- /* eslint-disable no-console */
235
- console.error('Warning! Postgres only supports 63 characters for query names.')
236
- console.error('You supplied %s (%s)', query.name, query.name.length)
237
- console.error('This can cause conflicts and silent errors executing queries')
238
- /* eslint-enable no-console */
239
- }
240
- // normalize null type array
241
- query.types = query.types || []
242
- var len = query.types.length
243
- var buffer = this.writer
244
- .addCString(query.name) // name of query
245
- .addCString(query.text) // actual query text
246
- .addInt16(len)
247
- for (var i = 0; i < len; i++) {
248
- buffer.addInt32(query.types[i])
249
- }
250
-
251
- var code = 0x50
252
- this._send(code, more)
149
+ Connection.prototype.parse = function (query) {
150
+ this._send(serialize.parse(query))
253
151
  }
254
152
 
255
153
  // send bind message
256
154
  // "more" === true to buffer the message until flush() is called
257
- Connection.prototype.bind = function (config, more) {
258
- // normalize config
259
- config = config || {}
260
- config.portal = config.portal || ''
261
- config.statement = config.statement || ''
262
- config.binary = config.binary || false
263
- var values = config.values || []
264
- var len = values.length
265
- var useBinary = false
266
- for (var j = 0; j < len; j++) { useBinary |= values[j] instanceof Buffer }
267
- var buffer = this.writer
268
- .addCString(config.portal)
269
- .addCString(config.statement)
270
- if (!useBinary) { buffer.addInt16(0) } else {
271
- buffer.addInt16(len)
272
- for (j = 0; j < len; j++) { buffer.addInt16(values[j] instanceof Buffer) }
273
- }
274
- buffer.addInt16(len)
275
- for (var i = 0; i < len; i++) {
276
- var val = values[i]
277
- if (val === null || typeof val === 'undefined') {
278
- buffer.addInt32(-1)
279
- } else if (val instanceof Buffer) {
280
- buffer.addInt32(val.length)
281
- buffer.add(val)
282
- } else {
283
- buffer.addInt32(Buffer.byteLength(val))
284
- buffer.addString(val)
285
- }
286
- }
287
-
288
- if (config.binary) {
289
- buffer.addInt16(1) // format codes to use binary
290
- buffer.addInt16(1)
291
- } else {
292
- buffer.addInt16(0) // format codes to use text
293
- }
294
- // 0x42 = 'B'
295
- this._send(0x42, more)
155
+ Connection.prototype.bind = function (config) {
156
+ this._send(serialize.bind(config))
296
157
  }
297
158
 
298
159
  // send execute message
299
160
  // "more" === true to buffer the message until flush() is called
300
- Connection.prototype.execute = function (config, more) {
301
- config = config || {}
302
- config.portal = config.portal || ''
303
- config.rows = config.rows || ''
304
- this.writer
305
- .addCString(config.portal)
306
- .addInt32(config.rows)
307
-
308
- // 0x45 = 'E'
309
- this._send(0x45, more)
161
+ Connection.prototype.execute = function (config) {
162
+ this._send(serialize.execute(config))
310
163
  }
311
164
 
312
- var emptyBuffer = Buffer.alloc(0)
313
-
165
+ const flushBuffer = serialize.flush()
314
166
  Connection.prototype.flush = function () {
315
- // 0x48 = 'H'
316
- this.writer.add(emptyBuffer)
317
- this._send(0x48)
167
+ if (this.stream.writable) {
168
+ this.stream.write(flushBuffer)
169
+ }
318
170
  }
319
171
 
172
+ const syncBuffer = serialize.sync()
320
173
  Connection.prototype.sync = function () {
321
- // clear out any pending data in the writer
322
- this.writer.flush(0)
323
-
324
- this.writer.add(emptyBuffer)
325
174
  this._ending = true
326
- this._send(0x53)
175
+ this._send(flushBuffer)
176
+ this._send(syncBuffer)
327
177
  }
328
178
 
329
- const END_BUFFER = Buffer.from([0x58, 0x00, 0x00, 0x00, 0x04])
179
+ const endBuffer = serialize.end()
330
180
 
331
181
  Connection.prototype.end = function () {
332
182
  // 0x58 = 'X'
333
- this.writer.add(emptyBuffer)
334
183
  this._ending = true
335
- if (!this.stream.writable) {
184
+ if (!this._connecting || !this.stream.writable) {
336
185
  this.stream.end()
337
186
  return
338
187
  }
339
- return this.stream.write(END_BUFFER, () => {
188
+ return this.stream.write(endBuffer, () => {
340
189
  this.stream.end()
341
190
  })
342
191
  }
343
192
 
344
- Connection.prototype.close = function (msg, more) {
345
- this.writer.addCString(msg.type + (msg.name || ''))
346
- this._send(0x43, more)
193
+ Connection.prototype.close = function (msg) {
194
+ this._send(serialize.close(msg))
347
195
  }
348
196
 
349
- Connection.prototype.describe = function (msg, more) {
350
- this.writer.addCString(msg.type + (msg.name || ''))
351
- this._send(0x44, more)
197
+ Connection.prototype.describe = function (msg) {
198
+ this._send(serialize.describe(msg))
352
199
  }
353
200
 
354
201
  Connection.prototype.sendCopyFromChunk = function (chunk) {
355
- this.stream.write(this.writer.add(chunk).flush(0x64))
202
+ this._send(serialize.copyData(chunk))
356
203
  }
357
204
 
358
205
  Connection.prototype.endCopyFrom = function () {
359
- this.stream.write(this.writer.add(emptyBuffer).flush(0x63))
206
+ this._send(serialize.copyDone())
360
207
  }
361
208
 
362
209
  Connection.prototype.sendCopyFail = function (msg) {
363
- // this.stream.write(this.writer.add(emptyBuffer).flush(0x66));
364
- this.writer.addCString(msg)
365
- this._send(0x66)
366
- }
367
-
368
- var Message = function (name, length) {
369
- this.name = name
370
- this.length = length
371
- }
372
-
373
- Connection.prototype.parseMessage = function (buffer) {
374
- this.offset = 0
375
- var length = buffer.length + 4
376
- switch (this._reader.header) {
377
- case 0x52: // R
378
- return this.parseR(buffer, length)
379
-
380
- case 0x53: // S
381
- return this.parseS(buffer, length)
382
-
383
- case 0x4b: // K
384
- return this.parseK(buffer, length)
385
-
386
- case 0x43: // C
387
- return this.parseC(buffer, length)
388
-
389
- case 0x5a: // Z
390
- return this.parseZ(buffer, length)
391
-
392
- case 0x54: // T
393
- return this.parseT(buffer, length)
394
-
395
- case 0x44: // D
396
- return this.parseD(buffer, length)
397
-
398
- case 0x45: // E
399
- return this.parseE(buffer, length)
400
-
401
- case 0x4e: // N
402
- return this.parseN(buffer, length)
403
-
404
- case 0x31: // 1
405
- return new Message('parseComplete', length)
406
-
407
- case 0x32: // 2
408
- return new Message('bindComplete', length)
409
-
410
- case 0x33: // 3
411
- return new Message('closeComplete', length)
412
-
413
- case 0x41: // A
414
- return this.parseA(buffer, length)
415
-
416
- case 0x6e: // n
417
- return new Message('noData', length)
418
-
419
- case 0x49: // I
420
- return new Message('emptyQuery', length)
421
-
422
- case 0x73: // s
423
- return new Message('portalSuspended', length)
424
-
425
- case 0x47: // G
426
- return this.parseG(buffer, length)
427
-
428
- case 0x48: // H
429
- return this.parseH(buffer, length)
430
-
431
- case 0x57: // W
432
- return new Message('replicationStart', length)
433
-
434
- case 0x63: // c
435
- return new Message('copyDone', length)
436
-
437
- case 0x64: // d
438
- return this.parsed(buffer, length)
439
- }
440
- }
441
-
442
- Connection.prototype.parseR = function (buffer, length) {
443
- var code = this.parseInt32(buffer)
444
-
445
- var msg = new Message('authenticationOk', length)
446
-
447
- switch (code) {
448
- case 0: // AuthenticationOk
449
- return msg
450
- case 3: // AuthenticationCleartextPassword
451
- if (msg.length === 8) {
452
- msg.name = 'authenticationCleartextPassword'
453
- return msg
454
- }
455
- break
456
- case 5: // AuthenticationMD5Password
457
- if (msg.length === 12) {
458
- msg.name = 'authenticationMD5Password'
459
- msg.salt = Buffer.alloc(4)
460
- buffer.copy(msg.salt, 0, this.offset, this.offset + 4)
461
- this.offset += 4
462
- return msg
463
- }
464
-
465
- break
466
- case 10: // AuthenticationSASL
467
- msg.name = 'authenticationSASL'
468
- msg.mechanisms = []
469
- do {
470
- var mechanism = this.parseCString(buffer)
471
-
472
- if (mechanism) {
473
- msg.mechanisms.push(mechanism)
474
- }
475
- } while (mechanism)
476
-
477
- return msg
478
- case 11: // AuthenticationSASLContinue
479
- msg.name = 'authenticationSASLContinue'
480
- msg.data = this.readString(buffer, length - 4)
481
-
482
- return msg
483
- case 12: // AuthenticationSASLFinal
484
- msg.name = 'authenticationSASLFinal'
485
- msg.data = this.readString(buffer, length - 4)
486
-
487
- return msg
488
- }
489
-
490
- throw new Error('Unknown authenticationOk message type' + util.inspect(msg))
491
- }
492
-
493
- Connection.prototype.parseS = function (buffer, length) {
494
- var msg = new Message('parameterStatus', length)
495
- msg.parameterName = this.parseCString(buffer)
496
- msg.parameterValue = this.parseCString(buffer)
497
- return msg
498
- }
499
-
500
- Connection.prototype.parseK = function (buffer, length) {
501
- var msg = new Message('backendKeyData', length)
502
- msg.processID = this.parseInt32(buffer)
503
- msg.secretKey = this.parseInt32(buffer)
504
- return msg
505
- }
506
-
507
- Connection.prototype.parseC = function (buffer, length) {
508
- var msg = new Message('commandComplete', length)
509
- msg.text = this.parseCString(buffer)
510
- return msg
511
- }
512
-
513
- Connection.prototype.parseZ = function (buffer, length) {
514
- var msg = new Message('readyForQuery', length)
515
- msg.name = 'readyForQuery'
516
- msg.status = this.readString(buffer, 1)
517
- return msg
210
+ this._send(serialize.copyFail(msg))
518
211
  }
519
212
 
520
- var ROW_DESCRIPTION = 'rowDescription'
521
- Connection.prototype.parseT = function (buffer, length) {
522
- var msg = new Message(ROW_DESCRIPTION, length)
523
- msg.fieldCount = this.parseInt16(buffer)
524
- var fields = []
525
- for (var i = 0; i < msg.fieldCount; i++) {
526
- fields.push(this.parseField(buffer))
527
- }
528
- msg.fields = fields
529
- return msg
530
- }
531
-
532
- var Field = function () {
533
- this.name = null
534
- this.tableID = null
535
- this.columnID = null
536
- this.dataTypeID = null
537
- this.dataTypeSize = null
538
- this.dataTypeModifier = null
539
- this.format = null
540
- }
541
-
542
- var FORMAT_TEXT = 'text'
543
- var FORMAT_BINARY = 'binary'
544
- Connection.prototype.parseField = function (buffer) {
545
- var field = new Field()
546
- field.name = this.parseCString(buffer)
547
- field.tableID = this.parseInt32(buffer)
548
- field.columnID = this.parseInt16(buffer)
549
- field.dataTypeID = this.parseInt32(buffer)
550
- field.dataTypeSize = this.parseInt16(buffer)
551
- field.dataTypeModifier = this.parseInt32(buffer)
552
- if (this.parseInt16(buffer) === TEXT_MODE) {
553
- this._mode = TEXT_MODE
554
- field.format = FORMAT_TEXT
555
- } else {
556
- this._mode = BINARY_MODE
557
- field.format = FORMAT_BINARY
558
- }
559
- return field
560
- }
561
-
562
- var DATA_ROW = 'dataRow'
563
- var DataRowMessage = function (length, fieldCount) {
564
- this.name = DATA_ROW
565
- this.length = length
566
- this.fieldCount = fieldCount
567
- this.fields = []
568
- }
569
-
570
- // extremely hot-path code
571
- Connection.prototype.parseD = function (buffer, length) {
572
- var fieldCount = this.parseInt16(buffer)
573
- var msg = new DataRowMessage(length, fieldCount)
574
- for (var i = 0; i < fieldCount; i++) {
575
- msg.fields.push(this._readValue(buffer))
576
- }
577
- return msg
578
- }
579
-
580
- // extremely hot-path code
581
- Connection.prototype._readValue = function (buffer) {
582
- var length = this.parseInt32(buffer)
583
- if (length === -1) return null
584
- if (this._mode === TEXT_MODE) {
585
- return this.readString(buffer, length)
586
- }
587
- return this.readBytes(buffer, length)
588
- }
589
-
590
- // parses error
591
- Connection.prototype.parseE = function (buffer, length, isNotice) {
592
- var fields = {}
593
- var fieldType = this.readString(buffer, 1)
594
- while (fieldType !== '\0') {
595
- fields[fieldType] = this.parseCString(buffer)
596
- fieldType = this.readString(buffer, 1)
597
- }
598
-
599
- // the msg is an Error instance
600
- var msg = isNotice ? { message: fields.M } : new Error(fields.M)
601
-
602
- // for compatibility with Message
603
- msg.name = isNotice ? 'notice' : 'error'
604
- msg.length = length
605
-
606
- msg.severity = fields.S
607
- msg.code = fields.C
608
- msg.detail = fields.D
609
- msg.hint = fields.H
610
- msg.position = fields.P
611
- msg.internalPosition = fields.p
612
- msg.internalQuery = fields.q
613
- msg.where = fields.W
614
- msg.schema = fields.s
615
- msg.table = fields.t
616
- msg.column = fields.c
617
- msg.dataType = fields.d
618
- msg.constraint = fields.n
619
- msg.file = fields.F
620
- msg.line = fields.L
621
- msg.routine = fields.R
622
- return msg
623
- }
624
-
625
- // same thing, different name
626
- Connection.prototype.parseN = function (buffer, length) {
627
- var msg = this.parseE(buffer, length, true)
628
- msg.name = 'notice'
629
- return msg
630
- }
631
-
632
- Connection.prototype.parseA = function (buffer, length) {
633
- var msg = new Message('notification', length)
634
- msg.processId = this.parseInt32(buffer)
635
- msg.channel = this.parseCString(buffer)
636
- msg.payload = this.parseCString(buffer)
637
- return msg
638
- }
639
-
640
- Connection.prototype.parseG = function (buffer, length) {
641
- var msg = new Message('copyInResponse', length)
642
- return this.parseGH(buffer, msg)
643
- }
644
-
645
- Connection.prototype.parseH = function (buffer, length) {
646
- var msg = new Message('copyOutResponse', length)
647
- return this.parseGH(buffer, msg)
648
- }
649
-
650
- Connection.prototype.parseGH = function (buffer, msg) {
651
- var isBinary = buffer[this.offset] !== 0
652
- this.offset++
653
- msg.binary = isBinary
654
- var columnCount = this.parseInt16(buffer)
655
- msg.columnTypes = []
656
- for (var i = 0; i < columnCount; i++) {
657
- msg.columnTypes.push(this.parseInt16(buffer))
658
- }
659
- return msg
660
- }
661
-
662
- Connection.prototype.parsed = function (buffer, length) {
663
- var msg = new Message('copyData', length)
664
- msg.chunk = this.readBytes(buffer, msg.length - 4)
665
- return msg
666
- }
667
-
668
- Connection.prototype.parseInt32 = function (buffer) {
669
- var value = buffer.readInt32BE(this.offset)
670
- this.offset += 4
671
- return value
672
- }
673
-
674
- Connection.prototype.parseInt16 = function (buffer) {
675
- var value = buffer.readInt16BE(this.offset)
676
- this.offset += 2
677
- return value
678
- }
679
-
680
- Connection.prototype.readString = function (buffer, length) {
681
- return buffer.toString(this.encoding, this.offset, (this.offset += length))
682
- }
683
-
684
- Connection.prototype.readBytes = function (buffer, length) {
685
- return buffer.slice(this.offset, (this.offset += length))
686
- }
687
-
688
- Connection.prototype.parseCString = function (buffer) {
689
- var start = this.offset
690
- var end = buffer.indexOf(0, start)
691
- this.offset = end + 1
692
- return buffer.toString(this.encoding, start, end)
693
- }
694
- // end parsing methods
695
213
  module.exports = Connection