1 module hunt.http.codec.http.decode.SettingsBodyParser; 2 3 4 import hunt.http.codec.http.decode.BodyParser; 5 import hunt.http.codec.http.decode.HeaderParser; 6 import hunt.http.codec.http.decode.Parser; 7 8 import hunt.http.codec.http.frame.ErrorCode; 9 import hunt.http.codec.http.frame.Flags; 10 import hunt.http.codec.http.frame.SettingsFrame; 11 12 import hunt.io.ByteBuffer; 13 import hunt.collection.HashMap; 14 import hunt.collection.Map; 15 16 import hunt.Exceptions; 17 import hunt.logging; 18 import std.format; 19 20 class SettingsBodyParser :BodyParser { 21 // 22 private State state = State.PREPARE; 23 private int cursor; 24 private int length; 25 private int settingId; 26 private int settingValue; 27 private Map!(int, int) settings; 28 29 this(HeaderParser headerParser, Parser.Listener listener) { 30 super(headerParser, listener); 31 } 32 33 protected void reset() { 34 state = State.PREPARE; 35 cursor = 0; 36 length = 0; 37 settingId = 0; 38 settingValue = 0; 39 settings = null; 40 } 41 42 override 43 protected void emptyBody(ByteBuffer buffer) { 44 onSettings(new HashMap!(int, int)()); 45 } 46 47 override 48 bool parse(ByteBuffer buffer) { 49 while (buffer.hasRemaining()) { 50 switch (state) { 51 case State.PREPARE: { 52 // SPEC: wrong streamId is treated as connection error. 53 if (getStreamId() != 0) 54 return connectionFailure(buffer, cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_settings_frame"); 55 length = getBodyLength(); 56 settings = new HashMap!(int, int)(); 57 state = State.SETTING_ID; 58 break; 59 } 60 case State.SETTING_ID: { 61 if (buffer.remaining() >= 2) { 62 settingId = buffer.get!short() & 0xFF_FF; 63 state = State.SETTING_VALUE; 64 length -= 2; 65 if (length <= 0) 66 return connectionFailure(buffer, cast(int)ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); 67 } else { 68 cursor = 2; 69 settingId = 0; 70 state = State.SETTING_ID_BYTES; 71 } 72 break; 73 } 74 case State.SETTING_ID_BYTES: { 75 int currByte = buffer.get() & 0xFF; 76 --cursor; 77 settingId += currByte << (8 * cursor); 78 --length; 79 if (length <= 0) 80 return connectionFailure(buffer, cast(int)ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); 81 if (cursor == 0) { 82 state = State.SETTING_VALUE; 83 } 84 break; 85 } 86 case State.SETTING_VALUE: { 87 if (buffer.remaining() >= 4) { 88 settingValue = buffer.get!int(); 89 version(HUNT_HTTP_DEBUG) 90 tracef(format("setting %d=%d", settingId, settingValue)); 91 settings.put(settingId, settingValue); 92 state = State.SETTING_ID; 93 length -= 4; 94 if (length == 0) 95 return onSettings(settings); 96 } else { 97 cursor = 4; 98 settingValue = 0; 99 state = State.SETTING_VALUE_BYTES; 100 } 101 break; 102 } 103 case State.SETTING_VALUE_BYTES: { 104 int currByte = buffer.get() & 0xFF; 105 --cursor; 106 settingValue += currByte << (8 * cursor); 107 --length; 108 if (cursor > 0 && length <= 0) 109 return connectionFailure(buffer, cast(int)ErrorCode.FRAME_SIZE_ERROR, "invalid_settings_frame"); 110 if (cursor == 0) { 111 version(HUNT_DEBUG) 112 tracef(format("setting %d=%d", settingId, settingValue)); 113 settings.put(settingId, settingValue); 114 state = State.SETTING_ID; 115 if (length == 0) 116 return onSettings(settings); 117 } 118 break; 119 } 120 default: { 121 throw new IllegalStateException(""); 122 } 123 } 124 } 125 return false; 126 } 127 128 protected bool onSettings(Map!(int, int) settings) { 129 SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK)); 130 reset(); 131 notifySettings(frame); 132 return true; 133 } 134 135 static SettingsFrame parseBody(ByteBuffer buffer) { 136 int bodyLength = buffer.remaining(); 137 // AtomicReference!(SettingsFrame) frameRef = new AtomicReference!(SettingsFrame)(); 138 // FIXME: Needing refactor or cleanup -@zxp at 6/28/2018, 11:31:02 AM 139 // 140 SettingsFrame frameRef; 141 142 class SettingsBodyParserEx : SettingsBodyParser 143 { 144 this() { super(null, null); } 145 146 override 147 protected int getStreamId() { 148 return 0; 149 } 150 151 override 152 protected int getBodyLength() { 153 return bodyLength; 154 } 155 156 override 157 protected bool onSettings(Map!(int, int) settings) { 158 // frameRef.set(new SettingsFrame(settings, false)); 159 frameRef = new SettingsFrame(settings, false); 160 return true; 161 } 162 163 override 164 protected bool connectionFailure(ByteBuffer buffer, int error, string reason) { 165 frameRef = null; 166 return false; 167 } 168 } 169 170 SettingsBodyParser parser = new SettingsBodyParserEx(); 171 if (bodyLength == 0) 172 parser.emptyBody(buffer); 173 else 174 parser.parse(buffer); 175 return frameRef; 176 } 177 178 private enum State { 179 PREPARE, SETTING_ID, SETTING_ID_BYTES, SETTING_VALUE, SETTING_VALUE_BYTES 180 } 181 }