123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- using Microsoft.AspNetCore.Connections;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
- using System;
- using System.Buffers;
- using System.IO.Pipelines;
- using System.Text;
- using System.Threading.Tasks;
- namespace FastGithub.HttpServer.TcpMiddlewares
- {
- /// <summary>
- /// 正向代理中间件
- /// </summary>
- sealed class HttpProxyMiddleware
- {
- private readonly HttpParser<HttpRequestHandler> httpParser = new();
- private readonly byte[] http200 = Encoding.ASCII.GetBytes("HTTP/1.1 200 Connection Established\r\n\r\n");
- private readonly byte[] http400 = Encoding.ASCII.GetBytes("HTTP/1.1 400 Bad Request\r\n\r\n");
- /// <summary>
- /// 执行中间件
- /// </summary>
- /// <param name="next"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- public async Task InvokeAsync(ConnectionDelegate next, ConnectionContext context)
- {
- var input = context.Transport.Input;
- var output = context.Transport.Output;
- var request = new HttpRequestHandler();
- while (context.ConnectionClosed.IsCancellationRequested == false)
- {
- var result = await input.ReadAsync();
- if (result.IsCanceled)
- {
- break;
- }
- try
- {
- if (this.ParseRequest(result, request, out var consumed))
- {
- if (request.ProxyProtocol == ProxyProtocol.TunnelProxy)
- {
- input.AdvanceTo(consumed);
- await output.WriteAsync(this.http200, context.ConnectionClosed);
- }
- else
- {
- input.AdvanceTo(result.Buffer.Start);
- }
- context.Features.Set<IHttpProxyFeature>(request);
- await next(context);
- break;
- }
- else
- {
- input.AdvanceTo(result.Buffer.Start, result.Buffer.End);
- }
- if (result.IsCompleted)
- {
- break;
- }
- }
- catch (Exception)
- {
- await output.WriteAsync(this.http400, context.ConnectionClosed);
- break;
- }
- }
- }
- /// <summary>
- /// 解析http请求
- /// </summary>
- /// <param name="result"></param>
- /// <param name="requestHandler"></param>
- /// <param name="consumed"></param>
- /// <returns></returns>
- private bool ParseRequest(ReadResult result, HttpRequestHandler request, out SequencePosition consumed)
- {
- var reader = new SequenceReader<byte>(result.Buffer);
- if (this.httpParser.ParseRequestLine(request, ref reader) &&
- this.httpParser.ParseHeaders(request, ref reader))
- {
- consumed = reader.Position;
- return true;
- }
- else
- {
- consumed = default;
- return false;
- }
- }
- /// <summary>
- /// 代理请求处理器
- /// </summary>
- private class HttpRequestHandler : IHttpRequestLineHandler, IHttpHeadersHandler, IHttpProxyFeature
- {
- private HttpMethod method;
- public HostString ProxyHost { get; private set; }
- public ProxyProtocol ProxyProtocol
- {
- get
- {
- if (this.ProxyHost.HasValue == false)
- {
- return ProxyProtocol.None;
- }
- if (this.method == HttpMethod.Connect)
- {
- return ProxyProtocol.TunnelProxy;
- }
- return ProxyProtocol.HttpProxy;
- }
- }
- void IHttpRequestLineHandler.OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span<byte> startLine)
- {
- this.method = versionAndMethod.Method;
- var host = Encoding.ASCII.GetString(startLine.Slice(targetPath.Offset, targetPath.Length));
- if (versionAndMethod.Method == HttpMethod.Connect)
- {
- this.ProxyHost = HostString.FromUriComponent(host);
- }
- else if (Uri.TryCreate(host, UriKind.Absolute, out var uri))
- {
- this.ProxyHost = HostString.FromUriComponent(uri);
- }
- }
- void IHttpHeadersHandler.OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
- {
- }
- void IHttpHeadersHandler.OnHeadersComplete(bool endStream)
- {
- }
- void IHttpHeadersHandler.OnStaticIndexedHeader(int index)
- {
- }
- void IHttpHeadersHandler.OnStaticIndexedHeader(int index, ReadOnlySpan<byte> value)
- {
- }
- }
- }
- }
|