1 module hunt.http.server.Http1ServerDecoder;
2 
3 import hunt.http.server.Http1ServerConnection;
4 import hunt.http.server.Http1ServerTunnelConnection;
5 import hunt.http.server.Http2ServerDecoder;
6 
7 import hunt.http.codec.http.decode.HttpParser;
8 import hunt.http.codec.websocket.decode.WebSocketDecoder;
9 
10 import hunt.http.HttpConnection;
11 import hunt.http.HttpConnection;
12 import hunt.net.codec.Decoder;
13 import hunt.http.HttpConnection;
14 import hunt.net.Connection;
15 
16 import hunt.io.ByteBuffer;
17 import hunt.io.BufferUtils;
18 import hunt.io.channel;
19 import hunt.Exceptions;
20 import hunt.logging;
21 import std.conv;
22 
23 /**
24 */
25 class Http1ServerDecoder : DecoderChain {
26 
27     private WebSocketDecoder webSocketDecoder;
28     private Http2ServerDecoder http2ServerDecoder;
29 
30     this(WebSocketDecoder webSocketDecoder, Http2ServerDecoder http2ServerDecoder) {
31         super(null);
32         this.webSocketDecoder = webSocketDecoder;
33         this.http2ServerDecoder = http2ServerDecoder;
34     }
35 
36     override DataHandleStatus decode(ByteBuffer buffer, Connection session) {
37         DataHandleStatus resultStatus = DataHandleStatus.Done;
38 
39         ByteBuffer buf = BufferUtils.toHeapBuffer(buffer);
40 
41         scope(exit) {
42             BufferUtils.clear(buffer);
43         }
44 
45         Object attachment = session.getAttribute(HttpConnection.NAME);
46         version (HUNT_HTTP_DEBUG) {
47             tracef("session type: %s", attachment is null ? "null" : typeid(attachment).name);
48         }
49 
50         AbstractHttpConnection abstractConnection = cast(AbstractHttpConnection) attachment;
51         if (abstractConnection is null) {
52             warningf("Bad connection instance: %s", attachment is null ? "null" : typeid(attachment).name);
53             return resultStatus;
54         }
55 
56         switch (abstractConnection.getConnectionType()) {
57         case HttpConnectionType.HTTP1: {
58                 Http1ServerConnection http1Connection = cast(Http1ServerConnection) attachment;
59                 if (http1Connection.getTunnelConnectionPromise() is null) {
60                     HttpParser parser = http1Connection.getParser();
61                     version (HUNT_HTTP_DEBUG) trace("Runing http1 parser for a buffer...");
62                     while (buf.hasRemaining()) {
63                         parser.parseNext(buf);
64                         if (http1Connection.getUpgradeHttp2Complete()) {
65                             resultStatus = http2ServerDecoder.decode(buf, session);
66                             break;
67                         } else if (http1Connection.getUpgradeWebSocketComplete()) {
68                             resultStatus = webSocketDecoder.decode(buf, session);
69                             break;
70                         }
71                     }
72 
73                     HttpParserState parserState = parser.getState();
74                     version (HUNT_HTTP_DEBUG) {
75                         infof("HTTP1 parsing done with a buffer. Parser state: %s", parserState);
76                     }
77 
78                     if(!parser.isIdle()) {
79                         resultStatus = DataHandleStatus.Pending;
80                     } 
81                 } else {
82                     Http1ServerTunnelConnection tunnelConnection = http1Connection.createHttpTunnel();
83                     if (tunnelConnection.content != null) {
84                         tunnelConnection.content(buf);
85                     }
86                 }
87             }
88             break;
89         case HttpConnectionType.HTTP2: {
90                 resultStatus = http2ServerDecoder.decode(buf, session);
91             }
92             break;
93         case HttpConnectionType.WEB_SOCKET: {
94                 resultStatus = webSocketDecoder.decode(buf, session);
95             }
96             break;
97         case HttpConnectionType.HTTP_TUNNEL: {
98                 Http1ServerTunnelConnection tunnelConnection = 
99                     cast(Http1ServerTunnelConnection) session.getAttribute(HttpConnection.NAME); // session.getAttachment();
100                 if (tunnelConnection.content != null) {
101                     tunnelConnection.content(buf);
102                 }
103             }
104             break;
105         default:
106             throw new IllegalStateException("client does not support the protocol " ~ to!string(
107                     abstractConnection.getConnectionType()));
108         }
109 
110         return resultStatus;
111     }
112 }