1 module hunt.http.routing.RoutingContext;
2 
3 import hunt.http.server.HttpSession;
4 import hunt.http.server.HttpServerRequest;
5 import hunt.http.server.HttpServerResponse;
6 
7 import hunt.http.codec.http.model;
8 import hunt.http.routing.handler;
9 
10 import hunt.http.Cookie;
11 import hunt.http.HttpConnection;
12 import hunt.http.HttpHeader;
13 import hunt.http.HttpFields;
14 import hunt.http.HttpOutputStream;
15 import hunt.http.HttpStatus;
16 import hunt.http.HttpVersion;
17 
18 import hunt.io.ByteBuffer;
19 import hunt.collection.List;
20 import hunt.collection.Map;
21 import hunt.concurrency.Promise;
22 import hunt.Exceptions;
23 import hunt.Functions;
24 import hunt.io.BufferUtils;
25 import hunt.logging;
26 import hunt.net.util.HttpURI;
27 import hunt.stream.Common;
28 import hunt.util.Common;
29 
30 import std.conv;
31 import std.variant;
32 
33 alias RoutingHandler =  void delegate(RoutingContext routingContext);
34 
35 deprecated("Using RouteHandler instead.")
36 alias Handler = RouteHandler;
37 
38 /**
39  * 
40  */
41 interface RouteHandler {
42     void handle(RoutingContext context);
43 }
44 
45 
46 /**
47  * A new RoutingContext(ctx) instance is created for each HTTP request.
48  * <p>
49  * You can visit the RoutingContext instance in the whole router chain.
50  * It provides HTTP request/response API and allows you to maintain arbitrary data that lives for the lifetime of the context.
51  * Contexts are discarded once they have been routed to the handler for the request.
52  * <p>
53  * The context also provides access to the Session, cookies and body for the request, given the correct handlers in the application.
54  *
55  * 
56  */
57 abstract class RoutingContext : Closeable {
58     
59     final T getAttributeAs(T)(string key) {
60         return getAttribute(key).get!T();
61     }
62 
63     final void setAttribute(T)(string key, T value) if(!is(T == Variant)) {
64         setAttribute(key, value.Variant());
65     }
66 
67     Variant getAttribute(string key);
68 
69     void setAttribute(string key, Variant value);
70 
71     Variant removeAttribute(string key);
72 
73     Variant[string] getAttributes();
74 
75     HttpServerResponse getResponse();
76 
77     void response(HttpServerResponse response);
78 
79     // HttpResponse getAsyncResponse();
80 
81     HttpServerRequest getRequest();
82 
83     // HttpOutputStream getOutputStream();  
84     OutputStream outputStream(); 
85 
86     int getConnectionId();
87 
88     HttpConnection httpConnection();
89 
90     string getRouterParameter(string name);
91 
92     string getWildcardMatchedResult(int index) {
93         return getRouterParameter("param" ~ index.to!string());
94     }
95 
96     string getRegexGroup(int index) {
97         return getRouterParameter("group" ~ index.to!string());
98     }
99 
100     string getPathParameter(string name) {
101         return getRouterParameter(name);
102     }
103 
104     // Optional!string getRouterParamOpt(string name) {
105     //     return Optional.ofNullable(getRouterParameter(name));
106     // }
107 
108     /**
109      * Set the HTTP body packet receiving callback.
110      *
111      * @param content The HTTP body data receiving callback. When the server receives the HTTP body packet, it will be called.
112      * @return RoutingContext
113      */
114     // RoutingContext onContent(Action1!ByteBuffer content);
115 
116     /**
117      * Set the HTTP body packet complete callback.
118      *
119      * @param contentComplete The HTTP body packet complete callback.
120      * @return RoutingContext
121      */
122     // RoutingContext onContentComplete(Action1!(HttpRequest) contentComplete);
123 
124     /**
125      * Set the HTTP message complete callback.
126      *
127      * @param messageComplete the HTTP message complete callback.
128      * @return RoutingContext
129      */
130     // RoutingContext onMessageComplete(Action1!(HttpRequest) messageComplete);
131 
132     /**
133      * If return true, it represents you has set a HTTP body data receiving callback.
134      *
135      * @return If return true, it represents you has set a HTTP body data receiving callback
136      */
137     bool isAsynchronousRead();
138 
139     void enableAsynchronousRead();
140 
141     /**
142      * Execute the next handler.
143      *
144      * @return If return false, it represents current handler is the last.
145      */
146     void next();
147 
148     /**
149      * If return false, it represents current handler is the last.
150      *
151      * @return If return false, it represents current handler is the last.
152      */
153     bool hasNext();
154 
155     // <T> RoutingContext complete(Promise<T> promise);
156 
157     // <T> bool next(Promise<T> promise);
158 
159     // <T> T> nextFuture() {
160     //     Promise.Completable<T> completable = new Promise.Completable<>();
161     //     next(completable);
162     //     return completable;
163     // }
164 
165     // <T> T> complete() {
166     //     Promise.Completable<T> completable = new Promise.Completable<>();
167     //     complete(completable);
168     //     return completable;
169     // }
170 
171     
172     void succeed(bool t) { 
173         version(HUNT_HTTP_DEBUG) trace("do nothing");
174     }
175 
176     void fail(Exception ex) { 
177         // version(HUNT_DEBUG) warning(ex);
178         // if(!isCommitted()) {
179         //     HttpServerResponse res = getResponse();
180         //     if(res !is null) {
181         //         res.setStatus(HttpStatus.BAD_REQUEST_400);
182         //     }
183         //     end(ex.msg);
184         // }
185     }
186 
187     // request wrap
188     string getMethod() {
189         return getRequest().getMethod();
190     }
191 
192     HttpURI getURI() {
193         return getRequest().getURI();
194     }
195 
196     HttpVersion getHttpVersion() {
197         return getRequest().getHttpVersion();
198     }
199 
200     HttpFields getFields() {
201         return getRequest().getFields();
202     }
203 
204     long getContentLength() {
205         return getRequest().getContentLength();
206     }
207 
208     Cookie[] getCookies() {
209         return getRequest().getCookies();
210     }
211 
212     string getParameter(string name);
213 
214     List!string getParameterValues(string name);
215 
216     Map!(string, List!string) getParameterMap();
217 
218     // Collection!Part getParts();
219 
220     // Part getPart(string name);
221 
222     // InputStream getInputStream();
223 
224     // BufferedReader getBufferedReader();
225 
226     string getStringBody(string charset); 
227 
228     string getStringBody(); 
229 
230     // <T> T getJsonBody(Class<T> clazz);
231 
232     // <T> T getJsonBody(GenericTypeReference<T> typeReference);
233 
234     // JsonObject getJsonObjectBody();
235 
236     // JsonArray getJsonArrayBody();
237 
238     // response wrap
239     RoutingContext setStatus(int status) {
240         getResponse().setStatus(status);
241         return this;
242     }
243 
244     RoutingContext setReason(string reason) {
245         getResponse().setReason(reason);
246         return this;
247     }
248 
249     RoutingContext setHttpVersion(HttpVersion httpVersion) {
250         getResponse().setHttpVersion(httpVersion);
251         return this;
252     }
253 
254     // RoutingContext put(HttpHeader header, string value) {
255     //     getResponse().getFields().put(header, value);
256     //     return this;
257     // }
258 
259     // RoutingContext put(string header, string value) {
260     //     getResponse().getFields().put(header, value);
261     //     return this;
262     // }
263 
264     // RoutingContext add(HttpHeader header, string value) {
265     //     getResponse().getFields().add(header, value);
266     //     return this;
267     // }
268 
269     // RoutingContext add(string name, string value) {
270     //     getResponse().getFields().add(name, value);
271     //     return this;
272     // }
273 
274     HttpFields getResponseHeaders() {
275         return getResponse().getFields();
276     }
277 
278     void responseHeader(HttpHeader header, HttpHeaderValue value) {
279         getResponse().getFields().put(header, value);
280     }
281 
282     void responseHeader(string header, string value) {
283         getResponse().getFields().put(header, value);
284     }
285 
286     void responseHeader(HttpHeader header, string value) {
287         getResponse().getFields().put(header, value);
288     }
289 
290     RoutingContext addCookie(Cookie cookie) {
291         getResponse().addCookie(cookie);
292         return this;
293     }
294 
295     RoutingContext write(string value);
296 
297     // RoutingContext writeJson(Object object) {
298     //     put(HttpHeader.CONTENT_TYPE, MimeTypes.Type.APPLICATION_JSON_UTF_8.asString()).write(Json.toJson(object));
299     //     return this;
300     // }
301 
302     RoutingContext write(byte[] b, int off, int len);
303 
304     RoutingContext write(byte[] b) {
305         return write(b, 0, cast(int)b.length);
306     }
307 
308     RoutingContext end(string value) {
309         return write(value).end();
310     }
311 
312     RoutingContext end();
313 
314     RoutingContext end(byte[] b) {
315         return write(b).end();
316     }
317 
318     void flush();
319 
320     bool isCommitted();
321 
322     void redirect(string url) {
323         setStatus(HttpStatus.FOUND_302);
324         getResponseHeaders().put(HttpHeader.LOCATION, url);
325         DefaultErrorResponseHandler.Default().render(this, HttpStatus.FOUND_302, null);
326     }
327 
328 
329     // HTTP session API
330     HttpSession getSessionById(string id);
331 
332     HttpSession getSession();
333 
334     HttpSession getSession(bool create);
335 
336     HttpSession getAndCreateSession(int maxAge);
337 
338     int getSessionSize();
339 
340     bool removeSessionById(string id);
341     
342     bool removeSession();
343 
344     bool updateSession(HttpSession httpSession);
345 
346     bool isRequestedSessionIdFromURL();
347 
348     bool isRequestedSessionIdFromCookie();
349 
350     string getRequestedSessionId();
351 
352     string getSessionIdParameterName();
353 
354     string groupName();
355     
356     void groupName(string name);
357 
358     // Template API
359     // void renderTemplate(string resourceName, Object scope);
360 
361     // void renderTemplate(string resourceName, Object[] scopes);
362 
363     // void renderTemplate(string resourceName, List!Object scopes);
364 
365     // void renderTemplate(string resourceName) {
366     //     renderTemplate(resourceName, Collections.emptyList());
367     // }
368 
369 }