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 }