Cleanup network module.
This commit is contained in:
8
Assets/Cryville/Common/Network/Http11.meta
Normal file
8
Assets/Cryville/Common/Network/Http11.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1a624371d4108614b9cdc4acca1499e2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@@ -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;
|
||||||
}
|
}
|
@@ -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
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
@@ -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
|
@@ -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) {
|
@@ -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
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
@@ -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
|
@@ -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 {
|
||||||
|
@@ -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();
|
||||||
|
@@ -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());
|
||||||
|
Reference in New Issue
Block a user