namespace Nwc.XmlRpc { using System; using System.IO; using System.Net.Sockets; using System.Collections; ///<summary>Very basic HTTP request handler.</summary> ///<remarks>This class is designed to accept a TcpClient and treat it as an HTTP request. /// It will do some basic header parsing and manage the input and output streams associated /// with the request.</remarks> public class SimpleHttpRequest { private String _httpMethod = null; private String _protocol; private String _filePathFile = null; private String _filePathDir = null; private String __filePath; private TcpClient _client; private StreamReader _input; private StreamWriter _output; private Hashtable _headers; /// <summary>A constructor which accepts the TcpClient.</summary> /// <remarks>It creates the associated input and output streams, determines the request type, /// and parses the remaining HTTP header.</remarks> /// <param name="client">The <c>TcpClient</c> associated with the HTTP connection.</param> public SimpleHttpRequest(TcpClient client) { _client = client; _output = new StreamWriter(client.GetStream()); _input = new StreamReader(client.GetStream()); GetRequestMethod(); GetRequestHeaders(); } /// <summary>The output <c>StreamWriter</c> associated with the request.</summary> public StreamWriter Output { get { return _output; } } /// <summary>The input <c>StreamReader</c> associated with the request.</summary> public StreamReader Input { get { return _input; } } /// <summary>The <c>TcpClient</c> with the request.</summary> public TcpClient Client { get { return _client; } } private String _filePath { get { return __filePath; } set { __filePath = value; _filePathDir = null; _filePathFile = null; } } /// <summary>The type of HTTP request (i.e. PUT, GET, etc.).</summary> public String HttpMethod { get { return _httpMethod; } } /// <summary>The level of the HTTP protocol.</summary> public String Protocol { get { return _protocol; } } /// <summary>The "path" which is part of any HTTP request.</summary> public String FilePath { get { return _filePath; } } /// <summary>The file portion of the "path" which is part of any HTTP request.</summary> public String FilePathFile { get { if (_filePathFile != null) return _filePathFile; int i = FilePath.LastIndexOf("/"); if (i == -1) return ""; i++; _filePathFile = FilePath.Substring(i, FilePath.Length - i); return _filePathFile; } } /// <summary>The directory portion of the "path" which is part of any HTTP request.</summary> public String FilePathDir { get { if (_filePathDir != null) return _filePathDir; int i = FilePath.LastIndexOf("/"); if (i == -1) return ""; i++; _filePathDir = FilePath.Substring(0, i); return _filePathDir; } } private void GetRequestMethod() { string req = _input.ReadLine(); if (req == null) throw new ApplicationException("Void request."); if (0 == String.Compare("GET ", req.Substring(0, 4), true)) _httpMethod = "GET"; else if (0 == String.Compare("POST ", req.Substring(0, 5), true)) _httpMethod = "POST"; else throw new InvalidOperationException("Unrecognized method in query: " + req); req = req.TrimEnd(); int idx = req.IndexOf(' ') + 1; if (idx >= req.Length) throw new ApplicationException("What do you want?"); string page_protocol = req.Substring(idx); int idx2 = page_protocol.IndexOf(' '); if (idx2 == -1) idx2 = page_protocol.Length; _filePath = page_protocol.Substring(0, idx2).Trim(); _protocol = page_protocol.Substring(idx2).Trim(); } private void GetRequestHeaders() { String line; int idx; _headers = new Hashtable(); while ((line = _input.ReadLine()) != "") { if (line == null) { break; } idx = line.IndexOf(':'); if (idx == -1 || idx == line.Length - 1) { Logger.WriteEntry("Malformed header line: " + line, LogLevel.Information); continue; } String key = line.Substring(0, idx); String value = line.Substring(idx + 1); try { _headers.Add(key, value); } catch (Exception) { Logger.WriteEntry("Duplicate header key in line: " + line, LogLevel.Information); } } } /// <summary> /// Format the object contents into a useful string representation. /// </summary> ///<returns><c>String</c> representation of the <c>SimpleHttpRequest</c> as the <i>HttpMethod FilePath Protocol</i>.</returns> override public String ToString() { return HttpMethod + " " + FilePath + " " + Protocol; } /// <summary> /// Close the <c>SimpleHttpRequest</c>. This flushes and closes all associated io streams. /// </summary> public void Close() { _output.Flush(); _output.Close(); _input.Close(); _client.Close(); } } }