1 module hunt.http.codec.websocket.frame.ControlFrame;
2 
3 import hunt.http.codec.websocket.frame.AbstractWebSocketFrame;
4 import hunt.http.Exceptions;
5 
6 import hunt.io.BufferUtils;
7 import hunt.io.ByteBuffer;
8 
9 import std.conv;
10 
11 abstract class ControlFrame : AbstractWebSocketFrame {
12     /**
13      * Maximum size of Control frame, per RFC 6455
14      */
15     enum int MAX_CONTROL_PAYLOAD = 125;
16 
17     this(byte opcode) {
18         super(opcode);
19     }
20 
21     override void assertValid() {
22         if (isControlFrame()) {
23             if (getPayloadLength() > ControlFrame.MAX_CONTROL_PAYLOAD) {
24                 throw new ProtocolException("Desired payload length [" ~ getPayloadLength().to!string() ~ 
25                     "] exceeds maximum control payload length [" ~
26                          MAX_CONTROL_PAYLOAD.to!string() ~ "]");
27             }
28 
29             if ((finRsvOp & 0x80) == 0) {
30                 throw new ProtocolException("Cannot have FIN==false on Control frames");
31             }
32 
33             if ((finRsvOp & 0x40) != 0) {
34                 throw new ProtocolException("Cannot have RSV1==true on Control frames");
35             }
36 
37             if ((finRsvOp & 0x20) != 0) {
38                 throw new ProtocolException("Cannot have RSV2==true on Control frames");
39             }
40 
41             if ((finRsvOp & 0x10) != 0) {
42                 throw new ProtocolException("Cannot have RSV3==true on Control frames");
43             }
44         }
45     }
46 
47     override bool opEquals(Object obj) {   
48         if (obj is null) 
49             return false;
50 
51         if (this is obj) 
52             return true;
53 
54         ControlFrame other = cast(ControlFrame) obj;
55         if(other is null)   return false;
56 
57         if (data is null) {
58             if (other.data !is null) {
59                 return false;
60             }
61         } else if (!data.opEquals(other.data)) {
62             return false;
63         }
64         return finRsvOp == other.finRsvOp && mask == other.mask && masked == other.masked;
65     }
66 
67     override bool isControlFrame() {
68         return true;
69     }
70 
71     override
72     bool isDataFrame() {
73         return false;
74     }
75 
76     override
77     AbstractWebSocketFrame setPayload(ByteBuffer buf) {
78         if (buf !is null && buf.remaining() > MAX_CONTROL_PAYLOAD) {
79             throw new ProtocolException("Control Payloads can not exceed " ~ MAX_CONTROL_PAYLOAD ~ " bytes in length.");
80         }
81         return super.setPayload(buf);
82     }
83 
84     override
85     ByteBuffer getPayload() {
86         if (super.getPayload() is null) {
87             return BufferUtils.EMPTY_BUFFER;
88         }
89         return super.getPayload();
90     }
91 }