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.common.Utils; |
29 import jdk.internal.net.http.websocket.Frame.Opcode; |
29 import jdk.internal.net.http.websocket.Frame.Opcode; |
30 |
30 |
31 import java.net.http.WebSocket.MessagePart; |
|
32 import java.nio.ByteBuffer; |
31 import java.nio.ByteBuffer; |
33 import java.nio.CharBuffer; |
32 import java.nio.CharBuffer; |
34 import java.nio.charset.CharacterCodingException; |
33 import java.nio.charset.CharacterCodingException; |
35 |
34 |
36 import static java.lang.String.format; |
35 import static java.lang.String.format; |
57 |
56 |
58 private final MessageStreamConsumer output; |
57 private final MessageStreamConsumer output; |
59 private final UTF8AccumulatingDecoder decoder = new UTF8AccumulatingDecoder(); |
58 private final UTF8AccumulatingDecoder decoder = new UTF8AccumulatingDecoder(); |
60 private boolean fin; |
59 private boolean fin; |
61 private Opcode opcode, originatingOpcode; |
60 private Opcode opcode, originatingOpcode; |
62 private MessagePart part = MessagePart.WHOLE; |
|
63 private long payloadLen; |
61 private long payloadLen; |
64 private long unconsumedPayloadLen; |
62 private long unconsumedPayloadLen; |
65 private ByteBuffer binaryData; |
63 private ByteBuffer binaryData; |
66 |
64 |
67 MessageDecoder(MessageStreamConsumer output) { |
65 MessageDecoder(MessageStreamConsumer output) { |
169 |
167 |
170 @Override |
168 @Override |
171 public void payloadData(ByteBuffer data) { |
169 public void payloadData(ByteBuffer data) { |
172 debug.log(Level.DEBUG, "payload %s", data); |
170 debug.log(Level.DEBUG, "payload %s", data); |
173 unconsumedPayloadLen -= data.remaining(); |
171 unconsumedPayloadLen -= data.remaining(); |
174 boolean isLast = unconsumedPayloadLen == 0; |
172 boolean lastPayloadChunk = unconsumedPayloadLen == 0; |
175 if (opcode.isControl()) { |
173 if (opcode.isControl()) { |
176 if (binaryData != null) { // An intermediate or the last chunk |
174 if (binaryData != null) { // An intermediate or the last chunk |
177 binaryData.put(data); |
175 binaryData.put(data); |
178 } else if (!isLast) { // The first chunk |
176 } else if (!lastPayloadChunk) { // The first chunk |
179 int remaining = data.remaining(); |
177 int remaining = data.remaining(); |
180 // It shouldn't be 125, otherwise the next chunk will be of size |
178 // It shouldn't be 125, otherwise the next chunk will be of size |
181 // 0, which is not what Reader promises to deliver (eager |
179 // 0, which is not what Reader promises to deliver (eager |
182 // reading) |
180 // reading) |
183 assert remaining < Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH |
181 assert remaining < Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH |
186 Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH).put(data); |
184 Frame.MAX_CONTROL_FRAME_PAYLOAD_LENGTH).put(data); |
187 } else { // The only chunk |
185 } else { // The only chunk |
188 binaryData = ByteBuffer.allocate(data.remaining()).put(data); |
186 binaryData = ByteBuffer.allocate(data.remaining()).put(data); |
189 } |
187 } |
190 } else { |
188 } else { |
191 part = determinePart(isLast); |
189 boolean last = fin && lastPayloadChunk; |
192 boolean text = opcode == Opcode.TEXT || originatingOpcode == Opcode.TEXT; |
190 boolean text = opcode == Opcode.TEXT || originatingOpcode == Opcode.TEXT; |
193 if (!text) { |
191 if (!text) { |
194 output.onBinary(data.slice(), part); |
192 output.onBinary(data.slice(), last); |
195 data.position(data.limit()); // Consume |
193 data.position(data.limit()); // Consume |
196 } else { |
194 } else { |
197 boolean binaryNonEmpty = data.hasRemaining(); |
195 boolean binaryNonEmpty = data.hasRemaining(); |
198 CharBuffer textData; |
196 CharBuffer textData; |
199 try { |
197 try { |
200 boolean eof = part == MessagePart.WHOLE |
198 textData = decoder.decode(data, last); |
201 || part == MessagePart.LAST; |
|
202 textData = decoder.decode(data, eof); |
|
203 } catch (CharacterCodingException e) { |
199 } catch (CharacterCodingException e) { |
204 throw new FailWebSocketException( |
200 throw new FailWebSocketException( |
205 "Invalid UTF-8 in frame " + opcode, |
201 "Invalid UTF-8 in frame " + opcode, |
206 StatusCodes.NOT_CONSISTENT).initCause(e); |
202 StatusCodes.NOT_CONSISTENT).initCause(e); |
207 } |
203 } |
208 if (!(binaryNonEmpty && !textData.hasRemaining())) { |
204 if (!(binaryNonEmpty && !textData.hasRemaining())) { |
209 // If there's a binary data, that result in no text, then we |
205 // If there's a binary data, that result in no text, then we |
210 // don't deliver anything |
206 // don't deliver anything, otherwise: |
211 output.onText(textData, part); |
207 output.onText(textData, last); |
212 } |
208 } |
213 } |
209 } |
214 } |
210 } |
215 } |
211 } |
216 |
212 |