1 module http_serv; 2 3 import heaploop.looping; 4 import heaploop.networking.http; 5 import std.string; 6 import std.stdio; 7 import std.typecons; 8 9 10 alias Tuple!(int, string[string], string[]) RackResponse; 11 12 interface RackApp { 13 RackResponse call(string[string] env); 14 } 15 16 class RackAdapter { 17 private: 18 RackApp _app; 19 20 public: 21 this(RackApp app) { 22 _app = app; 23 } 24 25 void handleRequest(HttpRequest req, HttpResponse res) { 26 string[string] env = requestToEnv(req); 27 RackResponse response = _app.call(env); 28 sendResponse(res, response); 29 } 30 31 private: 32 string[string] requestToEnv(HttpRequest request) { 33 string[string] environment; 34 35 environment["HTTP_VERSION"] = request.protocolVersion.toString; 36 environment["REQUEST_METHOD"] = request.method; 37 environment["REQUEST_URI"] = request.rawUri; 38 environment["REQUEST_PATH"] = request.uri.path; 39 environment["SCRIPT_NAME"] = ""; 40 environment["PATH_INFO"] = request.uri.path; 41 environment["QUERY_STRING"] = request.uri.query; 42 environment["FRAGMENT"] = request.uri.fragment; 43 44 string headerKey; 45 auto transTable = makeTrans("-", "_"); 46 foreach(h; request.headers) { 47 headerKey = "HTTP_%s".format(h.name.toUpper.translate(transTable)); 48 environment[headerKey] = h.value; 49 } 50 return environment; 51 } 52 53 void sendResponse(HttpResponse response, RackResponse rackResponse) { 54 response.statusCode(rackResponse[0]); 55 foreach(string header, string value; rackResponse[1]) { 56 response.addHeader(header, value); 57 } 58 foreach(string chunk; rackResponse[2]) { 59 response.write(chunk); 60 } 61 response.end; 62 } 63 } 64 65 class HelloApp : RackApp { 66 RackResponse call(string[string] env) { 67 string[string] headers; 68 string[] resBody; 69 70 headers["Content-Type"] = "text/plain"; 71 resBody ~= "Hello, World!"; 72 73 return RackResponse(200, headers, resBody); 74 } 75 } 76 77 void main() { 78 loop ^^= { 79 auto server = new HttpListener; 80 server.bind4("0.0.0.0", 3000); 81 writeln("listening on http://localhost:3000"); 82 server.listen ^^= (connection) { 83 try { 84 auto app = new HelloApp; 85 auto adapter = new RackAdapter(app); 86 connection.process ^^= (&adapter.handleRequest); 87 } catch(Exception ex) { 88 writeln("something went wrong processing http in this connection"); 89 } 90 }; 91 }; 92 }