| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 | using System;using System.Collections.Generic;using System.Net;using System.Net.Sockets;using System.Text;namespace Renci.SshNet.Tests.Common{    public class HttpProxyStub : IDisposable    {        private readonly IPEndPoint _endPoint;        private AsyncSocketListener _listener;        private HttpRequestParser _httpRequestParser;        private readonly IList<byte[]> _responses;        public HttpProxyStub(IPEndPoint endPoint)        {            _endPoint = endPoint;            _responses = new List<byte[]>();        }        public HttpRequest HttpRequest        {            get            {                if (_httpRequestParser == null)                {                    throw new InvalidOperationException("The proxy is not started.");                }                return _httpRequestParser.HttpRequest;            }        }        public IList<byte[]> Responses        {            get { return _responses; }        }        public void Start()        {            _httpRequestParser = new HttpRequestParser();            _listener = new AsyncSocketListener(_endPoint);            _listener.BytesReceived += OnBytesReceived;            _listener.Start();        }        public void Stop()        {            _listener?.Stop();        }        public void Dispose()        {            Stop();            GC.SuppressFinalize(this);        }        private void OnBytesReceived(byte[] bytesReceived, Socket socket)        {            _httpRequestParser.ProcessData(bytesReceived);            if (_httpRequestParser.CurrentState == HttpRequestParser.State.Content)            {                foreach (var response in Responses)                {                    _ = socket.Send(response);                }                socket.Shutdown(SocketShutdown.Send);            }        }        private class HttpRequestParser        {            private readonly List<byte> _buffer;            private readonly HttpRequest _httpRequest;            public enum State            {                RequestLine,                Headers,                Content            }            public HttpRequestParser()            {                CurrentState = State.RequestLine;                _buffer = new List<byte>();                _httpRequest = new HttpRequest();            }            public HttpRequest HttpRequest            {                get { return _httpRequest; }            }            public State CurrentState { get; private set; }            public void ProcessData(byte[] data)            {                var position = 0;                while (position != data.Length)                {                    if (CurrentState == State.RequestLine)                    {                        var requestLine = ReadLine(data, ref position);                        if (requestLine != null)                        {                            _httpRequest.RequestLine = requestLine;                            CurrentState = State.Headers;                        }                    }                    if (CurrentState == State.Headers)                    {                        var line = ReadLine(data, ref position);                        if (line != null)                        {                            if (line.Length == 0)                            {                                CurrentState = State.Content;                            }                            else                            {                                _httpRequest.Headers.Add(line);                            }                        }                    }                    if (CurrentState == State.Content)                    {                        if (position < data.Length)                        {                            var currentContent = _httpRequest.MessageBody;                            var newBufferSize = currentContent.Length + (data.Length - position);                            var copyBuffer = new byte[newBufferSize];                            Array.Copy(currentContent, copyBuffer, currentContent.Length);                            Array.Copy(data, position, copyBuffer, currentContent.Length, data.Length - position);                            _httpRequest.MessageBody = copyBuffer;                            break;                        }                    }                }            }            private string ReadLine(byte[] data, ref int position)            {                for (; position < data.Length; position++)                {                    var b = data[position];                    if (b == '\n')                    {                        var buffer = _buffer.ToArray();                        var bytesInLine = buffer.Length;                        // when the previous byte was a CR, then do not include it in line                        if (buffer.Length > 0 && buffer[buffer.Length - 1] == '\r')                        {                            bytesInLine -= 1;                        }                        // clear the buffer                        _buffer.Clear();                        // move position up one position as we've processed the current byte                        position++;                        return Encoding.ASCII.GetString(buffer, 0, bytesInLine);                    }                    _buffer.Add(b);                }                return null;            }        }    }}
 |