using Apewer;
using Apewer.Internals;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace Apewer.Network
{
///
public class HttpClient
{
private string _key = TextUtility.Guid();
internal bool _locked = false;
private TextSet _properties = new TextSet(true);
private HttpRequest _request = new HttpRequest();
private HttpResponse _response = new HttpResponse();
private Exception _lastexception = null;
private HttpWebRequest _lastrequest = null;
private HttpWebResponse _lastresponse = null;
///
public HttpRequest Request { get { return _request; } }
///
public HttpResponse Response { get { return _response; } }
///
public string Key { get { return _properties["Key"]; } }
///
///
///
///
///
///
///
///
private static HttpWebRequest CreateRequest(HttpRequest request)
{
var error = (Exception)null;
if (request == null) throw new ArgumentNullException("Request", "参数无效。");
var properties = request._properties;
var certificates = request._certificates;
var headers = request._headers;
var cookies = request._cookies;
var timeout = request._timeout;
var url = properties["Url"];
// 全局证书验证。
var https = url.ToLower().StartsWith("https");
if (https) SslUtility.ApproveValidation();
// 创建对象。
var http = (HttpWebRequest)WebRequest.Create(properties["Url"]);
// 证书。
foreach (var certificate in certificates)
{
if (certificate == null) continue;
if (certificate.LongLength < 1L) continue;
try
{
var x509 = new X509Certificate(certificate);
http.ClientCertificates.Add(x509);
}
finally { }
}
// 请求超时。
if (timeout > 0) http.Timeout = timeout;
// 方法。
http.Method = request._method.ToString();
// 允许重定向。
http.AllowAutoRedirect = request._redirect;
// 头。
foreach (var header in headers.Origin)
{
var key = header.Key.ToTrim(); ;
var value = header.Value.ToTrim();
if (TextUtility.IsBlank(key)) continue;
if (TextUtility.IsBlank(value)) continue;
try
{
switch (key.Lower())
{
case "accept":
http.Accept = value;
break;
case "connection":
http.Connection = value;
break;
case "content-length":
http.ContentLength = NumberUtility.Int64(value);
break;
case "content-type":
http.ContentType = value;
break;
case "date":
// request.Date = ClockUtility.Parse(value);
break;
case "expect":
http.Expect = value;
break;
#if !NET20
case "host":
http.Host = value;
break;
#endif
case "if-modified-since":
// request.IfModifiedSince = ClockUtility.Parse(value);
break;
case "referer":
case "referrer":
http.Referer = value;
break;
case "transfer-encoding":
http.TransferEncoding = value;
break;
case "user-agent":
http.UserAgent = value;
break;
default:
http.Headers.Add(header.Key, header.Value);
break;
}
}
catch { }
}
if (!TextUtility.IsBlank(properties["TransferEncoding"])) http.TransferEncoding = properties["TransferEncoding"];
if (!TextUtility.IsBlank(properties["ContentType"])) http.ContentType = properties["ContentType"];
if (!TextUtility.IsBlank(properties["UserAgent"])) http.UserAgent = properties["UserAgent"];
if (!TextUtility.IsBlank(properties["Referer"])) http.Referer = properties["Referer"];
// Cookies。
if (cookies != null) http.CookieContainer = cookies;
// 对 POST 请求加入内容数据。
if (request._method == HttpMethod.POST)
{
if (request._stream != null)
{
http.ContentLength = request._contentlength;
var rs = http.GetRequestStream();
try
{
BytesUtility.Read(request._stream, rs, request._progress);
}
catch { }
}
else if (request._data != null && request._data.LongLength > 0L)
{
http.ContentLength = request._data.Length;
var rs = http.GetRequestStream();
try
{
rs.Write(request._data, 0, request._data.Length);
}
catch (Exception exception) { error = exception; }
}
}
if (error == null) return http;
throw error;
}
///
///
///
///
///
///
private static HttpWebResponse CreateResponse(HttpWebRequest request, HttpResponse response)
{
var error = (Exception)null;
// 发起请求。
var http = (HttpWebResponse)request.GetResponse();
// 读取头。
foreach (var key in http.Headers.AllKeys) response._headers[key] = http.Headers[key];
response._cached = http.IsFromCache;
response._cookies = http.Cookies;
response._contentlength = http.ContentLength;
response._statuscode = http.StatusCode;
response._properties["CharacterSet"] = http.CharacterSet;
response._properties["ContentEncoding"] = http.ContentEncoding;
response._properties["ContentType"] = http.ContentType;
response._properties["LastModified"] = ClockUtility.Lucid(http.LastModified);
response._properties["Method"] = http.Method;
response._properties["ProtocolVersion"] = http.ProtocolVersion.ToString();
response._properties["Url"] = http.ResponseUri.OriginalString;
response._properties["Server"] = http.Server;
response._properties["StatusDescription"] = http.StatusDescription;
// 读取内容。
var rs = http.GetResponseStream();
if (response._stream == null)
{
var memory = new MemoryStream();
try
{
BytesUtility.Read(rs, memory, response.ProgressCallback);
}
catch (Exception exception) { error = exception; }
response._data = memory.ToArray();
memory.Dispose();
}
else
{
BytesUtility.Read(rs, response._stream, response.ProgressCallback);
}
http.Close();
if (error == null) return http;
throw error;
}
///
public Exception LatestException { get { return _lastexception; } }
///
public WebException WebException { get { return _lastexception as WebException; } }
///
public Exception Send()
{
var error = null as Exception;
if (_request._locked || _response._locked)
{
error = new InvalidOperationException("存在已启动的请求,无法继续此次请求。");
}
else
{
_request._locked = true;
_response._locked = true;
try
{
_lastrequest = CreateRequest(_request);
_lastresponse = CreateResponse(_lastrequest, _response);
}
catch (Exception exception)
{
error = exception;
}
_request._locked = false;
_response._locked = false;
}
_lastexception = error;
return error;
}
/// GET
public static HttpClient SimpleGet(string url, int timeout = 30000)
{
var http = new HttpClient();
http.Request.Url = url;
http.Request.Timeout = timeout;
http.Request.Method = HttpMethod.GET;
http.Send();
return http;
}
/// POST
public static HttpClient SimplePost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
{
var http = new HttpClient();
http.Request.Url = url;
http.Request.Timeout = timeout;
http.Request.Method = HttpMethod.POST;
if (type.NotBlank()) http.Request.ContentType = type;
http.Request.Data = data ?? BytesUtility.Empty;
http.Send();
return http;
}
/// POST text/plain
public static HttpClient SimpleText(string url, string text, int timeout = 30000, string type = "text/plain")
{
return SimplePost(url, TextUtility.Bytes(text), timeout, type);
}
/// POST application/x-www-form-urlencoded
public static HttpClient SimpleForm(string url, IDictionary form, int timeout = 30000)
{
if (form == null) return SimplePost(url, BytesUtility.Empty, timeout, "application/x-www-form-urlencoded");
var cache = new List();
foreach (var i in form)
{
var key = TextUtility.EncodeUrl(i.Key);
var value = TextUtility.EncodeUrl(i.Value);
cache.Add(key + "=" + value);
}
var text = string.Join("&", cache.ToArray());
var data = TextUtility.Bytes(text);
return SimplePost(url, data, timeout, "application/x-www-form-urlencoded");
}
/// POST application/x-www-form-urlencoded
public static HttpClient SimpleForm(string url, TextSet form, int timeout = 30000)
{
return SimpleForm(url, form.Origin, timeout);
}
/// 合并表单参数,不包含 Query 的 ? 符号。
public static string MergeForm(IDictionary form)
{
if (form == null) return "";
if (form.Count < 1) return "";
var cache = new List();
foreach (var i in form)
{
var key = TextUtility.EncodeUrl(i.Key);
var value = TextUtility.EncodeUrl(i.Value);
cache.Add(key + "=" + value);
}
var text = string.Join("&", cache.ToArray());
return text;
}
/// 合并表单参数,不包含 Query 的 ? 符号。
public static string MergeForm(TextSet form)
{
if (form == null) return "";
return MergeForm(form.Origin());
}
}
}