Skip to content

Instantly share code, notes, and snippets.

/HttpServer.cs Secret

Created February 16, 2013 01:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/bfe618a877fc658acbab to your computer and use it in GitHub Desktop.
Save anonymous/bfe618a877fc658acbab to your computer and use it in GitHub Desktop.
using HttpMachine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Foo {
public sealed class Client {
internal Stream Stream { get; set; }
}
public enum HttpMethod {
Get,
Post,
Put,
Delete,
Head,
}
public delegate Task<HttpResponse> RequestHandler(HttpRequest request);
public sealed class HttpRequest {
public HttpMethod Method { get; set; }
public string Path { get; set; }
public string QueryString { get; set; }
public IDictionary<string, string> Headers { get; set; }
public List<byte> Body { get; set; }
public HttpRequest() {
Headers = new Dictionary<string, string>();
Body = new List<byte>();
}
}
internal static class StreamExtensions {
public static async Task WriteAsync(this Stream stream, string @string) {
var buffer = UTF8Encoding.UTF8.GetBytes(@string);
await stream.WriteAsync(buffer, 0, buffer.Length);
}
}
public sealed class HttpResponse {
public uint StatusCode { get; set; }
public IDictionary<string, string> Headers { get; set; }
public Stream BodyStream { get; set; }
public HttpResponse() {
StatusCode = 200;
Headers = new Dictionary<string, string>{
{"transfer-encoding", "chunked"}
};
}
public async Task WriteToStreamAsync(Stream stream) {
await stream.WriteAsync(String.Format("HTTP/1.1 {0}\r\n", StatusCode));
foreach (var header in Headers) {
await stream.WriteAsync(String.Format("{0}: {1}\r\n", header.Key, header.Value));
}
await stream.WriteAsync("\r\n");
if (BodyStream != null) {
var buffer = new byte[1024];
int nread;
do {
nread = await BodyStream.ReadAsync(buffer, 0, buffer.Length);
await stream.WriteAsync(String.Format("{0:X}\r\n", nread));
await stream.WriteAsync(buffer, 0, nread);
await stream.WriteAsync("\r\n");
} while (nread != -1);
await stream.WriteAsync("0\r\n\r\n");
}
}
}
public class HttpServer {
private sealed class ParserHandler : IHttpParserHandler {
private Stream Stream { get; set; }
private HttpRequest Request { get; set; }
private string HeaderName { get; set; }
public event EventHandler<HttpRequest> OnRequest;
public ParserHandler(Stream stream) {
Stream = stream;
}
public void OnMessageBegin(HttpParser parser) {
Request = new HttpRequest();
}
public void OnMethod(HttpParser parser, string method) {
Request.Method = new Dictionary<string, HttpMethod> {
{"GET", HttpMethod.Get},
{"POST", HttpMethod.Post},
{"PUT", HttpMethod.Put},
{"DELETE", HttpMethod.Delete},
{"HEAD", HttpMethod.Head},
}[method];
}
public void OnRequestUri(HttpParser parser, string requestUri) {
Request.Path = requestUri;
}
public void OnFragment(HttpParser parser, string fragment) {
// wtf is this
}
public void OnQueryString(HttpParser parser, string queryString) {
Request.QueryString = queryString;
}
public void OnHeaderName(HttpParser parser, string name) {
HeaderName = name;
}
public void OnHeaderValue(HttpParser parser, string value) {
if (Request.Headers.ContainsKey(HeaderName)) {
Request.Headers[HeaderName] += "," + value;
} else {
Request.Headers[HeaderName] = value;
}
}
public void OnHeadersEnd(HttpParser parser) { /* no-op */ }
public void OnBody(HttpParser parser, ArraySegment<byte> data) {
Request.Body.AddRange(data);
}
public void OnMessageEnd(HttpParser parser) {
OnRequest.Invoke(this, Request);
}
}
public RequestHandler RequestHandler { get; set; }
public void Run(string host, int port) {
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint(IPAddress.Parse(host), port);
socket.Bind(endPoint);
socket.Listen(128);
for (; ; ) {
var clientSocket = socket.Accept();
var stream = new NetworkStream(clientSocket);
HandleClient(new Client { Stream = stream });
}
}
private async Task HandleClient(Client client) {
var parserHandler = new ParserHandler(client.Stream);
var parser = new HttpParser(parserHandler);
parserHandler.OnRequest += async (sender, request) => {
var response = await RequestHandler(request);
response.WriteToStreamAsync(client.Stream);
};
for (; ; ) {
var buffer = new byte[1024];
int bytesRead;
do {
bytesRead = await client.Stream.ReadAsync(buffer, 0, buffer.Length);
var bytesParsed = parser.Execute(new ArraySegment<byte>(buffer));
if (bytesParsed != bytesRead) {
// TODO: Decent error.
throw new Exception();
}
} while (bytesRead != -1);
parser.Execute(new ArraySegment<byte>());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment