Archived
1
0
Fork 0
This repository has been archived on 2024-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
maki/Maki/Rest/WebRequest.cs

276 lines
9.9 KiB
C#
Raw Normal View History

2017-05-31 21:02:38 +00:00
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
namespace Maki.Rest
{
2017-08-09 21:23:43 +00:00
public class WebRequest : IDisposable
2017-05-31 21:02:38 +00:00
{
private const string USER_AGENT = @"DiscordBot (https://github.com/flashwave/maki, 1.0.0.0)";
private const string GENERIC_CONTENT_TYPE = @"application/octet-stream";
private const string JSON_CONTENT_TYPE = @"application/json";
private const string FORM_CONTENT_TYPE = @"multipart/form-data";
2017-10-13 20:05:50 +00:00
private const long BUFFER_SIZE = 8192000;
2017-05-31 21:02:38 +00:00
2017-08-09 21:23:43 +00:00
public readonly HttpMethod Method;
public readonly string Url;
public string UserAgent { get; set; } = USER_AGENT;
public string ContentType { get; set; } = GENERIC_CONTENT_TYPE;
2017-10-13 20:05:50 +00:00
public long ContentLength => HttpWebResponse.ContentLength < 1 ? BUFFER_SIZE : HttpWebResponse.ContentLength;
2017-05-31 21:02:38 +00:00
// TODO: make this not static
internal static string Authorisation { get; set; }
2017-10-13 20:05:50 +00:00
private readonly Dictionary<string, string> Headers = new Dictionary<string, string>();
private readonly Dictionary<string, string> Parameters = new Dictionary<string, string>();
private readonly Dictionary<string, byte[]> Files = new Dictionary<string, byte[]>();
2017-05-31 21:02:38 +00:00
2017-10-13 20:05:50 +00:00
private readonly Dictionary<string, string> MimeTypes = new Dictionary<string, string>()
2017-05-31 21:02:38 +00:00
{
{ "png", "image/png" },
{ "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" },
{ "gif", "image/gif" },
};
2017-10-13 20:05:50 +00:00
private byte[] RawRequestBody = new byte[0];
private HttpWebRequest HttpWebRequest;
private Stream RequestStream;
private HttpWebResponse HttpWebResponse;
private Stream ResponseStream;
2017-05-31 21:02:38 +00:00
2017-10-13 20:05:50 +00:00
private byte[] RawResponseValue;
2017-08-09 21:23:43 +00:00
public byte[] RawResponse
2017-05-31 21:02:38 +00:00
{
get
{
2017-10-13 20:05:50 +00:00
if (RawResponseValue == null)
2017-05-31 21:02:38 +00:00
{
2017-10-13 20:05:50 +00:00
using (MemoryStream ms = new MemoryStream())
{
byte[] bytes = new byte[4096];
int read = 0;
while ((read = ResponseStream.Read(bytes, 0, bytes.Length)) > 0)
ms.Write(bytes, 0, read);
ms.Seek(0, SeekOrigin.Begin);
RawResponseValue = new byte[ms.Length];
ms.Read(RawResponseValue, 0, RawResponseValue.Length);
}
2017-05-31 21:02:38 +00:00
}
2017-10-13 20:05:50 +00:00
return RawResponseValue;
2017-05-31 21:02:38 +00:00
}
}
2017-10-13 20:05:50 +00:00
private string ResponseString = string.Empty;
2017-05-31 21:02:38 +00:00
2017-08-09 21:23:43 +00:00
public string Response
2017-05-31 21:02:38 +00:00
{
get
{
2017-10-13 20:05:50 +00:00
if (string.IsNullOrEmpty(ResponseString))
ResponseString = Encoding.UTF8.GetString(RawResponse);
2017-05-31 21:02:38 +00:00
2017-10-13 20:05:50 +00:00
return ResponseString;
2017-05-31 21:02:38 +00:00
}
}
2017-08-09 21:23:43 +00:00
public T ResponseJson<T>() =>
2017-05-31 21:02:38 +00:00
JsonConvert.DeserializeObject<T>(Response);
2017-08-09 21:23:43 +00:00
public short Status =>
2017-10-13 20:05:50 +00:00
(short)HttpWebResponse?.StatusCode;
2017-05-31 21:02:38 +00:00
static WebRequest()
{
ServicePointManager.Expect100Continue = false;
}
2017-08-09 21:23:43 +00:00
public WebRequest(HttpMethod method, string url)
2017-05-31 21:02:38 +00:00
{
Method = method;
Url = url;
}
2017-08-09 21:23:43 +00:00
public void AddRaw(byte[] bytes) =>
2017-10-13 20:05:50 +00:00
RawRequestBody = bytes;
2017-05-31 21:02:38 +00:00
2017-08-09 21:23:43 +00:00
public void AddRaw(string str) =>
2017-05-31 21:02:38 +00:00
AddRaw(Encoding.UTF8.GetBytes(str));
2017-08-09 21:23:43 +00:00
public void AddJson(object obj)
2017-05-31 21:02:38 +00:00
{
ContentType = JSON_CONTENT_TYPE;
AddRaw(JsonConvert.SerializeObject(obj));
}
2017-08-09 21:23:43 +00:00
public void AddParam(string name, string contents) =>
2017-10-13 20:05:50 +00:00
Parameters.Add(name, contents);
2017-05-31 21:02:38 +00:00
2017-08-09 21:23:43 +00:00
public void AddFile(string name, byte[] bytes) =>
2017-10-13 20:05:50 +00:00
Files.Add(name, bytes);
2017-05-31 21:02:38 +00:00
2017-08-09 21:23:43 +00:00
public void Perform()
2017-05-31 21:02:38 +00:00
{
StringBuilder urlBuilder = new StringBuilder();
2017-08-09 21:23:43 +00:00
if (!Url.StartsWith("http://") && !Url.StartsWith("https://"))
2017-05-31 21:02:38 +00:00
{
urlBuilder.Append(RestEndpoints.BASE_URL);
urlBuilder.Append(RestEndpoints.BASE_PATH);
}
urlBuilder.Append(Url);
if (Method == HttpMethod.GET
|| Method == HttpMethod.DELETE)
2017-10-13 20:05:50 +00:00
if (Parameters.Count > 1)
2017-05-31 21:02:38 +00:00
{
if (!Url.Contains('?'))
urlBuilder.Append(@"?");
2017-10-13 20:05:50 +00:00
foreach (KeyValuePair<string, string> param in Parameters)
2017-05-31 21:02:38 +00:00
urlBuilder.Append($@"{param.Key}={param.Value}&");
}
string url = urlBuilder.ToString().TrimEnd('&');
2017-10-13 20:05:50 +00:00
HttpWebRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
HttpWebRequest.Method = Method.ToString();
HttpWebRequest.UserAgent = UserAgent;
HttpWebRequest.KeepAlive = true;
2017-05-31 21:02:38 +00:00
//wRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
2017-10-13 20:05:50 +00:00
HttpWebRequest.ReadWriteTimeout = Timeout.Infinite;
HttpWebRequest.Timeout = Timeout.Infinite;
2017-05-31 21:02:38 +00:00
2017-08-09 21:23:43 +00:00
if (!string.IsNullOrEmpty(Authorisation) && url.StartsWith(RestEndpoints.BASE_URL + RestEndpoints.BASE_PATH))
2017-10-13 20:05:50 +00:00
HttpWebRequest.Headers[HttpRequestHeader.Authorization] = Authorisation;
2017-05-31 21:02:38 +00:00
2017-10-13 20:05:50 +00:00
foreach (KeyValuePair<string, string> header in Headers)
HttpWebRequest.Headers[header.Key] = header.Value;
2017-05-31 21:02:38 +00:00
if (Method == HttpMethod.POST
|| Method == HttpMethod.PUT
|| Method == HttpMethod.PATCH)
{
2017-10-13 20:05:50 +00:00
RequestStream = HttpWebRequest.GetRequestStream();
2017-05-31 21:02:38 +00:00
2017-10-13 20:05:50 +00:00
if (Parameters.Count + Files.Count < 1)
RequestStream.Write(RawRequestBody, 0, RawRequestBody.Length);
2017-05-31 21:02:38 +00:00
else
{
string boundary = $@"-----------------------------{DateTime.Now.Ticks}";
ContentType = $@"{FORM_CONTENT_TYPE}; boundary={boundary}";
2017-10-13 20:05:50 +00:00
if (Parameters.Count >= 1)
2017-05-31 21:02:38 +00:00
{
StringBuilder postBodyBuilder = new StringBuilder();
byte[] postBody = new byte[0];
2017-10-13 20:05:50 +00:00
foreach (KeyValuePair<string, string> param in Parameters)
2017-05-31 21:02:38 +00:00
{
postBodyBuilder.AppendLine($@"--{boundary}");
postBodyBuilder.AppendLine($@"Content-Disposition: form-data; name=""{param.Key}""");
postBodyBuilder.AppendLine();
postBodyBuilder.AppendLine(param.Value);
}
postBody = Encoding.UTF8.GetBytes(postBodyBuilder.ToString());
2017-10-13 20:05:50 +00:00
RequestStream.Write(postBody, 0, postBody.Length);
2017-05-31 21:02:38 +00:00
}
2017-10-13 20:05:50 +00:00
if (Files.Count >= 1)
2017-05-31 21:02:38 +00:00
{
byte[] boundaryBytes = Encoding.UTF8.GetBytes($@"--{boundary}");
byte[] newLineBytes = Encoding.UTF8.GetBytes("\r\n");
2017-10-13 20:05:50 +00:00
foreach (KeyValuePair<string, byte[]> file in Files)
2017-05-31 21:02:38 +00:00
{
string cType = GENERIC_CONTENT_TYPE;
string fileExt = Path.GetExtension(file.Key).ToLower().TrimStart('.');
2017-10-13 20:05:50 +00:00
if (MimeTypes.ContainsKey(fileExt))
cType = MimeTypes[fileExt];
2017-05-31 21:02:38 +00:00
byte[] cDisposBytes = Encoding.UTF8.GetBytes($@"Content-Disposition: form-data; name=""{file.Key}""; filename=""{file.Key}""");
byte[] cTypeBytes = Encoding.UTF8.GetBytes($@"Content-Type: {cType}");
// Boundary + newline
2017-10-13 20:05:50 +00:00
RequestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
2017-05-31 21:02:38 +00:00
// Disposition header + newline
2017-10-13 20:05:50 +00:00
RequestStream.Write(cDisposBytes, 0, cDisposBytes.Length);
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
2017-05-31 21:02:38 +00:00
// Type header + newline
2017-10-13 20:05:50 +00:00
RequestStream.Write(cTypeBytes, 0, cTypeBytes.Length);
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
2017-05-31 21:02:38 +00:00
// newline + contents + newline
2017-10-13 20:05:50 +00:00
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
RequestStream.Write(file.Value, 0, file.Value.Length);
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
2017-05-31 21:02:38 +00:00
}
}
byte[] closingBound = Encoding.UTF8.GetBytes($@"--{boundary}--");
2017-10-13 20:05:50 +00:00
RequestStream.Write(closingBound, 0, closingBound.Length);
2017-05-31 21:02:38 +00:00
}
}
2017-10-13 20:05:50 +00:00
HttpWebRequest.ContentType = ContentType;
2017-05-31 21:02:38 +00:00
try
{
2017-10-13 20:05:50 +00:00
HttpWebResponse = HttpWebRequest.GetResponse() as HttpWebResponse;
2017-05-31 21:02:38 +00:00
} catch (WebException ex)
{
2017-10-13 20:05:50 +00:00
HttpWebResponse = ex.Response as HttpWebResponse;
2017-05-31 21:02:38 +00:00
}
2017-10-13 20:05:50 +00:00
ResponseStream = HttpWebResponse.GetResponseStream();
2017-05-31 21:02:38 +00:00
}
#region IDisposable
2017-10-13 20:05:50 +00:00
private bool IsDisposed = false;
/// <summary>
/// Disconnects and releases all unmanaged objects
/// </summary>
2017-05-31 21:02:38 +00:00
private void Dispose(bool disposing)
{
2017-10-13 20:05:50 +00:00
if (IsDisposed)
return;
IsDisposed = true;
RequestStream?.Dispose();
HttpWebRequest?.Abort();
ResponseStream?.Dispose();
HttpWebResponse?.Close();
if (disposing)
GC.SuppressFinalize(true);
2017-05-31 21:02:38 +00:00
}
~WebRequest()
2017-10-13 20:05:50 +00:00
=> Dispose(false);
2017-05-31 21:02:38 +00:00
public void Dispose()
2017-10-13 20:05:50 +00:00
=> Dispose(true);
2017-05-31 21:02:38 +00:00
#endregion
}
}