You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.7 KiB
231 lines
7.7 KiB
#if NETCORE
|
|
|
|
using Apewer.Network;
|
|
using Microsoft.AspNetCore.Http;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace Apewer.Web
|
|
{
|
|
|
|
/// <summary>用于网站的服务程序。</summary>
|
|
public class AspNetCoreProvider : ApiProvider<HttpContext>
|
|
{
|
|
|
|
private HttpContext context;
|
|
private HttpRequest request;
|
|
private HttpResponse response;
|
|
|
|
/// <summary>HttpContext</summary>
|
|
public override HttpContext Context { get => context; }
|
|
|
|
/// <summary>创建服务程序实例。</summary>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public AspNetCoreProvider(HttpContext context)
|
|
{
|
|
if (context == null) throw new ArgumentNullException(nameof(context));
|
|
this.context = context;
|
|
request = context.Request;
|
|
response = context.Response;
|
|
}
|
|
|
|
#region Request
|
|
|
|
/// <summary>获取 HTTP 方法。</summary>
|
|
public override Network.HttpMethod GetMethod() => ApiUtility.Method(request.Method);
|
|
|
|
/// <summary>获取客户端的 IP 地址。</summary>
|
|
public override string GetClientIP() => request.HttpContext.Connection.RemoteIpAddress.ToString();
|
|
|
|
/// <summary>获取请求的 URL。</summary>
|
|
public override Uri GetUrl()
|
|
{
|
|
var https = request.IsHttps;
|
|
var port = Context.Connection.LocalPort;
|
|
var query = request.QueryString == null ? null : request.QueryString.Value;
|
|
|
|
var sb = new StringBuilder();
|
|
sb.Append(https ? "https://" : "http://");
|
|
sb.Append(request.Host.Host ?? "");
|
|
if ((https && port != 443) || (!https && port != 80))
|
|
{
|
|
sb.Append(":");
|
|
sb.Append(port);
|
|
}
|
|
sb.Append(request.Path);
|
|
if (!string.IsNullOrEmpty(query))
|
|
{
|
|
if (!query.StartsWith("?")) sb.Append("?");
|
|
sb.Append(query);
|
|
}
|
|
|
|
var url = sb.ToString();
|
|
var uri = new Uri(url);
|
|
return uri;
|
|
}
|
|
|
|
/// <summary>获取请求的 Referrer。</summary>
|
|
public override string GetReferrer() => null;
|
|
|
|
/// <summary>获取请求的头。</summary>
|
|
public override HttpHeaders GetHeaders()
|
|
{
|
|
var headers = request.Headers;
|
|
var result = new HttpHeaders();
|
|
if (headers == null) return result;
|
|
foreach (var key in headers.Keys)
|
|
{
|
|
if (string.IsNullOrEmpty(key)) continue;
|
|
try
|
|
{
|
|
var value = headers[key];
|
|
if (string.IsNullOrEmpty(value)) continue;
|
|
result.Add(key, value);
|
|
}
|
|
catch { }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>获取请求的内容类型。</summary>
|
|
public override string GetContentType() => request.ContentType;
|
|
|
|
/// <summary>获取请求的内容长度。</summary>
|
|
public override long GetContentLength() => request.ContentLength ?? -1L;
|
|
|
|
/// <summary>获取请求的内容。</summary>
|
|
public override Stream RequestBody() => request.Body;
|
|
|
|
#endregion
|
|
|
|
#region Response
|
|
|
|
/// <summary>设置 HTTP 状态。</summary>
|
|
public override void SetStatus(int status, int subStatus = 0) => response.StatusCode = status;
|
|
|
|
/// <summary>设置响应的头。</summary>
|
|
public override string SetHeader(string name, string value)
|
|
{
|
|
try
|
|
{
|
|
response.Headers.Add(name, value);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Internals.Error(nameof(AspNetCoreProvider), nameof(SetHeader), ex.Message(), name, value);
|
|
return ex.Message;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>设置响应的缓存秒数,设置为 0 即不允许缓存。</summary>
|
|
public override void SetCache(int seconds)
|
|
{
|
|
if (seconds > 0)
|
|
{
|
|
SetHeader("Cache-Control", $"public, max-age={seconds}, s-maxage={seconds}");
|
|
}
|
|
else
|
|
{
|
|
SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
SetHeader("Pragma", "no-cache");
|
|
}
|
|
}
|
|
|
|
/// <summary>设置响应的缓存秒数。</summary>
|
|
public override void SetContentType(string value) => response.ContentType = value;
|
|
|
|
/// <summary>设置响应的内容长度。</summary>
|
|
public override void SetContentLength(long value) => response.ContentLength = value;
|
|
|
|
/// <summary>设置响应重定向。</summary>
|
|
public override void SetRedirect(string location) => SetRedirect(location, false);
|
|
|
|
/// <summary>获取 Response 流。</summary>
|
|
public override Stream ResponseBody() => response.Body;
|
|
|
|
#endregion
|
|
|
|
#region This
|
|
|
|
/// <summary>将客户端重新定向到新 URL。</summary>
|
|
/// <remarks>默认响应 302 状态。可指定 permanent = true 以响应 301 状态。</remarks>
|
|
public void SetRedirect(string location, bool permanent = false)
|
|
{
|
|
try { response.Redirect(location, permanent); } catch { }
|
|
}
|
|
|
|
private static void Async(Stream source, Stream destination, Func<long, bool> progress = null, int buffer = 4096, Action after = null)
|
|
{
|
|
if (source == null || !source.CanRead || destination == null || !destination.CanWrite)
|
|
{
|
|
after?.Invoke();
|
|
return;
|
|
}
|
|
|
|
Async(source, destination, progress, buffer, after, 0L);
|
|
}
|
|
|
|
private static void Async(Stream source, Stream destination, Func<long, bool> progress, int buffer, Action after, long total)
|
|
{
|
|
// 缓冲区。
|
|
var limit = buffer < 1 ? 1 : buffer;
|
|
var temp = new byte[limit];
|
|
|
|
// 读取一次。
|
|
try
|
|
{
|
|
source.BeginRead(temp, 0, limit, (ar1) =>
|
|
{
|
|
var count = source.EndRead(ar1);
|
|
if (count > 0)
|
|
{
|
|
destination.BeginWrite(temp, 0, count, (ar2) =>
|
|
{
|
|
destination.EndWrite(ar2);
|
|
total += count;
|
|
if (progress != null)
|
|
{
|
|
var @continue = progress.Invoke(total);
|
|
if (!@continue)
|
|
{
|
|
after?.Invoke();
|
|
return;
|
|
}
|
|
}
|
|
Async(source, destination, progress, buffer, after, total);
|
|
}, null);
|
|
}
|
|
else after?.Invoke();
|
|
}, null);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>解析 URL 的查询字符串,获取所有已解码的参数。</summary>
|
|
public static StringPairs ParseQuery(HttpRequest request)
|
|
{
|
|
if (request == null) return new StringPairs();
|
|
|
|
var sp = new StringPairs();
|
|
if (request.Query == null) return sp;
|
|
|
|
var keys = request.Query.Keys;
|
|
sp.Capacity = keys.Count;
|
|
foreach (var key in keys)
|
|
{
|
|
sp.Add(key, request.Query[key]);
|
|
}
|
|
sp.Capacity = sp.Count;
|
|
return sp;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|