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;
        }
Exemple #2
0
        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();
        }
Exemple #3
0
        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 ()
            };
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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()
            });
        }
Exemple #6
0
        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();
        }