private byte[] SerializeControlFrameHeaders(ProtocolHeaders frameHeaders) { var headers = new List <byte>(256); headers.AddRange(BinaryHelper.Int32ToBytes(frameHeaders.Count)); foreach (KeyValuePair <string, string> pair in frameHeaders) { byte[] nameBin = Encoding.UTF8.GetBytes(pair.Key); headers.AddRange(BinaryHelper.Int32ToBytes(nameBin.Length)); headers.AddRange(nameBin); byte[] valBin = Encoding.UTF8.GetBytes(pair.Value); headers.AddRange(BinaryHelper.Int32ToBytes(valBin.Length)); headers.AddRange(valBin); } return(headers.ToArray()); }
/// <summary> /// Parses HTTP header of Http2 data frame. /// </summary> /// <param name="frame">The frame.</param> /// <param name="data">The data.</param> private static void ParseDataFrameHeader(ref DataFrame frame, byte[] data) { frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 0, 4), 0); frame.Flags = data[4]; frame.IsFinal = (frame.Flags & 0x01) != 0; }
/// <summary> /// Deserializes the data into control frame. /// </summary> /// <param name="data">The data.</param> /// <returns>Deserialized frame.</returns> private BaseFrame DeserializeControlFrame(byte[] data) { FrameType type = GetFrameType(data); ControlFrame frame = new ControlFrame(); switch (type) { case FrameType.RTS: frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 8, 4)); frame.StatusCode = (StatusCode)BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 12, 4)); break; case FrameType.Headers: case FrameType.SynReply: ParseControlFrameHeader(ref frame, data); frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 8, 4)); ParseControlFrameHeaders(ref frame, data, 12); break; case FrameType.SynStream: ParseControlFrameHeader(ref frame, data); frame.StreamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 8, 4)); frame.AssociatedToStreamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 12, 4)); frame.Priority = (byte)(data[16] >> 5); frame.Slot = data[17]; ParseControlFrameHeaders(ref frame, data, 18); break; case FrameType.Settings: int numberOfEntries = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 8, 4)); frame = new SettingsFrame(numberOfEntries); int headersOffset = 12; for (int i = 0; i < numberOfEntries; i++) { int key = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, headersOffset, 4)); headersOffset += 4; int value = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, headersOffset, 4)); headersOffset += 4; frame.SettingsHeaders.Add(key, value); } ParseControlFrameHeader(ref frame, data); break; case FrameType.GoAway: int lastSeenGoodStreamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 8, 4)); StatusCode status = StatusCode.Success; if (data.Length > 12) { status = (StatusCode)BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 12, 4)); } frame = new GoAwayFrame(lastSeenGoodStreamId, status); ParseControlFrameHeader(ref frame, data); break; case FrameType.Ping: int streamID = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 4, 4)); frame = new ControlFrame { StreamId = streamID }; ParseControlFrameHeader(ref frame, data); break; case FrameType.WindowUpdate: int streamId = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 4, 4)); int deltaWindowSize = BinaryHelper.Int32FromBytes(new ArraySegment <byte>(data, 8, 4)); frame = new WindowUpdateFrame(streamId, deltaWindowSize); ParseControlFrameHeader(ref frame, data); break; } frame.Type = type; return(frame); }
private FrameType GetFrameType(byte[] data) { return((FrameType)BinaryHelper.Int16FromBytes(data[2], data[3])); }
/// <summary> /// Serializes the control frame. /// </summary> /// <param name="frame">The frame.</param> /// <returns>Serialized control frame.</returns> private byte[] SerializeControlFrame(ControlFrame frame) { var byteList = new List <byte>(); byteList.Add((byte)(((frame.Version & 0xFF00) >> 8) | 0x80)); byteList.Add((byte)(frame.Version & 0x00FF)); byteList.Add((byte)(((Int16)frame.Type & 0xFF00) >> 8)); byteList.Add((byte)((Int16)frame.Type & 0x00FF)); var headersArray = new byte[0]; switch (frame.Type) { case FrameType.SynStream: byteList.Add(Convert.ToByte(frame.Flags | (frame.IsFinal ? 0x01 : 0x00))); headersArray = SerializeControlFrameHeaders(frame.Headers); if (headersArray.Length > 0) { ProcessorRun(ref headersArray, DirectionProcessType.Outbound, frame.Flags); } byteList.AddRange(BinaryHelper.Int32ToBytes(headersArray.Length + 10, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); byteList.AddRange(BinaryHelper.Int32ToBytes(0)); byteList.Add(Convert.ToByte(frame.Priority >> 5)); byteList.Add(Unused); break; case FrameType.RTS: byteList.Add(0); byteList.AddRange(BinaryHelper.Int32ToBytes(headersArray.Length + 8, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); byteList.AddRange(BinaryHelper.Int32ToBytes((int)frame.StatusCode)); break; case FrameType.SynReply: byteList.Add(frame.Flags); headersArray = SerializeControlFrameHeaders(frame.Headers); if (headersArray.Length > 0) { ProcessorRun(ref headersArray, DirectionProcessType.Outbound, frame.Flags); } byteList.AddRange(BinaryHelper.Int32ToBytes(headersArray.Length + 4, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); break; case FrameType.GoAway: byteList.Add(frame.Flags); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); byteList.AddRange(BinaryHelper.Int32ToBytes((int)frame.StatusCode)); break; case FrameType.Ping: byteList.Add(frame.Flags); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); break; case FrameType.WindowUpdate: byteList.Add(frame.Flags); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.StreamId)); byteList.AddRange(BinaryHelper.Int64ToBytes(((WindowUpdateFrame)frame).DeltaWindowSize)); break; case FrameType.Settings: byteList.Add(frame.Flags); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.Length, 3)); byteList.AddRange(BinaryHelper.Int32ToBytes(frame.NumberOfEntries)); break; } byteList.AddRange(headersArray); return(byteList.ToArray()); }