using System; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Net; using System.Security.Cryptography.X509Certificates; using System.Text; namespace Apewer.Web { /// <summary>响应。</summary> public sealed class MiniResponse { bool _disposed = false; /// <summary>上下文。</summary> public MiniContext Context { get; private set; } /// <summary>保持连接。</summary> internal bool KeepAlive { get; set; } /// <summary>HTTP 状态码。</summary> /// <remarks>默认值:200</remarks> public int Status { get; set; } /// <summary>头。</summary> public StringPairs Headers { get; set; } /// <summary>内容类型。</summary> public string ContentType { get; set; } /// <summary>内容长度。</summary> public long ContentLength { get; set; } /// <summary>重定向地址。</summary> internal string Location { get; set; } /// <summary></summary> public Stream Body { get => Context.Connection.GetResponseStream(); } internal MiniResponse(MiniContext context) { Context = context; Headers = new StringPairs(); ContentLength = -1; Status = 200; } /// <summary></summary> public Json ToJson() { var json = new Json(); json.SetProperty("Status", Status); json.SetProperty("Location", Location); json.SetProperty("ContentType", ContentType); json.SetProperty("ContentLength", ContentLength); json.SetProperty("Headers", Json.From(Headers)); return json; } /// <summary>重定向到指定的 URL。</summary> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> public void Redirect(string url, int status) { if (url == null) throw new ArgumentNullException(nameof(url)); url = TextUtility.Trim(url); if (url.IsEmpty()) throw new ArgumentException("参数 url 为空。"); Status = 302; Location = url; } void Close(bool force) { if (_disposed) return; _disposed = true; Context.Connection.Close(force); } /// <summary>关闭连接。</summary> public void Close() => Close(false); #region cookies /// <summary>生成 Cookie 的头字段。</summary> public static string Format(Cookie cookie) { if (cookie == null) return null; if (string.IsNullOrEmpty(cookie.Name)) return null; var segs = new List<string>(4); if (cookie.Version > 0) segs.Add("Version=" + cookie.Version.ToString()); if (!string.IsNullOrEmpty(cookie.Name)) segs.Add(cookie.Name + "=" + (cookie.Value ?? "")); if (!string.IsNullOrEmpty(cookie.Path)) segs.Add("Path=" + cookie.Path); if (!string.IsNullOrEmpty(cookie.Domain)) segs.Add("Domain=" + cookie.Domain); if (!string.IsNullOrEmpty(cookie.Port)) segs.Add("Port=" + cookie.Port); if (segs.Count < 1) return null; var text = string.Join(";", segs.ToArray()); return text; } static string QuotedString(Cookie cookie, string value) { if (cookie.Version == 0 || IsToken(value)) return value; else return "\"" + value.Replace("\"", "\\\"") + "\""; } static bool IsToken(string value) { // from RFC 2965, 2068 const string tspecials = "()<>@,;:\\\"/[]?={} \t"; int len = value.Length; for (int i = 0; i < len; i++) { char c = value[i]; if (c < 0x20 || c >= 0x7f || tspecials.IndexOf(c) != -1) return false; } return true; } #endregion } }