wechat wss demo

test.js 26KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. 'use strict'
  2. var test = require('tape')
  3. var mqtt = require('./')
  4. var Buffer = require('safe-buffer').Buffer
  5. var WS = require('readable-stream').Writable
  6. function normalExpectedObject (object) {
  7. if (object.username != null) object.username = object.username.toString()
  8. if (object.password != null) object.password = Buffer.from(object.password)
  9. return object
  10. }
  11. function testParseGenerate (name, object, buffer, opts) {
  12. test(name + ' parse', function (t) {
  13. t.plan(2)
  14. var parser = mqtt.parser(opts)
  15. var expected = object
  16. var fixture = buffer
  17. parser.on('packet', function (packet) {
  18. if (packet.cmd !== 'publish') {
  19. delete packet.topic
  20. delete packet.payload
  21. }
  22. t.deepEqual(packet, normalExpectedObject(expected), 'expected packet')
  23. })
  24. parser.on('error', function (err) {
  25. t.fail(err)
  26. })
  27. t.equal(parser.parse(fixture), 0, 'remaining bytes')
  28. })
  29. test(name + ' generate', function (t) {
  30. t.equal(mqtt.generate(object).toString('hex'), buffer.toString('hex'))
  31. t.end()
  32. })
  33. test(name + ' mirror', function (t) {
  34. t.plan(2)
  35. var parser = mqtt.parser(opts)
  36. var expected = object
  37. var fixture = mqtt.generate(object)
  38. parser.on('packet', function (packet) {
  39. if (packet.cmd !== 'publish') {
  40. delete packet.topic
  41. delete packet.payload
  42. }
  43. t.deepEqual(packet, normalExpectedObject(expected), 'expected packet')
  44. })
  45. parser.on('error', function (err) {
  46. t.fail(err)
  47. })
  48. t.equal(parser.parse(fixture), 0, 'remaining bytes')
  49. })
  50. }
  51. function testParseError (expected, fixture) {
  52. test(expected, function (t) {
  53. t.plan(1)
  54. var parser = mqtt.parser()
  55. parser.on('error', function (err) {
  56. t.equal(err.message, expected, 'expected error message')
  57. })
  58. parser.on('packet', function () {
  59. t.fail('parse errors should not be followed by packet events')
  60. })
  61. parser.parse(fixture)
  62. })
  63. }
  64. function testGenerateError (expected, fixture) {
  65. test(expected, function (t) {
  66. t.plan(1)
  67. try {
  68. mqtt.generate(fixture)
  69. } catch (err) {
  70. t.equal(expected, err.message)
  71. }
  72. })
  73. }
  74. function testParseGenerateDefaults (name, object, buffer, opts) {
  75. test(name + ' parse', function (t) {
  76. var parser = mqtt.parser(opts)
  77. var expected = object
  78. var fixture = buffer
  79. t.plan(1 + Object.keys(expected).length)
  80. parser.on('packet', function (packet) {
  81. Object.keys(expected).forEach(function (key) {
  82. t.deepEqual(packet[key], expected[key], 'expected packet property ' + key)
  83. })
  84. })
  85. t.equal(parser.parse(fixture), 0, 'remaining bytes')
  86. })
  87. test(name + ' generate', function (t) {
  88. t.equal(mqtt.generate(object).toString('hex'), buffer.toString('hex'))
  89. t.end()
  90. })
  91. }
  92. function testWriteToStreamError (expected, fixture) {
  93. test('writeToStream ' + expected + ' error', function (t) {
  94. t.plan(2)
  95. var stream = WS()
  96. stream.write = () => t.fail('should not have called write')
  97. stream.on('error', () => t.pass('error emitted'))
  98. var result = mqtt.writeToStream(fixture, stream)
  99. t.false(result, 'result should be false')
  100. })
  101. }
  102. test('disabled numbers cache', function (t) {
  103. var stream = WS()
  104. var message = {
  105. cmd: 'publish',
  106. retain: false,
  107. qos: 0,
  108. dup: false,
  109. length: 10,
  110. topic: Buffer.from('test'),
  111. payload: Buffer.from('test')
  112. }
  113. var expected = Buffer.from([
  114. 48, 10, // Header
  115. 0, 4, // Topic length
  116. 116, 101, 115, 116, // Topic (test)
  117. 116, 101, 115, 116 // Payload (test)
  118. ])
  119. var written = Buffer.alloc(0)
  120. stream.write = (chunk) => {
  121. written = Buffer.concat([written, chunk])
  122. }
  123. mqtt.writeToStream.cacheNumbers = false
  124. mqtt.writeToStream(message, stream)
  125. t.deepEqual(written, expected, 'written buffer is expected')
  126. mqtt.writeToStream.cacheNumbers = true
  127. stream.end()
  128. t.end()
  129. })
  130. testParseGenerate('minimal connect', {
  131. cmd: 'connect',
  132. retain: false,
  133. qos: 0,
  134. dup: false,
  135. length: 18,
  136. protocolId: 'MQIsdp',
  137. protocolVersion: 3,
  138. clean: false,
  139. keepalive: 30,
  140. clientId: 'test'
  141. }, Buffer.from([
  142. 16, 18, // Header
  143. 0, 6, // Protocol ID length
  144. 77, 81, 73, 115, 100, 112, // Protocol ID
  145. 3, // Protocol version
  146. 0, // Connect flags
  147. 0, 30, // Keepalive
  148. 0, 4, // Client ID length
  149. 116, 101, 115, 116 // Client ID
  150. ]))
  151. testParseGenerate('no clientId with 3.1.1', {
  152. cmd: 'connect',
  153. retain: false,
  154. qos: 0,
  155. dup: false,
  156. length: 12,
  157. protocolId: 'MQTT',
  158. protocolVersion: 4,
  159. clean: true,
  160. keepalive: 30,
  161. clientId: ''
  162. }, Buffer.from([
  163. 16, 12, // Header
  164. 0, 4, // Protocol ID length
  165. 77, 81, 84, 84, // Protocol ID
  166. 4, // Protocol version
  167. 2, // Connect flags
  168. 0, 30, // Keepalive
  169. 0, 0 // Client ID length
  170. ]))
  171. testParseGenerateDefaults('default connect', {
  172. cmd: 'connect',
  173. clientId: 'test'
  174. }, Buffer.from([
  175. 16, 16, 0, 4, 77, 81, 84,
  176. 84, 4, 2, 0, 0,
  177. 0, 4, 116, 101, 115, 116
  178. ]))
  179. testParseGenerate('empty will payload', {
  180. cmd: 'connect',
  181. retain: false,
  182. qos: 0,
  183. dup: false,
  184. length: 47,
  185. protocolId: 'MQIsdp',
  186. protocolVersion: 3,
  187. will: {
  188. retain: true,
  189. qos: 2,
  190. topic: 'topic',
  191. payload: new Buffer(0)
  192. },
  193. clean: true,
  194. keepalive: 30,
  195. clientId: 'test',
  196. username: 'username',
  197. password: new Buffer('password')
  198. }, Buffer.from([
  199. 16, 47, // Header
  200. 0, 6, // Protocol ID length
  201. 77, 81, 73, 115, 100, 112, // Protocol ID
  202. 3, // Protocol version
  203. 246, // Connect flags
  204. 0, 30, // Keepalive
  205. 0, 4, // Client ID length
  206. 116, 101, 115, 116, // Client ID
  207. 0, 5, // Will topic length
  208. 116, 111, 112, 105, 99, // Will topic
  209. 0, 0, // Will payload length
  210. // Will payload
  211. 0, 8, // Username length
  212. 117, 115, 101, 114, 110, 97, 109, 101, // Username
  213. 0, 8, // Password length
  214. 112, 97, 115, 115, 119, 111, 114, 100 // Password
  215. ]))
  216. testParseGenerate('empty buffer username payload', {
  217. cmd: 'connect',
  218. retain: false,
  219. qos: 0,
  220. dup: false,
  221. length: 20,
  222. protocolId: 'MQIsdp',
  223. protocolVersion: 3,
  224. clean: true,
  225. keepalive: 30,
  226. clientId: 'test',
  227. username: new Buffer('')
  228. }, Buffer.from([
  229. 16, 20, // Header
  230. 0, 6, // Protocol ID length
  231. 77, 81, 73, 115, 100, 112, // Protocol ID
  232. 3, // Protocol version
  233. 130, // Connect flags
  234. 0, 30, // Keepalive
  235. 0, 4, // Client ID length
  236. 116, 101, 115, 116, // Client ID
  237. 0, 0 // Username length
  238. // Empty Username payload
  239. ]))
  240. testParseGenerate('empty string username payload', {
  241. cmd: 'connect',
  242. retain: false,
  243. qos: 0,
  244. dup: false,
  245. length: 20,
  246. protocolId: 'MQIsdp',
  247. protocolVersion: 3,
  248. clean: true,
  249. keepalive: 30,
  250. clientId: 'test',
  251. username: ''
  252. }, Buffer.from([
  253. 16, 20, // Header
  254. 0, 6, // Protocol ID length
  255. 77, 81, 73, 115, 100, 112, // Protocol ID
  256. 3, // Protocol version
  257. 130, // Connect flags
  258. 0, 30, // Keepalive
  259. 0, 4, // Client ID length
  260. 116, 101, 115, 116, // Client ID
  261. 0, 0 // Username length
  262. // Empty Username payload
  263. ]))
  264. testParseGenerate('empty buffer password payload', {
  265. cmd: 'connect',
  266. retain: false,
  267. qos: 0,
  268. dup: false,
  269. length: 30,
  270. protocolId: 'MQIsdp',
  271. protocolVersion: 3,
  272. clean: true,
  273. keepalive: 30,
  274. clientId: 'test',
  275. username: 'username',
  276. password: new Buffer('')
  277. }, Buffer.from([
  278. 16, 30, // Header
  279. 0, 6, // Protocol ID length
  280. 77, 81, 73, 115, 100, 112, // Protocol ID
  281. 3, // Protocol version
  282. 194, // Connect flags
  283. 0, 30, // Keepalive
  284. 0, 4, // Client ID length
  285. 116, 101, 115, 116, // Client ID
  286. 0, 8, // Username length
  287. 117, 115, 101, 114, 110, 97, 109, 101, // Username payload
  288. 0, 0 // Password length
  289. // Empty password payload
  290. ]))
  291. testParseGenerate('empty string password payload', {
  292. cmd: 'connect',
  293. retain: false,
  294. qos: 0,
  295. dup: false,
  296. length: 30,
  297. protocolId: 'MQIsdp',
  298. protocolVersion: 3,
  299. clean: true,
  300. keepalive: 30,
  301. clientId: 'test',
  302. username: 'username',
  303. password: ''
  304. }, Buffer.from([
  305. 16, 30, // Header
  306. 0, 6, // Protocol ID length
  307. 77, 81, 73, 115, 100, 112, // Protocol ID
  308. 3, // Protocol version
  309. 194, // Connect flags
  310. 0, 30, // Keepalive
  311. 0, 4, // Client ID length
  312. 116, 101, 115, 116, // Client ID
  313. 0, 8, // Username length
  314. 117, 115, 101, 114, 110, 97, 109, 101, // Username payload
  315. 0, 0 // Password length
  316. // Empty password payload
  317. ]))
  318. testParseGenerate('empty string username and password payload', {
  319. cmd: 'connect',
  320. retain: false,
  321. qos: 0,
  322. dup: false,
  323. length: 22,
  324. protocolId: 'MQIsdp',
  325. protocolVersion: 3,
  326. clean: true,
  327. keepalive: 30,
  328. clientId: 'test',
  329. username: '',
  330. password: new Buffer('')
  331. }, Buffer.from([
  332. 16, 22, // Header
  333. 0, 6, // Protocol ID length
  334. 77, 81, 73, 115, 100, 112, // Protocol ID
  335. 3, // Protocol version
  336. 194, // Connect flags
  337. 0, 30, // Keepalive
  338. 0, 4, // Client ID length
  339. 116, 101, 115, 116, // Client ID
  340. 0, 0, // Username length
  341. // Empty Username payload
  342. 0, 0 // Password length
  343. // Empty password payload
  344. ]))
  345. testParseGenerate('maximal connect', {
  346. cmd: 'connect',
  347. retain: false,
  348. qos: 0,
  349. dup: false,
  350. length: 54,
  351. protocolId: 'MQIsdp',
  352. protocolVersion: 3,
  353. will: {
  354. retain: true,
  355. qos: 2,
  356. topic: 'topic',
  357. payload: new Buffer('payload')
  358. },
  359. clean: true,
  360. keepalive: 30,
  361. clientId: 'test',
  362. username: 'username',
  363. password: new Buffer('password')
  364. }, Buffer.from([
  365. 16, 54, // Header
  366. 0, 6, // Protocol ID length
  367. 77, 81, 73, 115, 100, 112, // Protocol ID
  368. 3, // Protocol version
  369. 246, // Connect flags
  370. 0, 30, // Keepalive
  371. 0, 4, // Client ID length
  372. 116, 101, 115, 116, // Client ID
  373. 0, 5, // Will topic length
  374. 116, 111, 112, 105, 99, // Will topic
  375. 0, 7, // Will payload length
  376. 112, 97, 121, 108, 111, 97, 100, // Will payload
  377. 0, 8, // Username length
  378. 117, 115, 101, 114, 110, 97, 109, 101, // Username
  379. 0, 8, // Password length
  380. 112, 97, 115, 115, 119, 111, 114, 100 // Password
  381. ]))
  382. testParseGenerate('max connect with special chars', {
  383. cmd: 'connect',
  384. retain: false,
  385. qos: 0,
  386. dup: false,
  387. length: 57,
  388. protocolId: 'MQIsdp',
  389. protocolVersion: 3,
  390. will: {
  391. retain: true,
  392. qos: 2,
  393. topic: 'tòpic',
  394. payload: new Buffer('pay£oad')
  395. },
  396. clean: true,
  397. keepalive: 30,
  398. clientId: 'te$t',
  399. username: 'u$ern4me',
  400. password: new Buffer('p4$$w0£d')
  401. }, Buffer.from([
  402. 16, 57, // Header
  403. 0, 6, // Protocol ID length
  404. 77, 81, 73, 115, 100, 112, // Protocol ID
  405. 3, // Protocol version
  406. 246, // Connect flags
  407. 0, 30, // Keepalive
  408. 0, 4, // Client ID length
  409. 116, 101, 36, 116, // Client ID
  410. 0, 6, // Will topic length
  411. 116, 195, 178, 112, 105, 99, // Will topic
  412. 0, 8, // Will payload length
  413. 112, 97, 121, 194, 163, 111, 97, 100, // Will payload
  414. 0, 8, // Username length
  415. 117, 36, 101, 114, 110, 52, 109, 101, // Username
  416. 0, 9, // Password length
  417. 112, 52, 36, 36, 119, 48, 194, 163, 100 // Password
  418. ]))
  419. test('connect all strings generate', function (t) {
  420. var message = {
  421. cmd: 'connect',
  422. retain: false,
  423. qos: 0,
  424. dup: false,
  425. length: 54,
  426. protocolId: 'MQIsdp',
  427. protocolVersion: 3,
  428. will: {
  429. retain: true,
  430. qos: 2,
  431. topic: 'topic',
  432. payload: 'payload'
  433. },
  434. clean: true,
  435. keepalive: 30,
  436. clientId: 'test',
  437. username: 'username',
  438. password: 'password'
  439. }
  440. var expected = Buffer.from([
  441. 16, 54, // Header
  442. 0, 6, // Protocol ID length
  443. 77, 81, 73, 115, 100, 112, // Protocol ID
  444. 3, // Protocol version
  445. 246, // Connect flags
  446. 0, 30, // Keepalive
  447. 0, 4, // Client ID length
  448. 116, 101, 115, 116, // Client ID
  449. 0, 5, // Will topic length
  450. 116, 111, 112, 105, 99, // Will topic
  451. 0, 7, // Will payload length
  452. 112, 97, 121, 108, 111, 97, 100, // Will payload
  453. 0, 8, // Username length
  454. 117, 115, 101, 114, 110, 97, 109, 101, // Username
  455. 0, 8, // Password length
  456. 112, 97, 115, 115, 119, 111, 114, 100 // Password
  457. ])
  458. t.equal(mqtt.generate(message).toString('hex'), expected.toString('hex'))
  459. t.end()
  460. })
  461. testParseError('Cannot parse protocolId', Buffer.from([
  462. 16, 4,
  463. 0, 6,
  464. 77, 81
  465. ]))
  466. testParseGenerate('connack with return code 0', {
  467. cmd: 'connack',
  468. retain: false,
  469. qos: 0,
  470. dup: false,
  471. length: 2,
  472. sessionPresent: false,
  473. returnCode: 0
  474. }, Buffer.from([
  475. 32, 2, 0, 0
  476. ]))
  477. testParseGenerate('connack with return code 0 session present bit set', {
  478. cmd: 'connack',
  479. retain: false,
  480. qos: 0,
  481. dup: false,
  482. length: 2,
  483. sessionPresent: true,
  484. returnCode: 0
  485. }, Buffer.from([
  486. 32, 2, 1, 0
  487. ]))
  488. testParseGenerate('connack with return code 5', {
  489. cmd: 'connack',
  490. retain: false,
  491. qos: 0,
  492. dup: false,
  493. length: 2,
  494. sessionPresent: false,
  495. returnCode: 5
  496. }, Buffer.from([
  497. 32, 2, 0, 5
  498. ]))
  499. testParseGenerate('minimal publish', {
  500. cmd: 'publish',
  501. retain: false,
  502. qos: 0,
  503. dup: false,
  504. length: 10,
  505. topic: 'test',
  506. payload: new Buffer('test')
  507. }, Buffer.from([
  508. 48, 10, // Header
  509. 0, 4, // Topic length
  510. 116, 101, 115, 116, // Topic (test)
  511. 116, 101, 115, 116 // Payload (test)
  512. ]))
  513. ;(function () {
  514. var buffer = new Buffer(2048)
  515. testParseGenerate('2KB publish packet', {
  516. cmd: 'publish',
  517. retain: false,
  518. qos: 0,
  519. dup: false,
  520. length: 2054,
  521. topic: 'test',
  522. payload: buffer
  523. }, Buffer.concat([Buffer.from([
  524. 48, 134, 16, // Header
  525. 0, 4, // Topic length
  526. 116, 101, 115, 116 // Topic (test)
  527. ]), buffer]))
  528. })()
  529. ;(function () {
  530. var buffer = new Buffer(2 * 1024 * 1024)
  531. testParseGenerate('2MB publish packet', {
  532. cmd: 'publish',
  533. retain: false,
  534. qos: 0,
  535. dup: false,
  536. length: 6 + 2 * 1024 * 1024,
  537. topic: 'test',
  538. payload: buffer
  539. }, Buffer.concat([Buffer.from([
  540. 48, 134, 128, 128, 1, // Header
  541. 0, 4, // Topic length
  542. 116, 101, 115, 116 // Topic (test)
  543. ]), buffer]))
  544. })()
  545. testParseGenerate('maximal publish', {
  546. cmd: 'publish',
  547. retain: true,
  548. qos: 2,
  549. length: 12,
  550. dup: true,
  551. topic: 'test',
  552. messageId: 10,
  553. payload: new Buffer('test')
  554. }, Buffer.from([
  555. 61, 12, // Header
  556. 0, 4, // Topic length
  557. 116, 101, 115, 116, // Topic
  558. 0, 10, // Message ID
  559. 116, 101, 115, 116 // Payload
  560. ]))
  561. test('publish all strings generate', function (t) {
  562. var message = {
  563. cmd: 'publish',
  564. retain: true,
  565. qos: 2,
  566. length: 12,
  567. dup: true,
  568. topic: 'test',
  569. messageId: 10,
  570. payload: new Buffer('test')
  571. }
  572. var expected = Buffer.from([
  573. 61, 12, // Header
  574. 0, 4, // Topic length
  575. 116, 101, 115, 116, // Topic
  576. 0, 10, // Message ID
  577. 116, 101, 115, 116 // Payload
  578. ])
  579. t.equal(mqtt.generate(message).toString('hex'), expected.toString('hex'))
  580. t.end()
  581. })
  582. testParseGenerate('empty publish', {
  583. cmd: 'publish',
  584. retain: false,
  585. qos: 0,
  586. dup: false,
  587. length: 6,
  588. topic: 'test',
  589. payload: new Buffer(0)
  590. }, Buffer.from([
  591. 48, 6, // Header
  592. 0, 4, // Topic length
  593. 116, 101, 115, 116 // Topic
  594. // Empty payload
  595. ]))
  596. test('splitted publish parse', function (t) {
  597. t.plan(3)
  598. var parser = mqtt.parser()
  599. var expected = {
  600. cmd: 'publish',
  601. retain: false,
  602. qos: 0,
  603. dup: false,
  604. length: 10,
  605. topic: 'test',
  606. payload: new Buffer('test')
  607. }
  608. parser.on('packet', function (packet) {
  609. t.deepEqual(packet, expected, 'expected packet')
  610. })
  611. t.equal(parser.parse(Buffer.from([
  612. 48, 10, // Header
  613. 0, 4, // Topic length
  614. 116, 101, 115, 116 // Topic (test)
  615. ])), 6, 'remaining bytes')
  616. t.equal(parser.parse(Buffer.from([
  617. 116, 101, 115, 116 // Payload (test)
  618. ])), 0, 'remaining bytes')
  619. })
  620. testParseGenerate('puback', {
  621. cmd: 'puback',
  622. retain: false,
  623. qos: 0,
  624. dup: false,
  625. length: 2,
  626. messageId: 2
  627. }, Buffer.from([
  628. 64, 2, // Header
  629. 0, 2 // Message ID
  630. ]))
  631. testParseGenerate('pubrec', {
  632. cmd: 'pubrec',
  633. retain: false,
  634. qos: 0,
  635. dup: false,
  636. length: 2,
  637. messageId: 2
  638. }, Buffer.from([
  639. 80, 2, // Header
  640. 0, 2 // Message ID
  641. ]))
  642. testParseGenerate('pubrel', {
  643. cmd: 'pubrel',
  644. retain: false,
  645. qos: 1,
  646. dup: false,
  647. length: 2,
  648. messageId: 2
  649. }, Buffer.from([
  650. 98, 2, // Header
  651. 0, 2 // Message ID
  652. ]))
  653. testParseGenerate('pubcomp', {
  654. cmd: 'pubcomp',
  655. retain: false,
  656. qos: 0,
  657. dup: false,
  658. length: 2,
  659. messageId: 2
  660. }, Buffer.from([
  661. 112, 2, // Header
  662. 0, 2 // Message ID
  663. ]))
  664. testParseError('Wrong subscribe header', Buffer.from([
  665. 128, 9, // Header (subscribeqos=0length=9)
  666. 0, 6, // Message ID (6)
  667. 0, 4, // Topic length,
  668. 116, 101, 115, 116, // Topic (test)
  669. 0 // Qos (0)
  670. ]))
  671. testParseGenerate('subscribe to one topic', {
  672. cmd: 'subscribe',
  673. retain: false,
  674. qos: 1,
  675. dup: false,
  676. length: 9,
  677. subscriptions: [
  678. {
  679. topic: 'test',
  680. qos: 0
  681. }
  682. ],
  683. messageId: 6
  684. }, Buffer.from([
  685. 130, 9, // Header (subscribeqos=1length=9)
  686. 0, 6, // Message ID (6)
  687. 0, 4, // Topic length,
  688. 116, 101, 115, 116, // Topic (test)
  689. 0 // Qos (0)
  690. ]))
  691. testParseGenerate('subscribe to three topics', {
  692. cmd: 'subscribe',
  693. retain: false,
  694. qos: 1,
  695. dup: false,
  696. length: 23,
  697. subscriptions: [
  698. {
  699. topic: 'test',
  700. qos: 0
  701. }, {
  702. topic: 'uest',
  703. qos: 1
  704. }, {
  705. topic: 'tfst',
  706. qos: 2
  707. }
  708. ],
  709. messageId: 6
  710. }, Buffer.from([
  711. 130, 23, // Header (publishqos=1length=9)
  712. 0, 6, // Message ID (6)
  713. 0, 4, // Topic length,
  714. 116, 101, 115, 116, // Topic (test)
  715. 0, // Qos (0)
  716. 0, 4, // Topic length
  717. 117, 101, 115, 116, // Topic (uest)
  718. 1, // Qos (1)
  719. 0, 4, // Topic length
  720. 116, 102, 115, 116, // Topic (tfst)
  721. 2 // Qos (2)
  722. ]))
  723. testParseGenerate('suback', {
  724. cmd: 'suback',
  725. retain: false,
  726. qos: 0,
  727. dup: false,
  728. length: 6,
  729. granted: [0, 1, 2, 128],
  730. messageId: 6
  731. }, Buffer.from([
  732. 144, 6, // Header
  733. 0, 6, // Message ID
  734. 0, 1, 2, 128 // Granted qos (0, 1, 2) and a rejected being 0x80
  735. ]))
  736. testParseGenerate('unsubscribe', {
  737. cmd: 'unsubscribe',
  738. retain: false,
  739. qos: 1,
  740. dup: false,
  741. length: 14,
  742. unsubscriptions: [
  743. 'tfst',
  744. 'test'
  745. ],
  746. messageId: 7
  747. }, Buffer.from([
  748. 162, 14,
  749. 0, 7, // Message ID (7)
  750. 0, 4, // Topic length
  751. 116, 102, 115, 116, // Topic (tfst)
  752. 0, 4, // Topic length,
  753. 116, 101, 115, 116 // Topic (test)
  754. ]))
  755. testParseGenerate('unsuback', {
  756. cmd: 'unsuback',
  757. retain: false,
  758. qos: 0,
  759. dup: false,
  760. length: 2,
  761. messageId: 8
  762. }, Buffer.from([
  763. 176, 2, // Header
  764. 0, 8 // Message ID
  765. ]))
  766. testParseGenerate('pingreq', {
  767. cmd: 'pingreq',
  768. retain: false,
  769. qos: 0,
  770. dup: false,
  771. length: 0
  772. }, Buffer.from([
  773. 192, 0 // Header
  774. ]))
  775. testParseGenerate('pingresp', {
  776. cmd: 'pingresp',
  777. retain: false,
  778. qos: 0,
  779. dup: false,
  780. length: 0
  781. }, Buffer.from([
  782. 208, 0 // Header
  783. ]))
  784. testParseGenerate('disconnect', {
  785. cmd: 'disconnect',
  786. retain: false,
  787. qos: 0,
  788. dup: false,
  789. length: 0
  790. }, Buffer.from([
  791. 224, 0 // Header
  792. ]))
  793. testGenerateError('Unknown command', {})
  794. testGenerateError('Invalid protocolId', {
  795. cmd: 'connect',
  796. retain: false,
  797. qos: 0,
  798. dup: false,
  799. length: 54,
  800. protocolId: 42,
  801. protocolVersion: 3,
  802. will: {
  803. retain: true,
  804. qos: 2,
  805. topic: 'topic',
  806. payload: 'payload'
  807. },
  808. clean: true,
  809. keepalive: 30,
  810. clientId: 'test',
  811. username: 'username',
  812. password: 'password'
  813. })
  814. testGenerateError('clientId must be supplied before 3.1.1', {
  815. cmd: 'connect',
  816. retain: false,
  817. qos: 0,
  818. dup: false,
  819. length: 54,
  820. protocolId: 'MQIsdp',
  821. protocolVersion: 3,
  822. will: {
  823. retain: true,
  824. qos: 2,
  825. topic: 'topic',
  826. payload: 'payload'
  827. },
  828. clean: true,
  829. keepalive: 30,
  830. username: 'username',
  831. password: 'password'
  832. })
  833. testGenerateError('clientId must be given if cleanSession set to 0', {
  834. cmd: 'connect',
  835. retain: false,
  836. qos: 0,
  837. dup: false,
  838. length: 54,
  839. protocolId: 'MQTT',
  840. protocolVersion: 4,
  841. will: {
  842. retain: true,
  843. qos: 2,
  844. topic: 'topic',
  845. payload: 'payload'
  846. },
  847. clean: false,
  848. keepalive: 30,
  849. username: 'username',
  850. password: 'password'
  851. })
  852. testGenerateError('Invalid keepalive', {
  853. cmd: 'connect',
  854. retain: false,
  855. qos: 0,
  856. dup: false,
  857. length: 54,
  858. protocolId: 'MQIsdp',
  859. protocolVersion: 3,
  860. will: {
  861. retain: true,
  862. qos: 2,
  863. topic: 'topic',
  864. payload: 'payload'
  865. },
  866. clean: true,
  867. keepalive: 'hello',
  868. clientId: 'test',
  869. username: 'username',
  870. password: 'password'
  871. })
  872. testGenerateError('Invalid keepalive', {
  873. cmd: 'connect',
  874. keepalive: 3.1416
  875. })
  876. testGenerateError('Invalid will', {
  877. cmd: 'connect',
  878. retain: false,
  879. qos: 0,
  880. dup: false,
  881. length: 54,
  882. protocolId: 'MQIsdp',
  883. protocolVersion: 3,
  884. will: 42,
  885. clean: true,
  886. keepalive: 30,
  887. clientId: 'test',
  888. username: 'username',
  889. password: 'password'
  890. })
  891. testGenerateError('Invalid will topic', {
  892. cmd: 'connect',
  893. retain: false,
  894. qos: 0,
  895. dup: false,
  896. length: 54,
  897. protocolId: 'MQIsdp',
  898. protocolVersion: 3,
  899. will: {
  900. retain: true,
  901. qos: 2,
  902. payload: 'payload'
  903. },
  904. clean: true,
  905. keepalive: 30,
  906. clientId: 'test',
  907. username: 'username',
  908. password: 'password'
  909. })
  910. testGenerateError('Invalid will payload', {
  911. cmd: 'connect',
  912. retain: false,
  913. qos: 0,
  914. dup: false,
  915. length: 54,
  916. protocolId: 'MQIsdp',
  917. protocolVersion: 3,
  918. will: {
  919. retain: true,
  920. qos: 2,
  921. topic: 'topic',
  922. payload: 42
  923. },
  924. clean: true,
  925. keepalive: 30,
  926. clientId: 'test',
  927. username: 'username',
  928. password: 'password'
  929. })
  930. testGenerateError('Invalid username', {
  931. cmd: 'connect',
  932. retain: false,
  933. qos: 0,
  934. dup: false,
  935. length: 54,
  936. protocolId: 'MQIsdp',
  937. protocolVersion: 3,
  938. will: {
  939. retain: true,
  940. qos: 2,
  941. topic: 'topic',
  942. payload: 'payload'
  943. },
  944. clean: true,
  945. keepalive: 30,
  946. clientId: 'test',
  947. username: 42,
  948. password: 'password'
  949. })
  950. testGenerateError('Invalid password', {
  951. cmd: 'connect',
  952. retain: false,
  953. qos: 0,
  954. dup: false,
  955. length: 54,
  956. protocolId: 'MQIsdp',
  957. protocolVersion: 3,
  958. will: {
  959. retain: true,
  960. qos: 2,
  961. topic: 'topic',
  962. payload: 'payload'
  963. },
  964. clean: true,
  965. keepalive: 30,
  966. clientId: 'test',
  967. username: 'username',
  968. password: 42
  969. })
  970. testGenerateError('Username is required to use password', {
  971. cmd: 'connect',
  972. retain: false,
  973. qos: 0,
  974. dup: false,
  975. length: 54,
  976. protocolId: 'MQIsdp',
  977. protocolVersion: 3,
  978. will: {
  979. retain: true,
  980. qos: 2,
  981. topic: 'topic',
  982. payload: 'payload'
  983. },
  984. clean: true,
  985. keepalive: 30,
  986. clientId: 'test',
  987. password: 'password'
  988. })
  989. test('support cork', function (t) {
  990. t.plan(9)
  991. var dest = WS()
  992. dest._write = function (chunk, enc, cb) {
  993. t.pass('_write called')
  994. cb()
  995. }
  996. mqtt.writeToStream({
  997. cmd: 'connect',
  998. retain: false,
  999. qos: 0,
  1000. dup: false,
  1001. length: 18,
  1002. protocolId: 'MQIsdp',
  1003. protocolVersion: 3,
  1004. clean: false,
  1005. keepalive: 30,
  1006. clientId: 'test'
  1007. }, dest)
  1008. dest.end()
  1009. })
  1010. // The following test case was designed after experiencing errors
  1011. // when trying to connect with tls on a non tls mqtt port
  1012. // the specific behaviour is:
  1013. // - first byte suggests this is a connect message
  1014. // - second byte suggests message length to be smaller than buffer length
  1015. // thus payload processing starts
  1016. // - the first two bytes suggest a protocol identifier string length
  1017. // that leads the parser pointer close to the end of the buffer
  1018. // - when trying to read further connect flags the buffer produces
  1019. // a "out of range" Error
  1020. //
  1021. testParseError('Packet too short', Buffer.from([
  1022. 16, 9,
  1023. 0, 6,
  1024. 77, 81, 73, 115, 100, 112,
  1025. 3
  1026. ]))
  1027. // CONNECT Packets that show other protocol IDs than
  1028. // the valid values MQTT and MQIsdp should cause an error
  1029. // those packets are a hint that this is not a mqtt connection
  1030. testParseError('Invalid protocolId', Buffer.from([
  1031. 16, 18,
  1032. 0, 6,
  1033. 65, 65, 65, 65, 65, 65, // AAAAAA
  1034. 3, // Protocol version
  1035. 0, // Connect flags
  1036. 0, 10, // Keepalive
  1037. 0, 4, // Client ID length
  1038. 116, 101, 115, 116 // Client ID
  1039. ]))
  1040. // CONNECT Packets that contain an unsupported protocol version
  1041. // Flag (i.e. not `3` or `4`) should cause an error
  1042. testParseError('Invalid protocol version', Buffer.from([
  1043. 16, 18,
  1044. 0, 6,
  1045. 77, 81, 73, 115, 100, 112, // Protocol ID
  1046. 1, // Protocol version
  1047. 0, // Connect flags
  1048. 0, 10, // Keepalive
  1049. 0, 4, // Client ID length
  1050. 116, 101, 115, 116 // Client ID
  1051. ]))
  1052. // When a packet contains a string in the variable header and the
  1053. // given string length of this exceeds the overall length of the packet that
  1054. // was specified in the fixed header, parsing must fail.
  1055. // this case simulates this behavior with the protocol ID string of the
  1056. // CONNECT packet. The fixed header suggests a remaining length of 8 bytes
  1057. // which would be exceeded by the string length of 15
  1058. // in this case, a protocol ID parse error is expected
  1059. testParseError('Cannot parse protocolId', Buffer.from([
  1060. 16, 8, // Fixed header
  1061. 0, 15, // string length 15 --> 15 > 8 --> error!
  1062. 77, 81, 73, 115, 100, 112,
  1063. 77, 81, 73, 115, 100, 112,
  1064. 77, 81, 73, 115, 100, 112,
  1065. 77, 81, 73, 115, 100, 112,
  1066. 77, 81, 73, 115, 100, 112,
  1067. 77, 81, 73, 115, 100, 112,
  1068. 77, 81, 73, 115, 100, 112,
  1069. 77, 81, 73, 115, 100, 112
  1070. ]))
  1071. test('stops parsing after first error', function (t) {
  1072. t.plan(4)
  1073. var parser = mqtt.parser()
  1074. var packetCount = 0
  1075. var errorCount = 0
  1076. var expectedPackets = 1
  1077. var expectedErrors = 1
  1078. parser.on('packet', function (packet) {
  1079. t.ok(++packetCount <= expectedPackets, 'expected <= ' + expectedPackets + ' packets')
  1080. })
  1081. parser.on('error', function (erroneous) {
  1082. t.ok(++errorCount <= expectedErrors, 'expected <= ' + expectedErrors + ' errors')
  1083. })
  1084. parser.parse(Buffer.from([
  1085. // First, a valid connect packet:
  1086. 16, 12, // Header
  1087. 0, 4, // Protocol ID length
  1088. 77, 81, 84, 84, // Protocol ID
  1089. 4, // Protocol version
  1090. 2, // Connect flags
  1091. 0, 30, // Keepalive
  1092. 0, 0, // Client ID length
  1093. // Then an invalid subscribe packet:
  1094. 128, 9, // Header (subscribeqos=0length=9)
  1095. 0, 6, // Message ID (6)
  1096. 0, 4, // Topic length,
  1097. 116, 101, 115, 116, // Topic (test)
  1098. 0, // Qos (0)
  1099. // And another invalid subscribe packet:
  1100. 128, 9, // Header (subscribeqos=0length=9)
  1101. 0, 6, // Message ID (6)
  1102. 0, 4, // Topic length,
  1103. 116, 101, 115, 116, // Topic (test)
  1104. 0, // Qos (0)
  1105. // Finally, a valid disconnect packet:
  1106. 224, 0 // Header
  1107. ]))
  1108. // Calling parse again clears the error and continues parsing
  1109. packetCount = 0
  1110. errorCount = 0
  1111. expectedPackets = 2
  1112. expectedErrors = 0
  1113. parser.parse(Buffer.from([
  1114. // Connect:
  1115. 16, 12, // Header
  1116. 0, 4, // Protocol ID length
  1117. 77, 81, 84, 84, // Protocol ID
  1118. 4, // Protocol version
  1119. 2, // Connect flags
  1120. 0, 30, // Keepalive
  1121. 0, 0, // Client ID length
  1122. // Disconnect:
  1123. 224, 0 // Header
  1124. ]))
  1125. })
  1126. testWriteToStreamError('Invalid protocolId', {
  1127. cmd: 'connect',
  1128. protocolId: {}
  1129. })
  1130. testWriteToStreamError('Invalid topic', {
  1131. cmd: 'publish',
  1132. topic: {}
  1133. })
  1134. testWriteToStreamError('Invalid messageId', {
  1135. cmd: 'subscribe',
  1136. mid: {}
  1137. })