1 module hunt.http.server.Http2ServerRequestHandler;
2 
3 import hunt.http.server.HttpServerResponse;
4 import hunt.http.server.Http2ServerConnection;
5 import hunt.http.server.ServerHttpHandler;
6 import hunt.http.server.ServerSessionListener;
7 
8 import hunt.http.codec.http.frame;
9 import hunt.http.codec.http.model;
10 import hunt.http.codec.http.stream.AbstractHttp2OutputStream;
11 import hunt.http.codec.http.stream.Session;
12 import hunt.http.codec.http.stream.Stream;
13 
14 import hunt.http.codec.http.stream.DataFrameHandler;
15 
16 import hunt.http.HttpFields;
17 import hunt.http.HttpHeader;
18 import hunt.http.HttpMetaData;
19 import hunt.http.HttpMethod;
20 import hunt.http.HttpRequest;
21 import hunt.http.HttpResponse;
22 import hunt.http.HttpStatus;
23 import hunt.http.HttpVersion;
24 import hunt.http.Version;
25 
26 import hunt.Exceptions;
27 import hunt.util.Common;
28 import hunt.text.Common;
29 
30 import hunt.logging;
31 import std.conv;
32 import std.string;
33 
34 alias StreamListener = hunt.http.codec.http.stream.Stream.Stream.Listener;
35 
36 /**
37 */
38 class Http2ServerRequestHandler : ServerSessionListener.Adapter {
39 
40     private ServerHttpHandler serverHttpHandler;
41     Http2ServerConnection connection;
42 
43     this(ServerHttpHandler serverHttpHandler) {
44         this.serverHttpHandler = serverHttpHandler;
45     }
46 
47     override
48     void onClose(Session session, GoAwayFrame frame) {
49         warningf("Server received the GoAwayFrame -> %s", frame.toString());
50         connection.close();
51     }
52 
53     override
54     void onFailure(Session session, Exception failure) {
55         errorf("Server failure: " ~ session.toString(), failure);
56         // Optional.ofNullable(connection).ifPresent(IO::close);
57         if(connection !is null)
58             connection.close();
59     }
60 
61     override
62     void onReset(Session session, ResetFrame frame) {
63         warningf("Server received ResetFrame %s", frame.toString());
64         // Optional.ofNullable(connection).ifPresent(IO::close);
65 
66         if(connection !is null)
67             connection.close();
68     }
69 
70     override
71     StreamListener onNewStream(Stream stream, HeadersFrame headersFrame) {
72         if (!headersFrame.getMetaData().isRequest()) {
73             throw new IllegalArgumentException("the stream " ~ stream.getId().to!string() ~ " received meta data that is not request type");
74         }
75 
76         version(HUNT_DEBUG) {
77             tracef("Server received stream: %s, %s", stream.getId(), headersFrame.toString());
78         }
79 
80         HttpRequest request = cast(HttpRequest) headersFrame.getMetaData();
81         HttpResponse response = new HttpServerResponse();
82         ServerHttp2OutputStream output = new ServerHttp2OutputStream(response, stream);
83 
84         string expectedValue = request.getFields().get(HttpHeader.EXPECT);
85         if ("100-continue".equalsIgnoreCase(expectedValue)) {
86             bool skipNext = serverHttpHandler.accept100Continue(request, response, output, connection);
87             if (!skipNext) {
88                 HttpResponse continue100 = new HttpResponse(HttpVersion.HTTP_1_1,
89                         HttpStatus.CONTINUE_100, HttpStatus.Code.CONTINUE.getMessage(),
90                         new HttpFields(), -1);
91                 output.writeFrame(new HeadersFrame(stream.getId(), continue100, null, false));
92             }
93         } else {
94             serverHttpHandler.headerComplete(request, response, output, connection);
95             if (headersFrame.isEndStream()) {
96                 serverHttpHandler.messageComplete(request, response, output, connection);
97             }
98         }
99 
100         
101 
102         return new class StreamListener.Adapter {
103             override
104             void onHeaders(Stream stream, HeadersFrame trailerFrame) {
105                 version(HUNT_DEBUG) {
106                     tracef("Server received trailer frame: %s, %s", stream.toString(), trailerFrame);
107                 }
108 
109                 if (trailerFrame.isEndStream()) {
110                     request.setTrailerSupplier(() => trailerFrame.getMetaData().getFields());
111                     serverHttpHandler.contentComplete(request, response, output, connection);
112                     serverHttpHandler.messageComplete(request, response, output, connection);
113                 } else {
114                     throw new IllegalArgumentException("the stream " ~ stream.getId().to!string() ~ " received illegal meta data");
115                 }
116             }
117 
118             override
119             void onData(Stream stream, DataFrame dataFrame, Callback callback) {
120                 DataFrameHandler.handleDataFrame(dataFrame, callback, request, response, output, connection, serverHttpHandler);
121             }
122 
123             override
124             void onReset(Stream stream, ResetFrame resetFrame) {
125                 int errorCode = resetFrame.getError();
126                 string reason; 
127                 int status = HttpStatus.INTERNAL_SERVER_ERROR_500;
128                 if (isValidErrorCode(errorCode)) {
129                     switch (cast(ErrorCode)errorCode) {
130                         case ErrorCode.PROTOCOL_ERROR:
131                             status = HttpStatus.BAD_REQUEST_400;
132                             break;
133                         default:
134                             status = HttpStatus.INTERNAL_SERVER_ERROR_500;
135                             break;
136                     }
137                     reason =  (cast(ErrorCode)errorCode).to!string().toLower();
138                 }
139                 else
140                     reason =  "error=" ~ resetFrame.getError().to!string();
141 
142                 serverHttpHandler.badMessage(status, reason, request, response, output, connection);
143             }
144         };
145     }
146 
147     static class ServerHttp2OutputStream : AbstractHttp2OutputStream {
148 
149         private Stream stream;
150 
151         this(HttpMetaData info, Stream stream) {
152             super(info, false);
153             this.stream = stream;
154             info.getFields().put(HttpHeader.X_POWERED_BY, X_POWERED_BY_VALUE);
155             info.getFields().put(HttpHeader.SERVER, SERVER_VALUE);
156         }
157 
158         override
159         protected Stream getStream() {
160             return stream;
161         }
162     }
163 
164 }