@@ -4,7 +4,7 @@ module Http2 =
4
4
5
5
let connectionPreface = " PRI * HTTP/2.0\r\n\r\n SM\r\n\r\n "
6
6
7
- type ErrorCode =
7
+ type ErrorCode =
8
8
| NoError
9
9
| ProtocolError
10
10
| InternalError
@@ -69,14 +69,14 @@ module Http2 =
69
69
let setPadded x = set x 3
70
70
let setPriority x = set x 5
71
71
72
- type FrameHeader = {
73
- // the length field allows payloads of up to 224224 bytes (~16MB) per frame
72
+ type FrameHeader = {
73
+ // the length field allows payloads of up to 2^24 bytes (~16MB) per frame
74
74
length : int32 ;
75
75
``type`` : byte ;
76
76
flags : byte ;
77
77
streamIdentifier : int32 }
78
78
79
- type Settings =
79
+ type Settings =
80
80
{ headerTableSize : int32
81
81
; enablePush : bool
82
82
; maxConcurrentStreams : int32 option
@@ -121,9 +121,10 @@ module Http2 =
121
121
Array.Reverse b
122
122
b
123
123
124
+ /// Get 31-bit int from 4-byte array (which MUST be in network order)
124
125
let get31Bit ( data : byte []) =
125
- data.[ 3 ] <- data.[ 3 ] &&& 128 uy
126
- BitConverter.ToInt32( data, 0 )
126
+ data.[ 0 ] <- data.[ 0 ] &&& 127 uy
127
+ BitConverter.ToInt32( checkEndianness data, 0 )
127
128
128
129
let get24BitBytes ( value : Int32 ) =
129
130
let bytes = BitConverter.GetBytes value
@@ -143,8 +144,8 @@ module Http2 =
143
144
let frameStreamIdData = Array.zeroCreate< byte> 4
144
145
Array.Copy ( bytes, 5 , frameStreamIdData, 0 , 4 )
145
146
146
- // turn of most significant bit
147
- let streamIdentifier = get31Bit ( checkEndianness frameStreamIdData)
147
+ // turn off most significant bit
148
+ let streamIdentifier = get31Bit frameStreamIdData
148
149
149
150
{ length = frameLength;
150
151
`` type `` = frameType;
@@ -163,11 +164,9 @@ module Http2 =
163
164
bytes.[ 3 ] <- header.`` type ``
164
165
bytes.[ 4 ] <- header.flags
165
166
166
- let encodedStreamIdentifier = BitConverter.GetBytes header.streamIdentifier
167
+ let encodedStreamIdentifier = BitConverter.GetBytes header.streamIdentifier |> checkEndianness
167
168
168
- encodedStreamIdentifier.[ 3 ] <- encodedStreamIdentifier.[ 3 ] &&& 128 uy
169
-
170
- let encodedStreamIdentifier = checkEndianness encodedStreamIdentifier
169
+ encodedStreamIdentifier.[ 0 ] <- encodedStreamIdentifier.[ 0 ] &&& 127 uy
171
170
172
171
bytes.[ 5 ] <- encodedStreamIdentifier.[ 0 ]
173
172
bytes.[ 6 ] <- encodedStreamIdentifier.[ 1 ]
@@ -181,7 +180,7 @@ module Http2 =
181
180
return parseFrameHeader bytes
182
181
}
183
182
184
- type Priority =
183
+ type Priority =
185
184
{ exclusive : bool
186
185
; streamIdentifier : int32
187
186
; weight: byte
@@ -216,7 +215,7 @@ module Http2 =
216
215
217
216
let parseData ( header : FrameHeader ) ( payload : byte []) =
218
217
assert ( header.`` type `` = 0 uy)
219
- // If a DATA frame is received whose stream identifier field is 0x0,
218
+ // If a DATA frame is received whose stream identifier field is 0x0,
220
219
// the recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
221
220
let isEndStream = ( header.flags &&& 0x1 uy) = 0x1 uy
222
221
let data = removePadding header payload
@@ -228,7 +227,7 @@ module Http2 =
228
227
if priority then
229
228
let dependecyData = Array.zeroCreate 4
230
229
Array.Copy( payload, 0 , dependecyData, 0 , 4 )
231
- let dependency = get31Bit ( checkEndianness dependecyData)
230
+ let dependency = get31Bit dependecyData
232
231
let weight = payload.[ 4 ]
233
232
234
233
Some ({ exclusive = true ; streamIdentifier = dependency; weight = weight})
@@ -284,7 +283,7 @@ module Http2 =
284
283
let data = removePadding header payload
285
284
let frameStreamIdData = Array.zeroCreate< byte> 4
286
285
Array.Copy ( data, 0 , frameStreamIdData, 0 , 4 )
287
- let streamIdentifier = get31Bit ( checkEndianness frameStreamIdData)
286
+ let streamIdentifier = get31Bit frameStreamIdData
288
287
let headerBlockFragment = Array.zeroCreate ( data.Length - 5 )
289
288
Array.Copy( data, headerBlockFragment, data.Length - 5 )
290
289
PushPromise ( streamIdentifier, headerBlockFragment)
@@ -299,7 +298,7 @@ module Http2 =
299
298
assert ( header.`` type `` = 7 uy)
300
299
let idData = Array.zeroCreate< byte> 4
301
300
Array.Copy ( payload, 0 , idData, 0 , 4 )
302
- let streamIdentifier = get31Bit ( checkEndianness idData)
301
+ let streamIdentifier = get31Bit idData
303
302
Array.Copy ( payload, 4 , idData, 0 , 4 )
304
303
let errorCode = BitConverter.ToUInt32 ( checkEndianness idData, 0 )
305
304
GoAway ( streamIdentifier, toErrorCode ( int errorCode), Array.sub payload 8 ( payload.Length - 8 ))
@@ -308,14 +307,14 @@ module Http2 =
308
307
assert ( header.`` type `` = 8 uy)
309
308
let idData = Array.zeroCreate< byte> 4
310
309
Array.Copy ( payload, 0 , idData, 0 , 4 )
311
- let windowSizeIncrement = get31Bit ( checkEndianness idData)
310
+ let windowSizeIncrement = get31Bit idData
312
311
WindowUpdate windowSizeIncrement
313
312
314
313
let parseContinuation ( header : FrameHeader ) ( payload : byte []) =
315
314
assert ( header.`` type `` = 8 uy)
316
315
Continuation payload
317
316
318
- let payloadDecoders : PayloadDecoder [] =
317
+ let payloadDecoders : PayloadDecoder [] =
319
318
[| parseData; parseHeaders; parsePriority; parseRstStream; parseSettings; parsePushPromise; parsePing;
320
319
parseGoAway; parseWindowUpdate; parseContinuation |]
321
320
@@ -331,15 +330,17 @@ module Http2 =
331
330
do ! t.write( ByteSegment( bytes, 0 , bytes.Length))
332
331
}
333
332
333
+ /// Poke a 16-bit int into a byte array in network byte order (big-endian)
334
334
let poke16 ( arr : byte array ) i w =
335
- arr.[ i] <- byte w
336
- arr.[ i + 1 ] <- byte ( w >>> 8 )
335
+ arr.[ i] <- byte ( w >>> 8 )
336
+ arr.[ i+ 1 ] <- byte w
337
337
338
+ /// Poke a 32-bit int into a byte array in network byte order (big-endian)
338
339
let poke32 ( arr : byte array ) i w =
339
- arr.[ i] <- byte w
340
- arr.[ i + 1 ] <- byte ( w >>> 8 )
341
- arr.[ i + 2 ] <- byte ( w >>> 0x10 )
342
- arr.[ i + 3 ] <- byte ( w >>> 0x18 )
340
+ arr.[ i] <- byte ( w >>> 0x18 )
341
+ arr.[ i + 1 ] <- byte ( w >>> 0x10 )
342
+ arr.[ i + 2 ] <- byte ( w >>> 8 )
343
+ arr.[ i + 3 ] <- byte w
343
344
344
345
let encodePriority priority =
345
346
let arr = Array.zeroCreate< byte> 5
@@ -353,16 +354,16 @@ module Http2 =
353
354
| Data ( bytes, flag) ->
354
355
{ length = bytes.Length; `` type `` = 0 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier} ,
355
356
[ bytes ]
356
- | Headers( None, bytes) ->
357
+ | Headers( None, bytes) ->
357
358
{ length = bytes.Length; `` type `` = 1 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier} ,
358
359
[ bytes ]
359
- | Headers( Some priority, bytes) ->
360
+ | Headers( Some priority, bytes) ->
360
361
{ length = bytes.Length + 5 ; `` type `` = 1 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier} ,
361
362
[ encodePriority priority ; bytes ]
362
- | Priority None ->
363
+ | Priority None ->
363
364
{ length = 0 ; `` type `` = 2 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier} ,
364
365
[[||]]
365
- | Priority ( Some priority) ->
366
+ | Priority ( Some priority) ->
366
367
{ length = 5 ; `` type `` = 2 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier} ,
367
368
[ encodePriority priority]
368
369
| RstStream errorCode ->
@@ -372,7 +373,7 @@ module Http2 =
372
373
[ b4 ]
373
374
| Settings ( flag, settings) ->
374
375
{ length = 36 ; `` type `` = 4 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier } ,
375
- [
376
+ [
376
377
for settingIdentifier in [ 1 .. 6 ] do
377
378
let arr = Array.zeroCreate< byte> 6
378
379
poke16 arr 0 settingIdentifier
@@ -402,27 +403,27 @@ module Http2 =
402
403
failwith " invalid setting identifier"
403
404
yield arr
404
405
]
405
- | PushPromise ( i, bytes) ->
406
+ | PushPromise ( i, bytes) ->
406
407
let b4 = Array.zeroCreate 4
407
408
poke32 b4 0 i
408
409
{ length = bytes.Length + 4 ; `` type `` = 5 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier } ,
409
- [ checkEndianness b4 ; bytes ]
410
+ [ b4 ; bytes ]
410
411
| Ping ( flag, bytes) ->
411
412
{ length = bytes.Length; `` type `` = 6 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier } ,
412
- [ bytes]
413
- | GoAway ( i, errorCode, bytes) ->
413
+ [ bytes]
414
+ | GoAway ( i, errorCode, bytes) ->
414
415
let a4 = Array.zeroCreate 4
415
416
let b4 = Array.zeroCreate 4
416
417
poke32 a4 0 i
417
418
poke32 b4 0 ( fromErrorCode errorCode)
418
419
{ length = bytes.Length + 8 ; `` type `` = 7 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier } ,
419
- [ checkEndianness a4; b4; bytes]
420
- | WindowUpdate w ->
420
+ [ a4; b4; bytes]
421
+ | WindowUpdate w ->
421
422
let b4 = Array.zeroCreate 4
422
423
poke32 b4 0 w
423
424
{ length = 4 ; `` type `` = 8 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier } ,
424
425
[ b4 ]
425
- | Continuation bytes ->
426
+ | Continuation bytes ->
426
427
{ length = bytes.Length; `` type `` = 9 uy ; flags = encodeInfo.flags; streamIdentifier = encodeInfo.streamIdentifier } ,
427
428
[ bytes ]
428
429
@@ -448,7 +449,7 @@ module Http2 =
448
449
449
450
open System.Collections .Generic
450
451
451
- let newDynamicRevIndex _ =
452
+ let newDynamicRevIndex _ =
452
453
Array.map ( fun _ -> new Dictionary< HeaderValue, HIndex>()) [| minTokenIx .. maxStaticTokenIndex |]
453
454
454
455
let newOtherRevIndex _ = new Dictionary< KeyValue, HIndex>()
@@ -463,7 +464,7 @@ module Http2 =
463
464
let buf = Array.zeroCreate huftmpsiz
464
465
let decoder = decode buf huftmpsiz
465
466
newDynamicTable maxsiz ( DecodeInfo( decoder, maxsiz))
466
-
467
+
467
468
open Suave.Utils
468
469
open System.Threading
469
470
@@ -480,10 +481,10 @@ module Http2 =
480
481
member val encodeDynamicTable = newDynamicTableForEncoding defaultDynamicTableSize
481
482
member val decodeDynamicTable = newDynamicTableForDecoding defaultDynamicTableSize 4096
482
483
483
- member x.read () : SocketOp < Frame > =
484
+ member x.read () : SocketOp < Frame > =
484
485
readFrame facade
485
486
486
- member x.write ( encInfo , p : FramePayload ) : SocketOp < unit > =
487
+ member x.write ( encInfo , p : FramePayload ) : SocketOp < unit > =
487
488
writeFrame encInfo p ( facade.GetCurrentContext() .connection.transport)
488
489
489
490
member x.writeResponseToFrame ( response : HttpResult ) = async {
@@ -502,14 +503,14 @@ module Http2 =
502
503
member x.send ( r : HttpRequest ) =
503
504
Async.Start ( procQueue.AsyncAdd <| Request r)
504
505
505
- member x.stop () =
506
+ member x.stop () =
506
507
Async.Start ( procQueue.AsyncAdd <| Stop)
507
508
closeEvent.WaitOne() |> ignore
508
509
509
510
member x.get () =
510
511
procQueue.AsyncGet()
511
512
512
- member x.writeLoop ( ctxOuter : HttpContext ) ( webPart : WebPart ) =
513
+ member x.writeLoop ( ctxOuter : HttpContext ) ( webPart : WebPart ) =
513
514
async {
514
515
// send an empty SETTINGS frame
515
516
let encInfo = { flags = 1 uy (* ack*) ; streamIdentifier = 0 ; padding = None}
0 commit comments