| 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;
- }
- }
- }
- }
|