|
|
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 {
/// <summary></summary>
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;
/// <summary></summary>
public HttpRequest Request { get { return _request; } }
/// <summary></summary>
public HttpResponse Response { get { return _response; } }
/// <summary></summary>
public string Key { get { return _properties["Key"]; } }
/// <exception cref="System.ArgumentException"></exception>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.InvalidOperationException"></exception>
/// <exception cref="System.NotSupportedException"></exception>
/// <exception cref="System.ObjectDisposedException"></exception>
/// <exception cref="System.Security.SecurityException"></exception>
/// <exception cref="System.Net.ProtocolViolationException"></exception>
/// <exception cref="System.Net.WebException"></exception>
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; }
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.InvalidOperationException"></exception>
/// <exception cref="System.NotSupportedException"></exception>
/// <exception cref="System.ObjectDisposedException"></exception>
/// <exception cref="System.Net.ProtocolViolationException"></exception>
/// <exception cref="System.Net.WebException"></exception>
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; }
/// <summary></summary>
public Exception LatestException { get { return _lastexception; } }
/// <summary></summary>
public WebException WebException { get { return _lastexception as WebException; } }
/// <summary></summary>
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; }
/// <summary>GET</summary>
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; }
/// <summary>POST</summary>
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; }
/// <summary>POST text/plain</summary>
public static HttpClient SimpleText(string url, string text, int timeout = 30000, string type = "text/plain") { return SimplePost(url, TextUtility.Bytes(text), timeout, type); }
/// <summary>POST application/x-www-form-urlencoded</summary>
public static HttpClient SimpleForm(string url, IDictionary<string, string> form, int timeout = 30000) { if (form == null) return SimplePost(url, BytesUtility.Empty, timeout, "application/x-www-form-urlencoded");
var cache = new List<string>(); 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"); }
/// <summary>POST application/x-www-form-urlencoded</summary>
public static HttpClient SimpleForm(string url, TextSet form, int timeout = 30000) { return SimpleForm(url, form.Origin, timeout); }
/// <summary>合并表单参数,不包含 Query 的 ? 符号。</summary>
public static string MergeForm(IDictionary<string, string> form) { if (form == null) return ""; if (form.Count < 1) return ""; var cache = new List<string>(); 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; }
/// <summary>合并表单参数,不包含 Query 的 ? 符号。</summary>
public static string MergeForm(TextSet form) { if (form == null) return ""; return MergeForm(form.Origin()); }
}
}
|