framer.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. var expect = require('chai').expect;
  2. var util = require('./util');
  3. var framer = require('../lib/protocol/framer');
  4. var Serializer = framer.Serializer;
  5. var Deserializer = framer.Deserializer;
  6. var frame_types = {
  7. DATA: ['data'],
  8. HEADERS: ['priority_information', 'data'],
  9. PRIORITY: ['priority_information'],
  10. RST_STREAM: ['error'],
  11. SETTINGS: ['settings'],
  12. PUSH_PROMISE: ['promised_stream', 'data'],
  13. PING: ['data'],
  14. GOAWAY: ['last_stream', 'error'],
  15. WINDOW_UPDATE: ['window_size'],
  16. CONTINUATION: ['data'],
  17. ALTSVC: ['protocolID', 'host', 'port', 'origin', 'maxAge']
  18. };
  19. var test_frames = [{
  20. frame: {
  21. type: 'DATA',
  22. flags: { END_STREAM: false, RESERVED2: false, RESERVED4: false,
  23. PADDED: false },
  24. stream: 10,
  25. data: new Buffer('12345678', 'hex')
  26. },
  27. // length + type + flags + stream + content
  28. buffer: new Buffer('000004' + '00' + '00' + '0000000A' + '12345678', 'hex')
  29. }, {
  30. frame: {
  31. type: 'HEADERS',
  32. flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
  33. PADDED: false, RESERVED5: false, PRIORITY: false },
  34. stream: 15,
  35. data: new Buffer('12345678', 'hex')
  36. },
  37. buffer: new Buffer('000004' + '01' + '00' + '0000000F' + '12345678', 'hex')
  38. }, {
  39. frame: {
  40. type: 'HEADERS',
  41. flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
  42. PADDED: false, RESERVED5: false, PRIORITY: true },
  43. stream: 15,
  44. priorityDependency: 10,
  45. priorityWeight: 5,
  46. exclusiveDependency: false,
  47. data: new Buffer('12345678', 'hex')
  48. },
  49. buffer: new Buffer('000009' + '01' + '20' + '0000000F' + '0000000A' + '05' + '12345678', 'hex')
  50. }, {
  51. frame: {
  52. type: 'HEADERS',
  53. flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
  54. PADDED: false, RESERVED5: false, PRIORITY: true },
  55. stream: 15,
  56. priorityDependency: 10,
  57. priorityWeight: 5,
  58. exclusiveDependency: true,
  59. data: new Buffer('12345678', 'hex')
  60. },
  61. buffer: new Buffer('000009' + '01' + '20' + '0000000F' + '8000000A' + '05' + '12345678', 'hex')
  62. }, {
  63. frame: {
  64. type: 'PRIORITY',
  65. flags: { },
  66. stream: 10,
  67. priorityDependency: 9,
  68. priorityWeight: 5,
  69. exclusiveDependency: false
  70. },
  71. buffer: new Buffer('000005' + '02' + '00' + '0000000A' + '00000009' + '05', 'hex')
  72. }, {
  73. frame: {
  74. type: 'PRIORITY',
  75. flags: { },
  76. stream: 10,
  77. priorityDependency: 9,
  78. priorityWeight: 5,
  79. exclusiveDependency: true
  80. },
  81. buffer: new Buffer('000005' + '02' + '00' + '0000000A' + '80000009' + '05', 'hex')
  82. }, {
  83. frame: {
  84. type: 'RST_STREAM',
  85. flags: { },
  86. stream: 10,
  87. error: 'INTERNAL_ERROR'
  88. },
  89. buffer: new Buffer('000004' + '03' + '00' + '0000000A' + '00000002', 'hex')
  90. }, {
  91. frame: {
  92. type: 'SETTINGS',
  93. flags: { ACK: false },
  94. stream: 10,
  95. settings: {
  96. SETTINGS_HEADER_TABLE_SIZE: 0x12345678,
  97. SETTINGS_ENABLE_PUSH: true,
  98. SETTINGS_MAX_CONCURRENT_STREAMS: 0x01234567,
  99. SETTINGS_INITIAL_WINDOW_SIZE: 0x89ABCDEF,
  100. SETTINGS_MAX_FRAME_SIZE: 0x00010000
  101. }
  102. },
  103. buffer: new Buffer('00001E' + '04' + '00' + '0000000A' + '0001' + '12345678' +
  104. '0002' + '00000001' +
  105. '0003' + '01234567' +
  106. '0004' + '89ABCDEF' +
  107. '0005' + '00010000', 'hex')
  108. }, {
  109. frame: {
  110. type: 'PUSH_PROMISE',
  111. flags: { RESERVED1: false, RESERVED2: false, END_PUSH_PROMISE: false,
  112. PADDED: false },
  113. stream: 15,
  114. promised_stream: 3,
  115. data: new Buffer('12345678', 'hex')
  116. },
  117. buffer: new Buffer('000008' + '05' + '00' + '0000000F' + '00000003' + '12345678', 'hex')
  118. }, {
  119. frame: {
  120. type: 'PING',
  121. flags: { ACK: false },
  122. stream: 15,
  123. data: new Buffer('1234567887654321', 'hex')
  124. },
  125. buffer: new Buffer('000008' + '06' + '00' + '0000000F' + '1234567887654321', 'hex')
  126. }, {
  127. frame: {
  128. type: 'GOAWAY',
  129. flags: { },
  130. stream: 10,
  131. last_stream: 0x12345678,
  132. error: 'PROTOCOL_ERROR'
  133. },
  134. buffer: new Buffer('000008' + '07' + '00' + '0000000A' + '12345678' + '00000001', 'hex')
  135. }, {
  136. frame: {
  137. type: 'WINDOW_UPDATE',
  138. flags: { },
  139. stream: 10,
  140. window_size: 0x12345678
  141. },
  142. buffer: new Buffer('000004' + '08' + '00' + '0000000A' + '12345678', 'hex')
  143. }, {
  144. frame: {
  145. type: 'CONTINUATION',
  146. flags: { RESERVED1: false, RESERVED2: false, END_HEADERS: true },
  147. stream: 10,
  148. data: new Buffer('12345678', 'hex')
  149. },
  150. // length + type + flags + stream + content
  151. buffer: new Buffer('000004' + '09' + '04' + '0000000A' + '12345678', 'hex')
  152. }, {
  153. frame: {
  154. type: 'ALTSVC',
  155. flags: { },
  156. stream: 0,
  157. maxAge: 31536000,
  158. port: 4443,
  159. protocolID: "h2",
  160. host: "altsvc.example.com",
  161. origin: ""
  162. },
  163. buffer: new Buffer(new Buffer('00002B' + '0A' + '00' + '00000000' + '0000', 'hex') + new Buffer('h2="altsvc.example.com:4443"; ma=31536000', 'ascii'))
  164. }, {
  165. frame: {
  166. type: 'ALTSVC',
  167. flags: { },
  168. stream: 0,
  169. maxAge: 31536000,
  170. port: 4443,
  171. protocolID: "h2",
  172. host: "altsvc.example.com",
  173. origin: "https://onlyme.example.com"
  174. },
  175. buffer: new Buffer(new Buffer('000045' + '0A' + '00' + '00000000' + '001A', 'hex') + new Buffer('https://onlyme.example.comh2="altsvc.example.com:4443"; ma=31536000', 'ascii'))
  176. }, {
  177. frame: {
  178. type: 'BLOCKED',
  179. flags: { },
  180. stream: 10
  181. },
  182. buffer: new Buffer('000000' + '0B' + '00' + '0000000A', 'hex')
  183. }];
  184. var deserializer_test_frames = test_frames.slice(0);
  185. var padded_test_frames = [{
  186. frame: {
  187. type: 'DATA',
  188. flags: { END_STREAM: false, RESERVED2: false, RESERVED4: false,
  189. PADDED: true },
  190. stream: 10,
  191. data: new Buffer('12345678', 'hex')
  192. },
  193. // length + type + flags + stream + pad length + content + padding
  194. buffer: new Buffer('00000B' + '00' + '08' + '0000000A' + '06' + '12345678' + '000000000000', 'hex')
  195. }, {
  196. frame: {
  197. type: 'HEADERS',
  198. flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
  199. PADDED: true, RESERVED5: false, PRIORITY: false },
  200. stream: 15,
  201. data: new Buffer('12345678', 'hex')
  202. },
  203. // length + type + flags + stream + pad length + data + padding
  204. buffer: new Buffer('00000B' + '01' + '08' + '0000000F' + '06' + '12345678' + '000000000000', 'hex')
  205. }, {
  206. frame: {
  207. type: 'HEADERS',
  208. flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
  209. PADDED: true, RESERVED5: false, PRIORITY: true },
  210. stream: 15,
  211. priorityDependency: 10,
  212. priorityWeight: 5,
  213. exclusiveDependency: false,
  214. data: new Buffer('12345678', 'hex')
  215. },
  216. // length + type + flags + stream + pad length + priority dependency + priority weight + data + padding
  217. buffer: new Buffer('000010' + '01' + '28' + '0000000F' + '06' + '0000000A' + '05' + '12345678' + '000000000000', 'hex')
  218. }, {
  219. frame: {
  220. type: 'HEADERS',
  221. flags: { END_STREAM: false, RESERVED2: false, END_HEADERS: false,
  222. PADDED: true, RESERVED5: false, PRIORITY: true },
  223. stream: 15,
  224. priorityDependency: 10,
  225. priorityWeight: 5,
  226. exclusiveDependency: true,
  227. data: new Buffer('12345678', 'hex')
  228. },
  229. // length + type + flags + stream + pad length + priority dependency + priority weight + data + padding
  230. buffer: new Buffer('000010' + '01' + '28' + '0000000F' + '06' + '8000000A' + '05' + '12345678' + '000000000000', 'hex')
  231. }, {
  232. frame: {
  233. type: 'PUSH_PROMISE',
  234. flags: { RESERVED1: false, RESERVED2: false, END_PUSH_PROMISE: false,
  235. PADDED: true },
  236. stream: 15,
  237. promised_stream: 3,
  238. data: new Buffer('12345678', 'hex')
  239. },
  240. // length + type + flags + stream + pad length + promised stream + data + padding
  241. buffer: new Buffer('00000F' + '05' + '08' + '0000000F' + '06' + '00000003' + '12345678' + '000000000000', 'hex')
  242. }];
  243. for (var idx = 0; idx < padded_test_frames.length; idx++) {
  244. deserializer_test_frames.push(padded_test_frames[idx]);
  245. }
  246. describe('framer.js', function() {
  247. describe('Serializer', function() {
  248. describe('static method .commonHeader({ type, flags, stream }, buffer_array)', function() {
  249. it('should add the appropriate 9 byte header buffer in front of the others', function() {
  250. for (var i = 0; i < test_frames.length; i++) {
  251. var test = test_frames[i];
  252. var buffers = [test.buffer.slice(9)];
  253. var header_buffer = test.buffer.slice(0,9);
  254. Serializer.commonHeader(test.frame, buffers);
  255. expect(buffers[0]).to.deep.equal(header_buffer);
  256. }
  257. });
  258. });
  259. Object.keys(frame_types).forEach(function(type) {
  260. var tests = test_frames.filter(function(test) { return test.frame.type === type; });
  261. var frame_shape = '{ ' + frame_types[type].join(', ') + ' }';
  262. describe('static method .' + type + '(' + frame_shape + ', buffer_array)', function() {
  263. it('should push buffers to the array that make up a ' + type + ' type payload', function() {
  264. for (var i = 0; i < tests.length; i++) {
  265. var test = tests[i];
  266. var buffers = [];
  267. Serializer[type](test.frame, buffers);
  268. expect(util.concat(buffers)).to.deep.equal(test.buffer.slice(9));
  269. }
  270. });
  271. });
  272. });
  273. describe('transform stream', function() {
  274. it('should transform frame objects to appropriate buffers', function() {
  275. var stream = new Serializer(util.log);
  276. for (var i = 0; i < test_frames.length; i++) {
  277. var test = test_frames[i];
  278. stream.write(test.frame);
  279. var chunk, buffer = new Buffer(0);
  280. while (chunk = stream.read()) {
  281. buffer = util.concat([buffer, chunk]);
  282. }
  283. expect(buffer).to.be.deep.equal(test.buffer);
  284. }
  285. });
  286. });
  287. });
  288. describe('Deserializer', function() {
  289. describe('static method .commonHeader(header_buffer, frame)', function() {
  290. it('should augment the frame object with these properties: { type, flags, stream })', function() {
  291. for (var i = 0; i < deserializer_test_frames.length; i++) {
  292. var test = deserializer_test_frames[i], frame = {};
  293. Deserializer.commonHeader(test.buffer.slice(0,9), frame);
  294. expect(frame).to.deep.equal({
  295. type: test.frame.type,
  296. flags: test.frame.flags,
  297. stream: test.frame.stream
  298. });
  299. }
  300. });
  301. });
  302. Object.keys(frame_types).forEach(function(type) {
  303. var tests = deserializer_test_frames.filter(function(test) { return test.frame.type === type; });
  304. var frame_shape = '{ ' + frame_types[type].join(', ') + ' }';
  305. describe('static method .' + type + '(payload_buffer, frame)', function() {
  306. it('should augment the frame object with these properties: ' + frame_shape, function() {
  307. for (var i = 0; i < tests.length; i++) {
  308. var test = tests[i];
  309. var frame = {
  310. type: test.frame.type,
  311. flags: test.frame.flags,
  312. stream: test.frame.stream
  313. };
  314. Deserializer[type](test.buffer.slice(9), frame);
  315. expect(frame).to.deep.equal(test.frame);
  316. }
  317. });
  318. });
  319. });
  320. describe('transform stream', function() {
  321. it('should transform buffers to appropriate frame object', function() {
  322. var stream = new Deserializer(util.log);
  323. var shuffled = util.shuffleBuffers(deserializer_test_frames.map(function(test) { return test.buffer; }));
  324. shuffled.forEach(stream.write.bind(stream));
  325. for (var j = 0; j < deserializer_test_frames.length; j++) {
  326. expect(stream.read()).to.be.deep.equal(deserializer_test_frames[j].frame);
  327. }
  328. });
  329. });
  330. });
  331. describe('bunyan formatter', function() {
  332. describe('`frame`', function() {
  333. var format = framer.serializers.frame;
  334. it('should assign a unique ID to each frame', function() {
  335. var frame1 = { type: 'DATA', data: new Buffer(10) };
  336. var frame2 = { type: 'PRIORITY', priority: 1 };
  337. expect(format(frame1).id).to.be.equal(format(frame1));
  338. expect(format(frame2).id).to.be.equal(format(frame2));
  339. expect(format(frame1)).to.not.be.equal(format(frame2));
  340. });
  341. });
  342. });
  343. });