23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package jdk.internal.net.http.websocket; |
26 package jdk.internal.net.http.websocket; |
27 |
27 |
|
28 import jdk.internal.net.http.common.Utils; |
28 import jdk.internal.net.http.websocket.Frame.Opcode; |
29 import jdk.internal.net.http.websocket.Frame.Opcode; |
29 |
30 |
30 import java.net.http.WebSocket.MessagePart; |
31 import java.net.http.WebSocket.MessagePart; |
31 import java.nio.ByteBuffer; |
32 import java.nio.ByteBuffer; |
32 import java.nio.CharBuffer; |
33 import java.nio.CharBuffer; |
33 import java.nio.charset.CharacterCodingException; |
34 import java.nio.charset.CharacterCodingException; |
34 |
35 |
35 import static java.lang.String.format; |
36 import static java.lang.String.format; |
|
37 import java.lang.System.Logger.Level; |
36 import static java.nio.charset.StandardCharsets.UTF_8; |
38 import static java.nio.charset.StandardCharsets.UTF_8; |
37 import static java.util.Objects.requireNonNull; |
39 import static java.util.Objects.requireNonNull; |
38 import static jdk.internal.net.http.common.Utils.dump; |
40 import static jdk.internal.net.http.common.Utils.dump; |
39 import static jdk.internal.net.http.websocket.StatusCodes.NO_STATUS_CODE; |
41 import static jdk.internal.net.http.websocket.StatusCodes.NO_STATUS_CODE; |
40 import static jdk.internal.net.http.websocket.StatusCodes.isLegalToReceiveFromServer; |
42 import static jdk.internal.net.http.websocket.StatusCodes.isLegalToReceiveFromServer; |
47 * form a message. |
49 * form a message. |
48 */ |
50 */ |
49 /* Exposed for testing purposes */ |
51 /* Exposed for testing purposes */ |
50 class MessageDecoder implements Frame.Consumer { |
52 class MessageDecoder implements Frame.Consumer { |
51 |
53 |
52 private final static boolean DEBUG = false; |
54 private static final boolean DEBUG = Utils.DEBUG_WS; |
|
55 private static final System.Logger debug = |
|
56 Utils.getWebSocketLogger("[Input]"::toString, DEBUG); |
|
57 |
53 private final MessageStreamConsumer output; |
58 private final MessageStreamConsumer output; |
54 private final UTF8AccumulatingDecoder decoder = new UTF8AccumulatingDecoder(); |
59 private final UTF8AccumulatingDecoder decoder = new UTF8AccumulatingDecoder(); |
55 private boolean fin; |
60 private boolean fin; |
56 private Opcode opcode, originatingOpcode; |
61 private Opcode opcode, originatingOpcode; |
57 private MessagePart part = MessagePart.WHOLE; |
62 private MessagePart part = MessagePart.WHOLE; |
68 return output; |
73 return output; |
69 } |
74 } |
70 |
75 |
71 @Override |
76 @Override |
72 public void fin(boolean value) { |
77 public void fin(boolean value) { |
73 if (DEBUG) { |
78 debug.log(Level.DEBUG, "fin %s", value); |
74 System.out.printf("[Input] fin %s%n", value); |
|
75 } |
|
76 fin = value; |
79 fin = value; |
77 } |
80 } |
78 |
81 |
79 @Override |
82 @Override |
80 public void rsv1(boolean value) { |
83 public void rsv1(boolean value) { |
81 if (DEBUG) { |
84 debug.log(Level.DEBUG, "rsv1 %s", value); |
82 System.out.printf("[Input] rsv1 %s%n", value); |
|
83 } |
|
84 if (value) { |
85 if (value) { |
85 throw new FailWebSocketException("Unexpected rsv1 bit"); |
86 throw new FailWebSocketException("Unexpected rsv1 bit"); |
86 } |
87 } |
87 } |
88 } |
88 |
89 |
89 @Override |
90 @Override |
90 public void rsv2(boolean value) { |
91 public void rsv2(boolean value) { |
91 if (DEBUG) { |
92 debug.log(Level.DEBUG, "rsv2 %s", value); |
92 System.out.printf("[Input] rsv2 %s%n", value); |
|
93 } |
|
94 if (value) { |
93 if (value) { |
95 throw new FailWebSocketException("Unexpected rsv2 bit"); |
94 throw new FailWebSocketException("Unexpected rsv2 bit"); |
96 } |
95 } |
97 } |
96 } |
98 |
97 |
99 @Override |
98 @Override |
100 public void rsv3(boolean value) { |
99 public void rsv3(boolean value) { |
101 if (DEBUG) { |
100 debug.log(Level.DEBUG, "rsv3 %s", value); |
102 System.out.printf("[Input] rsv3 %s%n", value); |
|
103 } |
|
104 if (value) { |
101 if (value) { |
105 throw new FailWebSocketException("Unexpected rsv3 bit"); |
102 throw new FailWebSocketException("Unexpected rsv3 bit"); |
106 } |
103 } |
107 } |
104 } |
108 |
105 |
109 @Override |
106 @Override |
110 public void opcode(Opcode v) { |
107 public void opcode(Opcode v) { |
111 if (DEBUG) { |
108 debug.log(Level.DEBUG, "opcode %s", v); |
112 System.out.printf("[Input] opcode %s%n", v); |
|
113 } |
|
114 if (v == Opcode.PING || v == Opcode.PONG || v == Opcode.CLOSE) { |
109 if (v == Opcode.PING || v == Opcode.PONG || v == Opcode.CLOSE) { |
115 if (!fin) { |
110 if (!fin) { |
116 throw new FailWebSocketException("Fragmented control frame " + v); |
111 throw new FailWebSocketException("Fragmented control frame " + v); |
117 } |
112 } |
118 opcode = v; |
113 opcode = v; |
136 } |
131 } |
137 } |
132 } |
138 |
133 |
139 @Override |
134 @Override |
140 public void mask(boolean value) { |
135 public void mask(boolean value) { |
141 if (DEBUG) { |
136 debug.log(Level.DEBUG, "mask %s", value); |
142 System.out.printf("[Input] mask %s%n", value); |
|
143 } |
|
144 if (value) { |
137 if (value) { |
145 throw new FailWebSocketException("Masked frame received"); |
138 throw new FailWebSocketException("Masked frame received"); |
146 } |
139 } |
147 } |
140 } |
148 |
141 |
149 @Override |
142 @Override |
150 public void payloadLen(long value) { |
143 public void payloadLen(long value) { |
151 if (DEBUG) { |
144 debug.log(Level.DEBUG, "payloadLen %s", value); |
152 System.out.printf("[Input] payloadLen %s%n", value); |
|
153 } |
|
154 if (opcode.isControl()) { |
145 if (opcode.isControl()) { |
155 if (value > Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH) { |
146 if (value > Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH) { |
156 throw new FailWebSocketException( |
147 throw new FailWebSocketException( |
157 format("%s's payload length %s", opcode, value)); |
148 format("%s's payload length %s", opcode, value)); |
158 } |
149 } |
176 throw new InternalError(); |
167 throw new InternalError(); |
177 } |
168 } |
178 |
169 |
179 @Override |
170 @Override |
180 public void payloadData(ByteBuffer data) { |
171 public void payloadData(ByteBuffer data) { |
181 if (DEBUG) { |
172 debug.log(Level.DEBUG, "payload %s", data); |
182 System.out.printf("[Input] payload %s%n", data); |
|
183 } |
|
184 unconsumedPayloadLen -= data.remaining(); |
173 unconsumedPayloadLen -= data.remaining(); |
185 boolean isLast = unconsumedPayloadLen == 0; |
174 boolean isLast = unconsumedPayloadLen == 0; |
186 if (opcode.isControl()) { |
175 if (opcode.isControl()) { |
187 if (binaryData != null) { // An intermediate or the last chunk |
176 if (binaryData != null) { // An intermediate or the last chunk |
188 binaryData.put(data); |
177 binaryData.put(data); |