using System.Collections.Generic; using System.IO; using System.Text; namespace Cryville.Common.Network { public class HttpResponse { 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 HttpResponseStream MessageBody { get; private set; } internal HttpResponse(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]; Logger.Log("main", 0, "Network", "Receive Response: {0} {1} {2}", HttpVersion, StatusCode, ReasonPhase); Headers = new Dictionary(); while (ParseHeader(reader, Headers)) ; if (Headers.ContainsKey("content-length")) { int length = int.Parse(Headers["content-length"]); MessageBody = new HttpResponseBlockStream(reader, length); } else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") { MessageBody = new HttpResponseChunkedStream(reader); } } 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(':'); 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); Logger.Log("main", 0, "Network", "Receive Header {0}: {1}", 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(); } } }