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 }