1 module hunt.http.codec.websocket.frame.WebSocketFrame; 2 3 import hunt.http.codec.websocket.frame.Frame; 4 import hunt.http.codec.websocket.model.common; 5 6 import hunt.container; 7 import hunt.string; 8 9 /** 10 * A Base Frame as seen in <a href="https://tools.ietf.org/html/rfc6455#section-5.2">RFC 6455. Sec 5.2</a> 11 * <p> 12 * <pre> 13 * 0 1 2 3 14 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 15 * +-+-+-+-+-------+-+-------------+-------------------------------+ 16 * |F|R|R|R| opcode|M| Payload len | Extended payload length | 17 * |I|S|S|S| (4) |A| (7) | (16/64) | 18 * |N|V|V|V| |S| | (if payload len==126/127) | 19 * | |1|2|3| |K| | | 20 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + 21 * | Extended payload length continued, if payload len == 127 | 22 * + - - - - - - - - - - - - - - - +-------------------------------+ 23 * | |Masking-key, if MASK set to 1 | 24 * +-------------------------------+-------------------------------+ 25 * | Masking-key (continued) | Payload Data | 26 * +-------------------------------- - - - - - - - - - - - - - - - + 27 * : Payload Data continued ... : 28 * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 29 * | Payload Data continued ... | 30 * +---------------------------------------------------------------+ 31 * </pre> 32 */ 33 abstract class WebSocketFrame : Frame { 34 35 /** 36 * Combined FIN + RSV1 + RSV2 + RSV3 + OpCode byte. 37 * <p> 38 * <pre> 39 * 1000_0000 (0x80) = fin 40 * 0100_0000 (0x40) = rsv1 41 * 0010_0000 (0x20) = rsv2 42 * 0001_0000 (0x10) = rsv3 43 * 0000_1111 (0x0F) = opcode 44 * </pre> 45 */ 46 protected byte finRsvOp; 47 protected bool masked = false; 48 49 protected byte[] mask; 50 /** 51 * The payload data. 52 * <p> 53 * It is assumed to always be in FLUSH mode (ready to read) in this object. 54 */ 55 protected ByteBuffer data; 56 57 /** 58 * Construct form opcode 59 * 60 * @param opcode the opcode the frame is based on 61 */ 62 protected this(byte opcode) { 63 reset(); 64 setOpCode(opcode); 65 } 66 67 abstract void assertValid(); 68 69 void copyHeaders(Frame frame) { 70 finRsvOp = 0x00; 71 finRsvOp |= frame.isFin() ? 0x80 : 0x00; 72 finRsvOp |= frame.isRsv1() ? 0x40 : 0x00; 73 finRsvOp |= frame.isRsv2() ? 0x20 : 0x00; 74 finRsvOp |= frame.isRsv3() ? 0x10 : 0x00; 75 finRsvOp |= frame.getOpCode() & 0x0F; 76 77 masked = frame.isMasked(); 78 if (masked) { 79 mask = frame.getMask(); 80 } else { 81 mask = null; 82 } 83 } 84 85 protected void copyHeaders(WebSocketFrame copy) { 86 finRsvOp = copy.finRsvOp; 87 masked = copy.masked; 88 mask = null; 89 if (copy.mask !is null) 90 mask = copy.mask.dup; 91 } 92 93 bool equals(Object obj) { return opEquals(obj); } 94 95 override bool opEquals(Object obj) { 96 if (this is obj) { 97 return true; 98 } 99 if (obj is null) { 100 return false; 101 } 102 103 WebSocketFrame other = cast(WebSocketFrame) obj; 104 if(other is null) return false; 105 106 if (data is null) { 107 if (other.data !is null) { 108 return false; 109 } 110 } else if (!data.opEquals(other.data)) { 111 return false; 112 } 113 if (finRsvOp != other.finRsvOp) { 114 return false; 115 } 116 if (mask != other.mask) { 117 return false; 118 } 119 if (masked != other.masked) { 120 return false; 121 } 122 return true; 123 } 124 125 override 126 byte[] getMask() { 127 return mask; 128 } 129 130 override 131 final byte getOpCode() { 132 return cast(byte) (finRsvOp & 0x0F); 133 } 134 135 /** 136 * Get the payload ByteBuffer. possible null. 137 */ 138 override 139 ByteBuffer getPayload() { 140 return data; 141 } 142 143 string getPayloadAsUTF8() { 144 return BufferUtils.toString(getPayload()); 145 } 146 147 override 148 int getPayloadLength() { 149 if (data is null) { 150 return 0; 151 } 152 return data.remaining(); 153 } 154 155 override 156 Type getType() { 157 return FrameTypeHelper.from(getOpCode()); 158 } 159 160 size_t hashCode() { return toHash(); } 161 162 override size_t toHash() @trusted nothrow { 163 int prime = 31; 164 size_t result = 1; 165 result = (prime * result) + ((data is null) ? 0 : data.toHash()); 166 result = (prime * result) + finRsvOp; 167 result = (prime * result) + hashOf(mask); 168 return result; 169 } 170 171 override 172 bool hasPayload() { 173 return ((data !is null) && data.hasRemaining()); 174 } 175 176 abstract bool isControlFrame(); 177 178 abstract bool isDataFrame(); 179 180 override 181 bool isFin() { 182 return cast(byte) (finRsvOp & 0x80) != 0; 183 } 184 185 override 186 bool isMasked() { 187 return masked; 188 } 189 190 override 191 bool isRsv1() { 192 return cast(byte) (finRsvOp & 0x40) != 0; 193 } 194 195 override 196 bool isRsv2() { 197 return cast(byte) (finRsvOp & 0x20) != 0; 198 } 199 200 override 201 bool isRsv3() { 202 return cast(byte) (finRsvOp & 0x10) != 0; 203 } 204 205 void reset() { 206 finRsvOp = cast(byte) 0x80; // FIN (!RSV, opcode 0) 207 masked = false; 208 data = null; 209 mask = null; 210 } 211 212 WebSocketFrame setFin(bool fin) { 213 // set bit 1 214 this.finRsvOp = cast(byte) ((finRsvOp & 0x7F) | (fin ? 0x80 : 0x00)); 215 return this; 216 } 217 218 Frame setMask(byte[] maskingKey) { 219 this.mask = maskingKey; 220 this.masked = (mask !is null); 221 return this; 222 } 223 224 Frame setMasked(bool mask) { 225 this.masked = mask; 226 return this; 227 } 228 229 protected WebSocketFrame setOpCode(byte op) { 230 this.finRsvOp = cast(byte) ((finRsvOp & 0xF0) | (op & 0x0F)); 231 return this; 232 } 233 234 /** 235 * Set the data payload. 236 * <p> 237 * The provided buffer will be used as is, no copying of bytes performed. 238 * <p> 239 * The provided buffer should be flipped and ready to READ from. 240 * 241 * @param buf the bytebuffer to set 242 * @return the frame itself 243 */ 244 WebSocketFrame setPayload(ByteBuffer buf) { 245 data = buf; 246 return this; 247 } 248 249 WebSocketFrame setRsv1(bool rsv1) { 250 // set bit 2 251 this.finRsvOp = cast(byte) ((finRsvOp & 0xBF) | (rsv1 ? 0x40 : 0x00)); 252 return this; 253 } 254 255 WebSocketFrame setRsv2(bool rsv2) { 256 // set bit 3 257 this.finRsvOp = cast(byte) ((finRsvOp & 0xDF) | (rsv2 ? 0x20 : 0x00)); 258 return this; 259 } 260 261 WebSocketFrame setRsv3(bool rsv3) { 262 // set bit 4 263 this.finRsvOp = cast(byte) ((finRsvOp & 0xEF) | (rsv3 ? 0x10 : 0x00)); 264 return this; 265 } 266 267 override 268 string toString() { 269 StringBuilder b = new StringBuilder(); 270 b.append(OpCode.name(cast(byte) (finRsvOp & 0x0F))); 271 b.append('['); 272 b.append("len=").append(getPayloadLength()); 273 b.append(",fin=").append((finRsvOp & 0x80) != 0); 274 b.append(",rsv="); 275 b.append(((finRsvOp & 0x40) != 0) ? '1' : '.'); 276 b.append(((finRsvOp & 0x20) != 0) ? '1' : '.'); 277 b.append(((finRsvOp & 0x10) != 0) ? '1' : '.'); 278 b.append(",masked=").append(masked); 279 b.append(']'); 280 return b.toString(); 281 } 282 }