sharp-application-server/server/HttpRequest.cs

230 lines
5.8 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using appsrv.exceptions;
using appsrv.http;
namespace appsrv.server
{
public class HttpRequest
{
private Stream stream;
private StreamReader streamReader;
private List<HttpRequest> currentRequests = new List<HttpRequest>();
private MemoryStream responseStream;
private StreamWriter responseWriter;
Dictionary<String, String> requestHeaders = new Dictionary<string, string>();
Dictionary<String, String> responseHeaders = new Dictionary<string, string>();
public EndPoint Client { get; private set; }
public ApplicationServer ApplicationServer { get; private set; }
public Uri URI { get; private set; }
public String Method { get; private set; }
public String RequestURL { get; private set; }
public String Protocol { get; private set; }
public String Hostname { get; private set; }
public int Port { get; private set; }
public QueryStringParameters Query { get; private set; }
public int StatusCode { get; set; } = 200;
public HttpRequest(ApplicationServer applicationServer, TcpClient client)
{
this.ApplicationServer = applicationServer;
this.Client = client.Client.RemoteEndPoint;
this.stream = client.GetStream();
this.streamReader = new StreamReader(this.stream);
String rLine = this.streamReader.ReadLine();
String[] rTokens = SplitWhitespace(
rLine
);
Console.WriteLine("Tokens: {0}", rTokens);
if (rTokens.Length != 3){
throw new IllegalRequestException(rLine);
}
this.Method = rTokens[0];
this.RequestURL = rTokens[1];
this.Protocol = rTokens[2];
}
public override string ToString()
{
return string.Format("[HttpRequest: Client={0}, ApplicationServer={1}, Hostname={6} Port={7} URI={2}, Method={3}, RequestURL={4}, Protocol={5} Query={8}]", Client, ApplicationServer, URI, Method, RequestURL, Protocol, Hostname, Port,Query);
}
public String GetRequestHeader(String name, String def = "")
{
name = name.ToLowerInvariant();
if (requestHeaders.ContainsKey(name))
return requestHeaders[name];
return def;
}
public String GetResponseHeader(String name, String def = "")
{
name = name.ToLowerInvariant();
if (responseHeaders.ContainsKey(name))
return responseHeaders[name];
return def;
}
public void SetResponseHeader(String name,String value){
name = name.ToLowerInvariant();
if (value == null)
{
this.responseHeaders.Remove(name);
}
else
{
this.responseHeaders[name] = value;
}
}
public Stream ResponseStream
{
get {
if (responseStream == null)
responseStream = new MemoryStream();
return responseStream;
}
}
public TextWriter ResponseWriter
{
get
{
if (this.responseWriter == null)
{
this.responseWriter = new StreamWriter(this.responseStream);
}
return this.responseWriter;
}
}
private String[] SplitWhitespace(String line){
LinkedList<String> tokens = new LinkedList<string>();
StringBuilder sb = new StringBuilder();
for (int n = 0; n < line.Length;)
{
for (; n < line.Length && !Char.IsWhiteSpace(line[n]); n++)
sb.Append(line[n]);
tokens.AddLast(sb.ToString());
sb.Clear();
for (; n < line.Length && Char.IsWhiteSpace(line[n]); n++) {}
}
return tokens.ToArray();
}
private void ReadHttpHeaders(){
String headerLine = this.streamReader.ReadLine();
String hName = null;
while (!headerLine.Equals(String.Empty)){
if (Char.IsWhiteSpace(headerLine[0]) && hName != null)
{
requestHeaders[hName] = requestHeaders[hName] + "," + headerLine.Trim();
} else {
String[] split = headerLine.Split(new char[] { ':' }, 2);
if (split.Length != 2){
throw new IllegalRequestException("malformed header");
}
hName = split[0].ToLowerInvariant();
requestHeaders[hName] = split[1];
}
headerLine = this.streamReader.ReadLine();
}
foreach (String hname in requestHeaders.Keys.ToArray()){
requestHeaders[hname] = requestHeaders[hname].Trim();
}
}
private void InterpretRequestHeaders()
{
String host = GetRequestHeader("host");
String[] hostTokens = host.Split(':');
Hostname = hostTokens[0];
if (hostTokens.Length > 1){
Port = int.Parse(hostTokens[1]);
}
URI = new Uri(String.Format("http://{0}:{1}/{2}", Hostname, Port, RequestURL));
Query = new QueryStringParameters(URI.Query);
}
private void SendResponse()
{
using (StreamWriter writer = new StreamWriter(this.stream))
{
ResponseStream.Position = 0;
SetResponseHeader("Content-Length", responseStream.Length.ToString());
writer.WriteLine("{0} {1} {2}", Protocol, StatusCode, HttpStatusCodes.GetStatusMessage(StatusCode));
foreach (String rhName in responseHeaders.Keys){
writer.WriteLine("{0}: {1}", rhName, responseHeaders[rhName]);
}
writer.WriteLine();
writer.Flush();
responseStream.CopyTo(this.stream);
}
}
public void Handle(){
this.ReadHttpHeaders();
this.InterpretRequestHeaders();
Console.WriteLine("Request Handled: {0}",this);
foreach (String key in this.requestHeaders.Keys){
Console.WriteLine("HH: {0} = {1}",key,this.requestHeaders[key]);
}
ApplicationServer.HandleRequest(this);
SendResponse();
this.streamReader.Close();
this.stream.Close();
}
}
}