using System; using System.Collections.Generic; using System.IO; using System.Text; namespace Cryville.Common.Network.Http11 { public class Http11Response : IDisposable { static readonly char[] spchar = new char[]{ ' ' }; public string HttpVersion { get; private set; } public string StatusCode { get; private set; } public string ReasonPhase { get; private set; } public Dictionary Headers { get; private set; } public Http11ResponseStream MessageBody { get; private set; } internal Http11Response(Stream stream) { var reader = new BinaryReader(stream, Encoding.ASCII); var statu_line = ReadLine(reader).Split(spchar, 3); HttpVersion = statu_line[0]; StatusCode = statu_line[1]; ReasonPhase = statu_line[2]; Headers = new Dictionary(StringComparer.OrdinalIgnoreCase); while (ParseHeader(reader, Headers)) ; if (Headers.ContainsKey("content-length")) { int length = int.Parse(Headers["content-length"]); MessageBody = new Http11ResponseBlockStream(reader, length); } else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") { MessageBody = new Http11ResponseChunkedStream(reader); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public virtual void Dispose(bool disposing) { if (disposing) { MessageBody.Dispose(); } } public override string ToString() { return string.Format("<{0} {1} {2}>", HttpVersion, StatusCode, ReasonPhase); } internal static bool ParseHeader(BinaryReader reader, Dictionary headers) { // TODO Multiline header var header = ReadLine(reader); if (header == "") return false; var s = header.Split(':', 2); string field_name = s[0].Trim().ToLower(); string field_value = s[1].Trim(); if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value; else headers.Add(field_name, field_value); return true; } internal static string ReadLine(BinaryReader reader) { StringBuilder result = new StringBuilder(); char c; while (true) { c = reader.ReadChar(); if (c == '\r') break; result.Append(c); } // TODO Unseekable reader.ReadByte(); return result.ToString(); } } }