123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- 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 result = await context.Transport.Input.ReadAsync();
- var httpRequest = this.GetHttpRequestHandler(result, out var consumed);
- // 协议错误
- if (consumed == 0L)
- {
- await context.Transport.Output.WriteAsync(this.http400, context.ConnectionClosed);
- }
- else
- {
- // 隧道代理连接请求
- if (httpRequest.ProxyProtocol == ProxyProtocol.TunnelProxy)
- {
- var position = result.Buffer.GetPosition(consumed);
- context.Transport.Input.AdvanceTo(position);
- await context.Transport.Output.WriteAsync(this.http200, context.ConnectionClosed);
- }
- else
- {
- var position = result.Buffer.Start;
- context.Transport.Input.AdvanceTo(position);
- }
- context.Features.Set<IHttpProxyFeature>(httpRequest);
- await next(context);
- }
- }
- /// <summary>
- /// 获取http请求处理者
- /// </summary>
- /// <param name="result"></param>
- /// <param name="consumed"></param>
- /// <returns></returns>
- private HttpRequestHandler GetHttpRequestHandler(ReadResult result, out long consumed)
- {
- var handler = new HttpRequestHandler();
- var reader = new SequenceReader<byte>(result.Buffer);
- if (this.httpParser.ParseRequestLine(handler, ref reader) &&
- this.httpParser.ParseHeaders(handler, ref reader))
- {
- consumed = reader.Consumed;
- }
- else
- {
- consumed = 0L;
- }
- return handler;
- }
- /// <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)
- {
- }
- }
- }
- }
|