protected override async Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { if (connection == null) { connection = new Http2Connection (request.RequestUri.Host, (uint)request.RequestUri.Port, request.RequestUri.Scheme == Uri.UriSchemeHttps); } else { // TODO: Check if they tried to use a new host/port } await connection.Connect (); var resetComplete = new ManualResetEventSlim (false); var stream = await connection.CreateStream (); stream.OnFrameReceived += frame => { if (frame.IsEndStream) resetComplete.Set (); }; var headersFrame = new HeadersFrame (stream.StreamIdentifer); headersFrame.Headers.Add (":method", request.Method.Method.ToUpperInvariant ()); headersFrame.Headers.Add (":path", request.RequestUri.PathAndQuery); headersFrame.Headers.Add (":scheme", request.RequestUri.Scheme); headersFrame.Headers.Add (":authority", request.RequestUri.Authority); headersFrame.EndHeaders = true; headersFrame.EndStream = true; await connection.SendFrame (headersFrame); resetComplete.Wait (connection.ConnectionTimeout); var responseData = new List<byte> (); var responseHeaders = new NameValueCollection (); foreach (var f in stream.Frames) { if (f.Type == FrameType.Headers) { responseHeaders = (f as HeadersFrame)?.Headers ?? new NameValueCollection (); } else if (f.Type == FrameType.Data) { responseData.AddRange ((f as DataFrame).Data); //responseData += Encoding.ASCII.GetString ((f as DataFrame).Data); } else if (f.Type == FrameType.Continuation) { // TODO: } } var httpStatusStr = responseHeaders.GetValues (":status")?.FirstOrDefault (); var httpStatus = HttpStatusCode.InternalServerError; Enum.TryParse<HttpStatusCode> (httpStatusStr, out httpStatus); var httpResponseMsg = new HttpResponseMessage (httpStatus); foreach (var h in responseHeaders.AllKeys) { if (!h.StartsWith (":")) httpResponseMsg.Headers.TryAddWithoutValidation (h, responseHeaders [h]); } httpResponseMsg.Content = new ByteArrayContent (responseData.ToArray ()); return httpResponseMsg; }
async void read() { int rx = 0; byte[] b = new byte[4096]; while (true) { try { rx = await clientStream.ReadAsync(b, 0, b.Length); } catch { rx = -1; } if (rx > 0) { Console.WriteLine("RX: {0} bytes", rx); for (int i = 0; i < rx; i++) { buffer.Add(b [i]); } while (true) { // We need at least 9 bytes to process the frame // 9 octets is the frame header length if (buffer.Count < 9) { break; } // Find out the frame length // which is a 24 bit uint, so we need to convert this as c# uint is 32 bit var flen = new byte[4]; flen [0] = 0x0; flen [1] = buffer.ElementAt(0); flen [2] = buffer.ElementAt(1); flen [3] = buffer.ElementAt(2); var frameLength = BitConverter.ToUInt32(flen.EnsureBigEndian(), 0); // If we are expecting a payload that's bigger than what's in our buffer // we should keep reading from the stream if (buffer.Count - 9 < frameLength) { break; } // If we made it this far, the buffer has all the data we need, let's get it out to process var data = buffer.GetRange(0, (int)frameLength + 9).ToArray(); // remove the processed info from the buffer buffer.RemoveRange(0, (int)frameLength + 9); // Get the Frame Type so we can instantiate the right subclass var frameType = data [3]; // 4th byte in frame header is TYPE // Don't need the flags yet //var frameFlags = data [4]; // 5th byte is FLAGS // we need to turn the stream id into a uint var frameStreamIdData = new byte[4]; Array.Copy(data, 5, frameStreamIdData, 0, 4); uint frameStreamId = Util.ConvertFromUInt31(frameStreamIdData.EnsureBigEndian()); Frame frame = null; var ft = (FrameType)frameType; switch (ft) { case FrameType.Data: frame = new DataFrame(); break; case FrameType.Headers: frame = new HeadersFrame(); break; case FrameType.Priority: frame = new PriorityFrame(); break; case FrameType.RstStream: frame = new RstStreamFrame(); break; case FrameType.Settings: frame = new SettingsFrame(); break; case FrameType.PushPromise: frame = new PushPromiseFrame(); break; case FrameType.Ping: frame = new PingFrame(); break; case FrameType.GoAway: frame = new GoAwayFrame(); break; case FrameType.WindowUpdate: frame = new WindowUpdateFrame(); break; case FrameType.Continuation: frame = new ContinuationFrame(); break; } try { // Call the specific subclass implementation to parse if (frame != null) { frame.Parse(data); } } catch (Exception ex) { Console.WriteLine("Parsing Frame Failed: " + ex); throw ex; } // If we are waiting on the connection preface from server // and it's the right frame type, set our resetevent if (ft == FrameType.Settings && resetEventConnectionSettingsFrame != null && !resetEventConnectionSettingsFrame.IsSet) { var settingsFrame = frame as SettingsFrame; // ack the settings from the server settingsFrame.Ack = true; await SendFrame(settingsFrame); resetEventConnectionSettingsFrame.Set(); } try { if (frameStreamId == 0) { foreach (var s in Streams) { if (s.Value.State != StreamState.Closed) { s.Value.ProcessFrame(frame); } } } else { var stream = await GetStream(frameStreamId); stream.ProcessFrame(frame); } } catch (Exception ex) { Console.WriteLine("Error Processing Frame: " + ex); throw ex; } } } else { // TODO: Connection error //throw new Exception ("Connection Error"); break; } } Disconnect(); }
public async Task<Http2Response> Send (Uri uri, HttpMethod method, NameValueCollection headers = null, byte[] data = null) { var semaphoreClose = new SemaphoreSlim(0); await connection.Connect (); var stream = await connection.CreateStream (); stream.OnFrameReceived += (frame) => { if (stream.State == StreamState.Closed) semaphoreClose.Release(); }; //await connection.SendFrame(new SettingsFrame()); var headersFrame = new HeadersFrame (stream.StreamIdentifer); headersFrame.Headers.Add (":method", method.Method.ToUpperInvariant ()); headersFrame.Headers.Add (":path", uri.PathAndQuery); headersFrame.Headers.Add (":scheme", uri.Scheme); headersFrame.Headers.Add (":authority", uri.Authority); if (headers != null && headers.Count > 0) headersFrame.Headers.Add (headers); headersFrame.EndHeaders = true; if (data != null && data.Length > 0) { await connection.SendFrame (headersFrame); var dataFrame = new DataFrame (stream.StreamIdentifer); dataFrame.Data = data; dataFrame.EndStream = true; await connection.SendFrame (dataFrame); } else { headersFrame.EndStream = true; await connection.SendFrame (headersFrame); } if (!await semaphoreClose.WaitAsync (connection.ConnectionTimeout)) throw new TimeoutException (); var responseData = new List<byte> (); var responseHeaders = new NameValueCollection (); foreach (var f in stream.Frames) { if (f.Type == FrameType.Headers) { responseHeaders = (f as HeadersFrame)?.Headers ?? new NameValueCollection (); } else if (f.Type == FrameType.Data) { responseData.AddRange ((f as DataFrame).Data); } else if (f.Type == FrameType.Continuation) { var h = (f as ContinuationFrame).Headers ?? new NameValueCollection (); responseHeaders.Add (h); } else if (f.Type == FrameType.GoAway) { var fga = f as GoAwayFrame; if (fga != null && fga.AdditionalDebugData != null && fga.AdditionalDebugData.Length > 0) responseData.AddRange (fga.AdditionalDebugData); } } var strStatus = "500"; if (responseHeaders [":status"] != null) strStatus = responseHeaders [":status"]; var statusCode = HttpStatusCode.OK; Enum.TryParse<HttpStatusCode> (strStatus, out statusCode); return new Http2Response { Status = statusCode, Stream = stream, Headers = responseHeaders, Body = responseData.ToArray () }; }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { if (connection == null) { connection = new Http2Connection(request.RequestUri.Host, (uint)request.RequestUri.Port, request.RequestUri.Scheme == Uri.UriSchemeHttps); } else { // TODO: Check if they tried to use a new host/port } await connection.Connect(); var resetComplete = new ManualResetEventSlim(false); var stream = await connection.CreateStream(); stream.OnFrameReceived += frame => { if (frame.IsEndStream) { resetComplete.Set(); } }; var headersFrame = new HeadersFrame(stream.StreamIdentifer); headersFrame.Headers.Add(":method", request.Method.Method.ToUpperInvariant()); headersFrame.Headers.Add(":path", request.RequestUri.PathAndQuery); headersFrame.Headers.Add(":scheme", request.RequestUri.Scheme); headersFrame.Headers.Add(":authority", request.RequestUri.Authority); headersFrame.EndHeaders = true; headersFrame.EndStream = true; await connection.SendFrame(headersFrame); resetComplete.Wait(connection.ConnectionTimeout); var responseData = new List <byte> (); var responseHeaders = new NameValueCollection(); foreach (var f in stream.Frames) { if (f.Type == FrameType.Headers) { responseHeaders = (f as HeadersFrame)?.Headers ?? new NameValueCollection(); } else if (f.Type == FrameType.Data) { responseData.AddRange((f as DataFrame).Data); //responseData += Encoding.ASCII.GetString ((f as DataFrame).Data); } else if (f.Type == FrameType.Continuation) { // TODO: } } var httpStatusStr = responseHeaders.GetValues(":status")?.FirstOrDefault(); var httpStatus = HttpStatusCode.InternalServerError; Enum.TryParse <HttpStatusCode> (httpStatusStr, out httpStatus); var httpResponseMsg = new HttpResponseMessage(httpStatus); foreach (var h in responseHeaders.AllKeys) { if (!h.StartsWith(":")) { httpResponseMsg.Headers.TryAddWithoutValidation(h, responseHeaders [h]); } } httpResponseMsg.Content = new ByteArrayContent(responseData.ToArray()); return(httpResponseMsg); }
public async Task <Http2Response> Send(Uri uri, HttpMethod method, NameValueCollection headers = null, byte[] data = null) { var semaphoreClose = new SemaphoreSlim(0); await connection.Connect(); var stream = await connection.CreateStream(); stream.OnFrameReceived += (frame) => { if (stream.State == StreamState.Closed) { semaphoreClose.Release(); } }; //await connection.SendFrame(new SettingsFrame()); var headersFrame = new HeadersFrame(stream.StreamIdentifer); headersFrame.Headers.Add(":method", method.Method.ToUpperInvariant()); headersFrame.Headers.Add(":path", uri.PathAndQuery); headersFrame.Headers.Add(":scheme", uri.Scheme); headersFrame.Headers.Add(":authority", uri.Authority); if (headers != null && headers.Count > 0) { headersFrame.Headers.Add(headers); } headersFrame.EndHeaders = true; if (data != null && data.Length > 0) { await connection.SendFrame(headersFrame); var dataFrame = new DataFrame(stream.StreamIdentifer); dataFrame.Data = data; dataFrame.EndStream = true; await connection.SendFrame(dataFrame); } else { headersFrame.EndStream = true; await connection.SendFrame(headersFrame); } if (!await semaphoreClose.WaitAsync(connection.ConnectionTimeout)) { throw new TimeoutException(); } var responseData = new List <byte> (); var responseHeaders = new NameValueCollection(); foreach (var f in stream.Frames) { if (f.Type == FrameType.Headers) { responseHeaders = (f as HeadersFrame)?.Headers ?? new NameValueCollection(); } else if (f.Type == FrameType.Data) { responseData.AddRange((f as DataFrame).Data); } else if (f.Type == FrameType.Continuation) { var h = (f as ContinuationFrame).Headers ?? new NameValueCollection(); responseHeaders.Add(h); } else if (f.Type == FrameType.GoAway) { var fga = f as GoAwayFrame; if (fga != null && fga.AdditionalDebugData != null && fga.AdditionalDebugData.Length > 0) { responseData.AddRange(fga.AdditionalDebugData); } } } var strStatus = "500"; if (responseHeaders [":status"] != null) { strStatus = responseHeaders [":status"]; } var statusCode = HttpStatusCode.OK; Enum.TryParse <HttpStatusCode> (strStatus, out statusCode); return(new Http2Response { Status = statusCode, Stream = stream, Headers = responseHeaders, Body = responseData.ToArray() }); }
async void read () { int rx = 0; byte[] b = new byte[4096]; while (true) { try { rx = await clientStream.ReadAsync(b, 0, b.Length); } catch { rx = -1; } if (rx > 0) { Console.WriteLine ("RX: {0} bytes", rx); for (int i = 0; i < rx; i++) buffer.Add (b [i]); while (true) { // We need at least 9 bytes to process the frame // 9 octets is the frame header length if (buffer.Count < 9) break; // Find out the frame length // which is a 24 bit uint, so we need to convert this as c# uint is 32 bit var flen = new byte[4]; flen [0] = 0x0; flen [1] = buffer.ElementAt (0); flen [2] = buffer.ElementAt (1); flen [3] = buffer.ElementAt (2); var frameLength = BitConverter.ToUInt32 (flen.EnsureBigEndian (), 0); // If we are expecting a payload that's bigger than what's in our buffer // we should keep reading from the stream if (buffer.Count - 9 < frameLength) break; // If we made it this far, the buffer has all the data we need, let's get it out to process var data = buffer.GetRange (0, (int)frameLength + 9).ToArray (); // remove the processed info from the buffer buffer.RemoveRange (0, (int)frameLength + 9); // Get the Frame Type so we can instantiate the right subclass var frameType = data [3]; // 4th byte in frame header is TYPE // Don't need the flags yet //var frameFlags = data [4]; // 5th byte is FLAGS // we need to turn the stream id into a uint var frameStreamIdData = new byte[4]; Array.Copy (data, 5, frameStreamIdData, 0, 4); uint frameStreamId = Util.ConvertFromUInt31 (frameStreamIdData.EnsureBigEndian ()); Frame frame = null; var ft = (FrameType)frameType; switch (ft) { case FrameType.Data: frame = new DataFrame (); break; case FrameType.Headers: frame = new HeadersFrame (); break; case FrameType.Priority: frame = new PriorityFrame (); break; case FrameType.RstStream: frame = new RstStreamFrame (); break; case FrameType.Settings: frame = new SettingsFrame (); break; case FrameType.PushPromise: frame = new PushPromiseFrame (); break; case FrameType.Ping: frame = new PingFrame (); break; case FrameType.GoAway: frame = new GoAwayFrame (); break; case FrameType.WindowUpdate: frame = new WindowUpdateFrame (); break; case FrameType.Continuation: frame = new ContinuationFrame (); break; } try { // Call the specific subclass implementation to parse if (frame != null) frame.Parse (data); } catch (Exception ex) { Console.WriteLine ("Parsing Frame Failed: " + ex); throw ex; } // If we are waiting on the connection preface from server // and it's the right frame type, set our resetevent if (ft == FrameType.Settings && resetEventConnectionSettingsFrame != null && !resetEventConnectionSettingsFrame.IsSet) { var settingsFrame = frame as SettingsFrame; // ack the settings from the server settingsFrame.Ack = true; await SendFrame (settingsFrame); resetEventConnectionSettingsFrame.Set (); } try { if (frameStreamId == 0) { foreach (var s in Streams) { if (s.Value.State != StreamState.Closed) s.Value.ProcessFrame(frame); } } else { var stream = await GetStream(frameStreamId); stream.ProcessFrame(frame); } } catch (Exception ex) { Console.WriteLine ("Error Processing Frame: " + ex); throw ex; } } } else { // TODO: Connection error //throw new Exception ("Connection Error"); break; } } Disconnect(); }