Cleanup network module.

This commit is contained in:
2023-07-04 11:12:27 +08:00
parent a4d0e3867a
commit f65e4f1900
12 changed files with 71 additions and 99 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1a624371d4108614b9cdc4acca1499e2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -4,12 +4,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public class HttpClient { public class Http11Client {
private readonly string _directHost; private readonly string _directHost;
protected string DirectHost { get { return _directHost; } } protected string DirectHost { get { return _directHost; } }
@@ -19,29 +18,17 @@ namespace Cryville.Common.Network {
readonly Uri _baseUri; readonly Uri _baseUri;
readonly int origPort; readonly int origPort;
protected string Version = "HTTP/1.1"; protected const string Version = "HTTP/1.1";
protected TcpClient TcpClient { get; private set; } protected TcpClient TcpClient { get; private set; }
protected Stream RawTcpStream { protected Stream RawTcpStream { get { return TcpClient.GetStream(); } }
get { protected virtual Stream Stream { get { return TcpClient.GetStream(); } }
return TcpClient.GetStream(); protected virtual string WindowsProxyProtocolName { get { return "http"; } }
}
}
protected virtual Stream Stream {
get {
return TcpClient.GetStream();
}
}
protected virtual string WindowsProxyProtocolName {
get {
return "http";
}
}
private readonly bool _proxied = false; private readonly bool _proxied = false;
public Dictionary<string, string> Headers { get; set; } public Dictionary<string, string> Headers { get; set; }
public HttpClient(Uri baseUri, int port = 80) { public Http11Client(Uri baseUri, int port = 80) {
_directHost = baseUri.Host; _directHost = baseUri.Host;
_directPort = port; _directPort = port;
_baseUri = baseUri; _baseUri = baseUri;
@@ -62,17 +49,17 @@ namespace Cryville.Common.Network {
TcpClient.Close(); TcpClient.Close();
} }
public HttpResponse Request(string method, Uri uri, string body = null, Encoding encoding = null) { public Http11Response Request(string method, Uri uri, string body = null, Encoding encoding = null) {
string struri = GetUri(uri).PathAndQuery; string struri = GetUri(uri).PathAndQuery;
return Request(Stream, method, struri, body, encoding); return Request(Stream, method, struri, body, encoding);
} }
public HttpResponse Request(Stream stream, string method, string uri, string body = null, Encoding encoding = null) { public Http11Response Request(Stream stream, string method, string uri, string body = null, Encoding encoding = null) {
var headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var h in Headers) foreach (var h in Headers)
headers.Add(h.Key, h.Value); headers.Add(h.Key, h.Value);
headers["Host"] = _baseUri.Host; headers["Host"] = _baseUri.Host;
byte[] payload = new byte[0]; byte[] payload = null;
if (body != null) { if (body != null) {
if (encoding == null) if (encoding == null)
encoding = Encoding.UTF8; encoding = Encoding.UTF8;
@@ -80,22 +67,24 @@ namespace Cryville.Common.Network {
headers.Add("Content-Encoding", encoding.EncodingName); headers.Add("Content-Encoding", encoding.EncodingName);
headers.Add("Content-Length", payload.Length.ToString(CultureInfo.InvariantCulture)); headers.Add("Content-Length", payload.Length.ToString(CultureInfo.InvariantCulture));
} }
string request_line = string.Format( using (var writer = new StreamWriter(stream, Encoding.ASCII, 1024, true)) {
"{0} {1} {2}\r\n", method, uri, Version writer.Write(method);
); writer.Write(' ');
string header_fields = string.Concat(( writer.Write(uri);
from h in headers select h.Key + ":" + h.Value + "\r\n" writer.Write(' ');
).ToArray()); writer.Write(Version);
byte[] buffer0 = Encoding.ASCII.GetBytes(string.Format( writer.Write("\r\n");
"{0}{1}\r\n", request_line, header_fields foreach (var header in headers) {
)); writer.Write(header.Key);
byte[] buffer1 = new byte[buffer0.Length + payload.Length]; writer.Write(':');
Array.Copy(buffer0, buffer1, buffer0.Length); writer.Write(header.Value);
Array.Copy(payload, 0, buffer1, buffer0.Length, payload.Length); writer.Write("\r\n");
Logger.Log("main", 0, "Network", Encoding.UTF8.GetString(buffer1)); }
stream.Write(buffer1, 0, buffer1.Length); writer.Write("\r\n");
stream.Flush(); if (payload != null) writer.Write(payload);
var response = new HttpResponse(stream); writer.Flush();
}
var response = new Http11Response(stream);
Logger.Log("main", 0, "Network", "{0}", response); Logger.Log("main", 0, "Network", "{0}", response);
return response; return response;
} }

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: f191de447a708da4f9d230e6545ce0a6 guid: 5a795e416e54c69418de1a3c27a88932
timeCreated: 1635470462
licenseType: Free
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@@ -1,31 +1,30 @@
using Cryville.Common.Logging; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public class HttpResponse { public class Http11Response {
static readonly char[] spchar = new char[]{ ' ' }; static readonly char[] spchar = new char[]{ ' ' };
public string HttpVersion { get; private set; } public string HttpVersion { get; private set; }
public string StatusCode { get; private set; } public string StatusCode { get; private set; }
public string ReasonPhase { get; private set; } public string ReasonPhase { get; private set; }
public Dictionary<string, string> Headers { get; private set; } public Dictionary<string, string> Headers { get; private set; }
public HttpResponseStream MessageBody { get; private set; } public Http11ResponseStream MessageBody { get; private set; }
internal HttpResponse(Stream stream) { internal Http11Response(Stream stream) {
var reader = new BinaryReader(stream, Encoding.ASCII); var reader = new BinaryReader(stream, Encoding.ASCII);
var statu_line = ReadLine(reader).Split(spchar, 3); var statu_line = ReadLine(reader).Split(spchar, 3);
HttpVersion = statu_line[0]; HttpVersion = statu_line[0];
StatusCode = statu_line[1]; StatusCode = statu_line[1];
ReasonPhase = statu_line[2]; ReasonPhase = statu_line[2];
Logger.Log("main", 0, "Network", "Receive Response: {0} {1} {2}", HttpVersion, StatusCode, ReasonPhase); Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Headers = new Dictionary<string, string>();
while (ParseHeader(reader, Headers)) ; while (ParseHeader(reader, Headers)) ;
if (Headers.ContainsKey("content-length")) { if (Headers.ContainsKey("content-length")) {
int length = int.Parse(Headers["content-length"]); int length = int.Parse(Headers["content-length"]);
MessageBody = new HttpResponseBlockStream(reader, length); MessageBody = new Http11ResponseBlockStream(reader, length);
} }
else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") { else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") {
MessageBody = new HttpResponseChunkedStream(reader); MessageBody = new Http11ResponseChunkedStream(reader);
} }
} }
@@ -37,12 +36,11 @@ namespace Cryville.Common.Network {
// TODO Multiline header // TODO Multiline header
var header = ReadLine(reader); var header = ReadLine(reader);
if (header == "") return false; if (header == "") return false;
var s = header.Split(':'); var s = header.Split(':', 2);
string field_name = s[0].Trim().ToLower(); string field_name = s[0].Trim().ToLower();
string field_value = s[1].Trim(); string field_value = s[1].Trim();
if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value; if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value;
else headers.Add(field_name, field_value); else headers.Add(field_name, field_value);
Logger.Log("main", 0, "Network", "Receive Header {0}: {1}", field_name, field_value);
return true; return true;
} }

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 5ea931bf5488011468f3d1243a038874 guid: 71234dd1c93d47b4893750686b2333a3
timeCreated: 1622589817
licenseType: Free
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@@ -1,12 +1,11 @@
using Cryville.Common.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public abstract class HttpResponseStream : Stream { public abstract class Http11ResponseStream : Stream {
public override bool CanRead { get { return true; } } public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } } public override bool CanSeek { get { return false; } }
@@ -37,11 +36,11 @@ namespace Cryville.Common.Network {
} }
} }
internal sealed class HttpResponseBlockStream : HttpResponseStream { internal sealed class Http11ResponseBlockStream : Http11ResponseStream {
readonly BinaryReader _reader; readonly BinaryReader _reader;
readonly int _length; readonly int _length;
int _pos = 0; int _pos = 0;
internal HttpResponseBlockStream(BinaryReader reader, int length) { internal Http11ResponseBlockStream(BinaryReader reader, int length) {
_reader = reader; _reader = reader;
_length = length; _length = length;
} }
@@ -51,7 +50,6 @@ namespace Cryville.Common.Network {
if (recv_len == 0) return 0; if (recv_len == 0) return 0;
while (recv < recv_len) { while (recv < recv_len) {
recv += _reader.Read(buffer, offset + recv, count - recv); recv += _reader.Read(buffer, offset + recv, count - recv);
Logger.Log("main", 0, "Network", "Message body received: {0}/{1}/{2}", recv, recv_len, _length);
} }
_pos += recv_len; _pos += recv_len;
return recv_len; return recv_len;
@@ -63,18 +61,17 @@ namespace Cryville.Common.Network {
} }
} }
internal sealed class HttpResponseChunkedStream : HttpResponseStream { internal sealed class Http11ResponseChunkedStream : Http11ResponseStream {
readonly BinaryReader _reader; readonly BinaryReader _reader;
byte[] _chunk = null; byte[] _chunk = null;
int _pos = 0; int _pos = 0;
internal HttpResponseChunkedStream(BinaryReader reader) { internal Http11ResponseChunkedStream(BinaryReader reader) {
_reader = reader; _reader = reader;
ReadChunk(); ReadChunk();
} }
public void ReadChunk() { public void ReadChunk() {
if (_chunk != null && _chunk.Length == 0) return; if (_chunk != null && _chunk.Length == 0) return;
string[] chunkHeader = HttpResponse.ReadLine(_reader).Split(';'); string[] chunkHeader = Http11Response.ReadLine(_reader).Split(';');
// int chunkSize = Array.IndexOf(LEN, chunkHeader[0].ToLower()[0]);
int chunkSize = int.Parse(chunkHeader[0], NumberStyles.HexNumber); int chunkSize = int.Parse(chunkHeader[0], NumberStyles.HexNumber);
if (chunkSize == -1) if (chunkSize == -1)
throw new IOException("Corrupted chunk received"); throw new IOException("Corrupted chunk received");
@@ -82,17 +79,16 @@ namespace Cryville.Common.Network {
_chunk = new byte[0]; _chunk = new byte[0];
// TODO TE Header, now just discard // TODO TE Header, now just discard
var headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>();
while (HttpResponse.ParseHeader(_reader, headers)) ; while (Http11Response.ParseHeader(_reader, headers)) ;
return; return;
} }
_chunk = new byte[chunkSize]; _chunk = new byte[chunkSize];
int recv = 0; int recv = 0;
while (recv < chunkSize) { while (recv < chunkSize) {
recv += _reader.Read(_chunk, recv, chunkSize - recv); recv += _reader.Read(_chunk, recv, chunkSize - recv);
Logger.Log("main", 0, "Network", "Message chunk received: {0}/{1}", recv, chunkSize);
} }
_pos = 0; _pos = 0;
if (HttpResponse.ReadLine(_reader) != "") if (Http11Response.ReadLine(_reader) != "")
throw new IOException("Corrupted chunk received"); throw new IOException("Corrupted chunk received");
} }
public override int Read(byte[] buffer, int offset, int count) { public override int Read(byte[] buffer, int offset, int count) {

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 9b35290e0e147a342acc29a20c8fceaf guid: 49a8d5b9869e5bb42bafbe71f84fecc5
timeCreated: 1622503538
licenseType: Free
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.IO; using System.IO;
namespace Cryville.Common.Network { namespace Cryville.Common.Network.Http11 {
public class HttpsClient : HttpClient { public class Https11Client : Http11Client {
readonly TlsClient _tlsClient; readonly TlsClient _tlsClient;
protected override Stream Stream { protected override Stream Stream {
@@ -16,7 +16,7 @@ namespace Cryville.Common.Network {
} }
} }
public HttpsClient(Uri baseUri) : base(baseUri, 443) { public Https11Client(Uri baseUri) : base(baseUri, 443) {
_tlsClient = new TlsClient(RawTcpStream, baseUri.Host); _tlsClient = new TlsClient(RawTcpStream, baseUri.Host);
} }

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 07e8215a93e3eb1418685009f0c58dcd guid: c5c233e6228ce204fa1a9724c48ac8fe
timeCreated: 1622596274
licenseType: Free
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@@ -1,4 +1,3 @@
using Cryville.Common.Logging;
using Org.BouncyCastle.Security; using Org.BouncyCastle.Security;
using Org.BouncyCastle.Tls; using Org.BouncyCastle.Tls;
using Org.BouncyCastle.Tls.Crypto; using Org.BouncyCastle.Tls.Crypto;
@@ -72,20 +71,6 @@ namespace Cryville.Common.Network {
public override TlsAuthentication GetAuthentication() { public override TlsAuthentication GetAuthentication() {
return new NullTlsAuthentication(); return new NullTlsAuthentication();
} }
public override void NotifyAlertReceived(short alertLevel, short alertDescription) {
Logger.Log("main", 0, "Network/TLS", "TLS Alert {0} {1}", alertLevel, alertDescription);
}
public override void NotifyServerVersion(ProtocolVersion serverVersion) {
base.NotifyServerVersion(serverVersion);
Logger.Log("main", 0, "Network/TLS", "NotifyServerVersion {0}", serverVersion);
}
public override void NotifySelectedCipherSuite(int selectedCipherSuite) {
base.NotifySelectedCipherSuite(selectedCipherSuite);
Logger.Log("main", 0, "Network/TLS", "NotifySelectedCipherSuite {0}", selectedCipherSuite);
}
} }
private class NullTlsAuthentication : TlsAuthentication { private class NullTlsAuthentication : TlsAuthentication {

View File

@@ -1,4 +1,4 @@
using Cryville.Common.Network; using Cryville.Common.Network.Http11;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
@@ -123,13 +123,13 @@ namespace Cryville.Crtr {
try { try {
switch (p[0]) { switch (p[0]) {
case "!http": case "!http":
var httpcl = new HttpClient(new Uri(p[1])); var httpcl = new Http11Client(new Uri(p[1]));
httpcl.Connect(); httpcl.Connect();
httpcl.Request("GET", new Uri(p[1])).MessageBody.ReadToEnd(); httpcl.Request("GET", new Uri(p[1])).MessageBody.ReadToEnd();
httpcl.Close(); httpcl.Close();
break; break;
case "!https": case "!https":
var httpscl = new HttpsClient(new Uri(p[1])); var httpscl = new Https11Client(new Uri(p[1]));
httpscl.Connect(); httpscl.Connect();
httpscl.Request("GET", new Uri(p[1])).MessageBody.ReadToEnd(); httpscl.Request("GET", new Uri(p[1])).MessageBody.ReadToEnd();
httpscl.Close(); httpscl.Close();

View File

@@ -1,4 +1,4 @@
using Cryville.Common.Network; using Cryville.Common.Network.Http11;
using Cryville.Common.Unity; using Cryville.Common.Unity;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
@@ -21,7 +21,7 @@ namespace Cryville.Crtr.Network {
List<VersionInfo> _versions; List<VersionInfo> _versions;
public void CheckVersion() { public void CheckVersion() {
try { try {
var client = new HttpsClient(BaseUri); var client = new Https11Client(BaseUri);
client.Connect(); client.Connect();
var response = client.Request("GET", new Uri(BaseUri, "versions")); var response = client.Request("GET", new Uri(BaseUri, "versions"));
var data = Encoding.UTF8.GetString(response.MessageBody.ReadToEnd()); var data = Encoding.UTF8.GetString(response.MessageBody.ReadToEnd());