1 module webcaret.application;
2 
3 import router;
4 import heaploop.networking.http;
5 import heaploop.networking.tcp : TcpStream;
6 import std.string : format;
7 import std.stdio : writeln;
8 
9 package:
10 
11 class AppHttpServerConnection : HttpServerConnection {
12 
13     public:
14         this(TcpStream stream) {
15             super(stream);
16         }
17 
18     protected:
19         override HttpRequest createIncomingMessage() {
20             return new ApplicationHttpRequest(this);
21         }
22 }
23 
24 class AppHttpListener : HttpListener {
25 
26     protected:
27         override HttpServerConnection createConnection(TcpStream stream) {
28             return new AppHttpServerConnection(stream);
29         }
30 }
31 
32 public:
33 
34 class ApplicationHttpRequest : HttpRequest, IRoutedRequest {
35 
36     private:
37         string[string] _params;
38         string[string] _form;
39 
40 package:
41 
42     void prepareRequest() {
43         switch(this.contentType) {
44             default:
45                 return;
46             case "application/x-www-form-urlencoded": {
47                 ubyte[] formData;
48                 this.read ^= (chunk) {
49                     formData ~= chunk.buffer;
50                 };
51                 string formText = cast(string)formData;
52                 this.form = parseURLEncodedForm(formText);
53                 break;
54             }
55             case "multipart/form-data": {
56                 assert(false, "multipart/form-data is not implemented yet, pull requests are welcome :)");
57             }
58         }
59     }
60 
61 
62     public:
63         @property {
64             string[string] params() nothrow {
65                 return _params;
66             }
67             void params(string[string] params) nothrow {
68                 _params = params;
69             }
70             string[string] form() nothrow {
71                 return _form;
72             }
73             void form(string[string] form) nothrow {
74                 _form = form;
75             }
76         }
77         this(HttpServerConnection connection) {
78             super(connection);
79         }
80 }
81 
82 class Application {
83     private:
84         Router!(ApplicationHttpRequest, HttpResponse) _router;
85 
86     public:
87         this() {
88             _router = new Router!(ApplicationHttpRequest, HttpResponse);
89         }
90 
91         @property {
92             Router!(ApplicationHttpRequest, HttpResponse) router() nothrow {
93                 return _router;
94             }
95         }
96 
97         void serve(string address, int port) {
98             auto server = new AppHttpListener;
99             server.bind4(address, port);
100             "Web^ Application serving http://%s:%d".format(address, port).writeln;
101             server.listen ^^= (connection) {
102                 debug writeln("HTTP Agent just connected");
103                 connection.process ^^= (request, response) {
104                     auto appRequest = cast(ApplicationHttpRequest)request;
105                     appRequest.prepareRequest();
106                     _router.execute(request.method, request.uri.path, appRequest, response);
107                 };
108             };
109         }
110 }
111