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 }