1 module hunt.http.codec.http.decode.ServerParser;
2
3
4 import hunt.http.codec.http.decode.PrefaceParser;
5 import hunt.http.codec.http.decode.Parser;
6 import hunt.http.codec.http.frame.ErrorCode;
7 import hunt.http.codec.http.frame.Flags;
8 import hunt.http.codec.http.frame.FrameType;
9
10 import hunt.io.ByteBuffer;
11 import hunt.io.BufferUtils;
12
13 import hunt.logging;
14 import hunt.Exceptions;
15
16
17 /**
18 */
19 class ServerParser :Parser {
20
21 private Listener listener;
22 private PrefaceParser prefaceParser;
23 private State state = State.PREFACE;
24 private bool _notifyPreface = true;
25
26 this(Listener listener, int maxDynamicTableSize, int maxHeaderSize) {
27 super(listener, maxDynamicTableSize, maxHeaderSize);
28 this.listener = listener;
29 this.prefaceParser = new PrefaceParser(listener);
30 }
31
32 /**
33 * <p>
34 * A direct upgrade is an unofficial upgrade from HTTP/1.1 to HTTP/2.0.
35 * </p>
36 * <p>
37 * A direct upgrade is initiated when
38 * HTTP connection sees a request with these
39 * bytes:
40 * </p>
41 *
42 * <pre>
43 * PRI * HTTP/2.0\r\n
44 * \r\n
45 * </pre>
46 * <p>
47 * This request is part of the HTTP/2.0 preface, indicating that a HTTP/2.0
48 * client is attempting a h2c direct connection.
49 * </p>
50 * <p>
51 * This is not a standard HTTP/1.1 Upgrade path.
52 * </p>
53 */
54 void directUpgrade() {
55 if (state != State.PREFACE)
56 throw new IllegalStateException("");
57 prefaceParser.directUpgrade();
58 }
59
60 /**
61 * <p>
62 * The standard HTTP/1.1 upgrade path.
63 * </p>
64 */
65 void standardUpgrade() {
66 if (state != State.PREFACE)
67 throw new IllegalStateException("");
68 _notifyPreface = false;
69 }
70
71 override
72 void parse(ByteBuffer buffer) {
73 version(HuntDebutMode)
74 tracef("parsing buffer: %s", buffer.toString());
75 try {
76 while (true) {
77 switch (state) {
78 case State.PREFACE: {
79 if (prefaceParser.parse(buffer)) {
80 if (_notifyPreface) {
81 onPreface();
82 }
83 state = State.SETTINGS;
84 break;
85 } else {
86 return;
87 }
88 }
89 case State.SETTINGS: {
90 if (parseHeader(buffer)) {
91 if (getFrameType() != FrameType.SETTINGS || hasFlag(Flags.ACK)) {
92 buffer.clear();
93 notifyConnectionFailure(cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_preface");
94 return;
95 }
96 if (parseBody(buffer)) {
97 state = State.FRAMES;
98 break;
99 } else {
100 return;
101 }
102 } else {
103 return;
104 }
105 }
106 case State.FRAMES: {
107 // Stay forever in the FRAMES state.
108 super.parse(buffer);
109 return;
110 }
111 default: {
112 throw new IllegalStateException("");
113 }
114 }
115 }
116 } catch (Exception x) {
117 errorf("server parser error", x);
118 BufferUtils.clear(buffer);
119 notifyConnectionFailure(cast(int)ErrorCode.PROTOCOL_ERROR, "parser_error");
120 }
121 }
122
123 protected void onPreface() {
124 notifyPreface();
125 }
126
127 private void notifyPreface() {
128 try {
129 listener.onPreface();
130 } catch (Exception x) {
131 errorf("Failure while notifying listener %s", x.message);
132 }
133 }
134
135 interface Listener : Parser.Listener {
136 void onPreface();
137
138 class Adapter : Parser.Listener.Adapter, Listener {
139 override
140 void onPreface() {
141 }
142 }
143 }
144
145 private enum State {
146 PREFACE, SETTINGS, FRAMES
147 }
148 }