You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Gateway/HttpMimeSocket.cs

314 lines
8.8 KiB
C#

using System;
using System.Buffers;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using UMC.Net;
namespace UMC.Host
{
public class HttpMimeSocket : HttpMime
{
String _scheme = "http";
public override string Scheme => _scheme;
int _timeOut = 20;
public int TimeOut => _timeOut;
public HttpMimeSocket(String scheme, System.IO.Stream stream, String host, String ip)
{
_scheme = scheme;
this._stream = stream;
this.ActiveTime = UMC.Data.Utility.TimeSpan();
this.pid = stream.GetHashCode();
this._Host = host;
this._remoteIpAddress = ip;
HttpMimeServier.httpMimes.TryAdd(pid, this);
Read(new HttpMimeRequest(this));
}
Stream _stream;
int pid = 0;
public int Id => pid;
String _remoteIpAddress, _Host;
public override String Host => _Host;
public override String RemoteIpAddress => _remoteIpAddress;
public override void Write(byte[] buffer, int offset, int count)
{
if (isDispose == false)
{
try
{
_stream.Write(buffer, offset, count);
}
catch
{
this.Dispose();
}
}
}
public override void OutputFinish()
{
try
{
Read(new HttpMimeRequest(this));
this.ActiveTime = UMC.Data.Utility.TimeSpan();
_timeOut = 20;
}
catch
{
this.Dispose();
}
}
public override void PrepareRespone(HttpMimeRequest httpMimeRequest)
{
_timeOut = 300;
base.PrepareRespone(httpMimeRequest);
}
public override void Subscribe(HttpMimeRequest webRequest)
{
var _subscribe = UMC.Net.NetSubscribe.Subscribe(webRequest.Headers, webRequest.UserHostAddress, HttpMimeServier.Server, _stream, UMC.Data.WebResource.Instance().Provider["appSecret"]);
if (_subscribe != null)
{
HttpMimeSocket link;
HttpMimeServier.httpMimes.TryRemove(pid, out link);
var writer = new Net.TextWriter(this.Write, _data);
writer.Write($"HTTP/1.1 101 {HttpStatusDescription.Get(101)}\r\n");
writer.Write("Connection: upgrade\r\n");
writer.Write("Upgrade: websocket\r\n");
writer.Write($"UMC-Publisher-Key: {HttpMimeServier.Server}\r\n");
writer.Write("Server: UMC.Proxy\r\n\r\n");
writer.Flush();
writer.Dispose();
_subscribe.Publish();
}
else
{
OutText(401, "连接验证不通过");
}
}
protected override void WebSocket(NetContext context)
{
if (context.Tag is HttpWebRequest)
{
var webr = context.Tag as HttpWebRequest;
this.WebSocket(webr);
}
else
{
HttpWebSocket.AcceptWebSocketAsyncCore(context, _stream);
}
}
public int ActiveTime
{
get; set;
}
bool isDispose = false;
public override void Dispose()
{
if (isDispose == false)
{
isDispose = true;
try
{
_stream.Close();
_stream.Dispose();
_data = null;
if (_webSocket != null)
{
_webSocket.Dispose();
}
}
catch
{
}
}
HttpMimeServier.httpMimes.TryRemove(pid, out var _);
}
async void WebSocket(HttpWebRequest webRequest)
{
try
{
var url = webRequest.RequestUri;
if (webRequest.CookieContainer != null)
{
String cookie;
if (webRequest.CookieContainer is Net.NetCookieContainer)
{
cookie = ((Net.NetCookieContainer)webRequest.CookieContainer).GetCookieHeader(url);
}
else
{
cookie = webRequest.CookieContainer.GetCookieHeader(url);
}
if (String.IsNullOrEmpty(cookie) == false)
{
webRequest.Headers[HttpRequestHeader.Cookie] = cookie;
}
}
if (String.IsNullOrEmpty(webRequest.Headers[HttpRequestHeader.Host]))
{
webRequest.Headers[HttpRequestHeader.Host] = webRequest.Host;
}
webRequest.Headers["Connection"] = "Upgrade";
var client = new Socket(SocketType.Stream, ProtocolType.Tcp);
await client.ConnectAsync(url.Host, url.Port);
_webSocket = new WebSocketer();
if (url.Scheme == "https")
{
SslStream ssl = new SslStream(new NetworkStream(client, true), false, (sender, certificate, chain, sslPolicyErrors) => true);
await ssl.AuthenticateAsClientAsync(url.Host, new X509CertificateCollection(), SslProtocols.None, false);
_webSocket.stream = ssl;
}
else
{
_webSocket.stream = new NetworkStream(client, true);
}
WebSocketWrite();
await _webSocket.stream.WriteAsync(_webSocket.buffer, 0, UMC.Net.NetHttpResponse.Header(webRequest, _webSocket.buffer));
WebSocketRead();
HttpMimeServier.httpMimes.TryRemove(this.pid, out var _);
}
catch (Exception ex)
{
OutText(500, ex.ToString());
}
}
class WebSocketer : IDisposable
{
public byte[] buffer = new byte[0x600];
public System.IO.Stream stream;
public void Dispose()
{
stream.Close();
stream.Dispose();
buffer = null;
}
}
WebSocketer _webSocket;
byte[] _data = new byte[0x600];
async void WebSocketRead()
{
int size = 0;
try
{
size = await _webSocket.stream.ReadAsync(_webSocket.buffer, 0, _webSocket.buffer.Length);
if (size > 0)
{
await _stream.WriteAsync(_webSocket.buffer, 0, size);
WebSocketRead();
}
else
{
this.Dispose();
}
}
catch
{
this.Dispose();
}
}
async void WebSocketWrite()
{
this.ActiveTime = UMC.Data.Utility.TimeSpan();
int size = 0;
try
{
size = await _stream.ReadAsync(this._data, 0, this._data.Length);
await _webSocket.stream.WriteAsync(_data, 0, size);
WebSocketWrite();
}
catch
{
this.Dispose();
}
}
async void Read(HttpMimeRequest req)
{
int size = 0;
try
{
size = await _stream.ReadAsync(this._data, 0, this._data.Length);
}
catch
{
this.Dispose();
return;
}
if (size > 0)
{
this.ActiveTime = UMC.Data.Utility.TimeSpan();
try
{
req.Receive(this._data, 0, size);
}
catch (Exception ex)
{
this.OutText(500, ex.ToString());
return;
}
}
else
{
this.Dispose();
return;
}
if (req.IsHttpFormatError)
{
req.Dispose();
this.Dispose();
return;
}
if (req.IsWebSocket == false && req.IsMimeFinish == false)
{
Read(req);
}
}
}
}