1 module hunt.http.HttpConnection;
2 
3 import hunt.http.HttpConnection;
4 import hunt.http.HttpOptions;
5 import hunt.http.HttpVersion;
6 
7 import hunt.io.ByteBuffer;
8 import hunt.concurrency.ScheduledThreadPoolExecutor;
9 import hunt.Exceptions;
10 import hunt.Functions;
11 import hunt.logging;
12 import hunt.net.AbstractConnection;
13 import hunt.net.Connection;
14 import hunt.net.Exceptions;
15 import hunt.net.secure.SecureSession;
16 import hunt.util.Common;
17 
18 import std.exception;
19 import std.socket;
20 
21 /**
22  * 
23  */
24 enum HttpConnectionType {
25     HTTP1, HTTP2, HTTP_TUNNEL, WEB_SOCKET
26 }
27 
28 interface HttpConnection : Closeable { // : Connection 
29 
30     enum string NAME = typeof(this).stringof;
31 
32     int getId();
33 
34     Connection getTcpConnection();
35 
36     HttpVersion getHttpVersion();
37 
38     Address getLocalAddress();
39 
40     Address getRemoteAddress();
41 
42     HttpConnection onClose(Action1!(HttpConnection) handler);
43 
44     HttpConnection onException(Action2!(HttpConnection, Exception) handler);
45 
46 
47     /**
48      * Returns the value of the user-defined attribute of this connection.
49      *
50      * @param key the key of the attribute
51      * @return <tt>null</tt> if there is no attribute with the specified key
52      */
53     Object getAttribute(string key);
54     
55     /**
56      * Sets a user-defined attribute.
57      *
58      * @param key the key of the attribute
59      * @param value the value of the attribute
60      */
61     void setAttribute(string key, Object value);
62 
63     /**
64      * Removes a user-defined attribute with the specified key.
65      *
66      * @param key The key of the attribute we want to remove
67      * @return The old value of the attribute.  <tt>null</tt> if not found.
68      */
69     Object removeAttribute(string key);
70 
71     /**
72      * @param key The key of the attribute we are looking for in the connection 
73      * @return <tt>true</tt> if this connection contains the attribute with
74      * the specified <tt>key</tt>.
75      */
76     bool containsAttribute(string key);
77 }
78 
79 
80 /**
81  * 
82  */
83 abstract class AbstractHttpConnection : HttpConnection { 
84     
85     protected ScheduledThreadPoolExecutor executor;
86 
87     protected Connection _tcpSession;
88     protected HttpVersion _httpVersion;
89     // protected ConnectionEvent!HttpConnection connectionEvent;
90     protected Action1!HttpConnection _closeHandler;
91     protected Action2!(HttpConnection, Exception) _exceptionHandler;
92 
93     this(Connection tcpSession, HttpVersion httpVersion) {
94         this._tcpSession = tcpSession;
95         this._httpVersion = httpVersion;
96         // connectionEvent = new ConnectionEvent!(HttpConnection)(this);
97     }
98 
99     // alias tcpSession this ;
100     Connection getTcpConnection() {
101         return _tcpSession;
102     }
103 
104     abstract HttpConnectionType getConnectionType();
105 
106 
107     Address getLocalAddress() {
108         return _tcpSession.getLocalAddress();
109     }
110 
111     Address getRemoteAddress() {
112         return _tcpSession.getRemoteAddress();
113     }
114 
115     override HttpVersion getHttpVersion() {
116         return _httpVersion;
117     }
118 
119     int getId() {
120         return _tcpSession.getId();
121     }
122 
123     bool isSecured() {
124         return _tcpSession.isSecured();
125     }
126 
127     void setAttribute(string key, Object value) {
128         _tcpSession.setAttribute(key, value);
129     }
130     
131     Object getAttribute(string key) {
132         return _tcpSession.getAttribute(key);
133     }
134     
135     Object removeAttribute(string key) {
136         return _tcpSession.removeAttribute(key);
137     }
138 
139     bool containsAttribute(string key) {
140         return _tcpSession.containsAttribute(key);
141     }
142 
143     override
144     HttpConnection onClose(Action1!HttpConnection handler) {
145         _closeHandler = handler;
146         return this;
147         // return connectionEvent.onClose(closedListener);
148     }
149 
150     override
151     HttpConnection onException(Action2!(HttpConnection, Exception) handler) {
152         _exceptionHandler = handler;
153         return this;
154         // return connectionEvent.onException(exceptionListener);
155     }
156 
157     void notifyClose() {
158         // implementationMissing(false);
159         // connectionEvent.notifyClose();
160         if(_closeHandler !is null) {
161             _closeHandler(this);
162         }
163     }
164 
165     void notifyException(Exception t) {
166         // implementationMissing(false);
167         if(_exceptionHandler !is null) {
168             _exceptionHandler(this, t);
169         }
170         // connectionEvent.notifyException(t);
171     }
172 
173     ///
174     void close() {
175         _tcpSession.close();
176     }
177 
178 
179 
180     // ByteBuffer decrypt(ByteBuffer buffer) {
181 
182     //     implementationMissing(false);
183     //     return null;
184         
185     //     // if (isEncrypted()) {
186     //     //     try {
187     //     //         return secureSession.read(buffer);
188     //     //     } catch (IOException e) {
189     //     //         throw new SecureNetException("decrypt exception", e);
190     //     //     }
191     //     // } else {
192     //     //     return null;
193     //     // }
194     // }
195 
196     // void encrypt(ByteBufferOutputEntry entry) {
197     //     implementationMissing(false);
198     //     // encrypt!(ByteBuffer)(entry, (buffers, callback) {
199     //     //     try {
200     //     //         secureSession.write(buffers, callback);
201     //     //     } catch (IOException e) {
202     //     //         throw new SecureNetException("encrypt exception", e);
203     //     //     }
204     //     // });
205     // }
206 
207     // void encrypt(ByteBufferArrayOutputEntry entry) {
208     //     encrypt(entry, (buffers, callback) {
209     //         try {
210     //             secureSession.write(buffers, callback);
211     //         } catch (IOException e) {
212     //             throw new SecureNetException("encrypt exception", e);
213     //         }
214     //     });
215     // }
216 
217     // void encrypt(ByteBuffer buffer) {
218     //     // try {
219     //     //     secureSession.write(buffer, Callback.NOOP);
220     //     // } catch (IOException e) {
221     //     //     errorf(e.toString());
222     //     //     throw new SecureNetException("encrypt exception", e);
223     //     // }
224 
225     //     implementationMissing(false);
226     // }
227 
228     // void encrypt(ByteBuffer[] buffers) {
229     //     // try {
230     //     //     secureSession.write(buffers, Callback.NOOP);
231     //     // } catch (IOException e) {
232     //     //     throw new SecureNetException("encrypt exception", e);
233     //     // }
234     //     implementationMissing(false);
235     // }
236 
237     // private void encrypt(T)(OutputEntry!T entry, Action2!(T, Callback) et) {
238 
239     //     implementationMissing(false);
240     //     // if (isEncrypted()) {
241     //     //     et(entry.getData(), entry.getCallback());
242     //     // }
243     // }
244 
245 }
246  
247 
248 /**
249  * 
250  */
251 abstract class HttpConnectionHandler : NetConnectionHandlerAdapter {
252 
253     // override
254     // DataHandleStatus messageReceived(Connection connection, Object message) {
255     //     implementationMissing(false);
256     //     return DataHandleStatus.Done;
257     // }
258 
259     override
260     void exceptionCaught(Connection connection, Throwable t) {
261         try {
262             version(HUNT_DEBUG) warningf("HTTP handler exception: %s", t.toString());
263             if(connection is null) {
264                 version(HUNT_DEBUG) warning("Connection is null.");
265             } else {
266                 Object attachment = connection.getAttribute(HttpConnection.NAME); 
267                 if (attachment is null) {
268                     version(HUNT_DEBUG) warningf("attachment is null");
269                 } else {
270                     AbstractHttpConnection httpConnection = cast(AbstractHttpConnection) attachment;
271                     if (httpConnection !is null ) {
272                         Exception ex = cast(Exception)t;
273                         if(ex is null && t !is null) {
274                             warningf("Can't handle a exception. Exception: %s", t.msg);
275                         }
276                         httpConnection.notifyException(ex);
277                     } 
278                 }
279             }
280         } finally {
281             if(connection !is null)
282                 connection.close();
283         }
284     }
285 
286     override
287     void connectionClosed(Connection connection) {
288         version(HUNT_DEBUG) {
289             infof("Connection %d closed event. Remote host: %s", 
290                 connection.getId(), connection.getRemoteAddress());
291         }
292 
293         Object attachment = connection.getAttribute(HttpConnection.NAME);
294         if (attachment is null) {
295             version(HUNT_HTTP_DEBUG) warningf("no connection attached");
296         } else {
297             version(HUNT_HTTP_DEBUG) tracef("attached connection: %s", typeid(attachment).name);
298             AbstractHttpConnection httpConnection = cast(AbstractHttpConnection) attachment;
299             if (httpConnection !is null) {
300                 try {
301                     httpConnection.notifyClose();
302                 } catch (Exception e) {
303                     errorf("The http connection close exception", e);
304                 }
305             } 
306         }
307     }
308 
309     // override
310     // void connectionOpened(Connection connection) {
311     //     implementationMissing(false);
312     // }
313 
314     // override
315     // void failedOpeningConnection(int connectionId, Throwable t) { 
316     //     errorf("Failed to open a http connection %d, reason: <%s>", connectionId, t.msg);
317     //     super.failedOpeningConnection(connectionId, t);
318     // }
319 
320     override
321     void failedAcceptingConnection(int connectionId, Throwable t) { implementationMissing(false); }
322 }