1
1
/*
2
- * Copyright (c) 2017, 2018 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2017, 2020 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
26
26
package jdk .internal .net .http ;
27
27
28
28
import java .net .ProtocolException ;
29
+ import java .nio .BufferUnderflowException ;
29
30
import java .nio .ByteBuffer ;
30
31
import java .util .ArrayList ;
31
32
import java .util .HashMap ;
32
33
import java .util .List ;
33
34
import java .util .Locale ;
34
35
import java .util .Map ;
35
36
import java .net .http .HttpHeaders ;
37
+
38
+ import jdk .internal .net .http .common .Utils ;
39
+
36
40
import static java .lang .String .format ;
37
41
import static java .util .Objects .requireNonNull ;
38
42
import static jdk .internal .net .http .common .Utils .ACCEPT_ALL ;
@@ -166,9 +170,30 @@ private boolean canContinueParsing(ByteBuffer buffer) {
166
170
}
167
171
}
168
172
173
+ /**
174
+ * Returns a character (char) corresponding to the next byte in the
175
+ * input, interpreted as an ISO-8859-1 encoded character.
176
+ * <p>
177
+ * The ISO-8859-1 encoding is a 8-bit character coding that
178
+ * corresponds to the first 256 Unicode characters - from U+0000 to
179
+ * U+00FF. UTF-16 is backward compatible with ISO-8859-1 - which
180
+ * means each byte in the input should be interpreted as an unsigned
181
+ * value from [0, 255] representing the character code.
182
+ *
183
+ * @param input a {@code ByteBuffer} containing a partial input
184
+ * @return the next byte in the input, interpreted as an ISO-8859-1
185
+ * encoded char
186
+ * @throws BufferUnderflowException
187
+ * if the input buffer's current position is not smaller
188
+ * than its limit
189
+ */
190
+ private char get (ByteBuffer input ) {
191
+ return (char )(input .get () & 0xFF );
192
+ }
193
+
169
194
private void readResumeStatusLine (ByteBuffer input ) {
170
195
char c = 0 ;
171
- while (input .hasRemaining () && (c =( char ) input . get ()) != CR ) {
196
+ while (input .hasRemaining () && (c = get (input )) != CR ) {
172
197
if (c == LF ) break ;
173
198
sb .append (c );
174
199
}
@@ -180,7 +205,7 @@ private void readResumeStatusLine(ByteBuffer input) {
180
205
}
181
206
182
207
private void readStatusLineFeed (ByteBuffer input ) throws ProtocolException {
183
- char c = state == State .STATUS_LINE_FOUND_LF ? LF : ( char ) input . get ();
208
+ char c = state == State .STATUS_LINE_FOUND_LF ? LF : get (input );
184
209
if (c != LF ) {
185
210
throw protocolException ("Bad trailing char, \" %s\" , when parsing status line, \" %s\" " ,
186
211
c , sb .toString ());
@@ -210,7 +235,7 @@ private void readStatusLineFeed(ByteBuffer input) throws ProtocolException {
210
235
private void maybeStartHeaders (ByteBuffer input ) {
211
236
assert state == State .STATUS_LINE_END ;
212
237
assert sb .length () == 0 ;
213
- char c = ( char ) input . get ();
238
+ char c = get (input );
214
239
if (c == CR ) {
215
240
state = State .STATUS_LINE_END_CR ;
216
241
} else if (c == LF ) {
@@ -224,7 +249,7 @@ private void maybeStartHeaders(ByteBuffer input) {
224
249
private void maybeEndHeaders (ByteBuffer input ) throws ProtocolException {
225
250
assert state == State .STATUS_LINE_END_CR || state == State .STATUS_LINE_END_LF ;
226
251
assert sb .length () == 0 ;
227
- char c = state == State .STATUS_LINE_END_LF ? LF : ( char ) input . get ();
252
+ char c = state == State .STATUS_LINE_END_LF ? LF : get (input );
228
253
if (c == LF ) {
229
254
headers = HttpHeaders .of (privateMap , ACCEPT_ALL );
230
255
privateMap = null ;
@@ -238,7 +263,7 @@ private void readResumeHeader(ByteBuffer input) {
238
263
assert state == State .HEADER ;
239
264
assert input .hasRemaining ();
240
265
while (input .hasRemaining ()) {
241
- char c = ( char ) input . get ();
266
+ char c = get (input );
242
267
if (c == CR ) {
243
268
state = State .HEADER_FOUND_CR ;
244
269
break ;
@@ -253,23 +278,31 @@ private void readResumeHeader(ByteBuffer input) {
253
278
}
254
279
}
255
280
256
- private void addHeaderFromString (String headerString ) {
281
+ private void addHeaderFromString (String headerString ) throws ProtocolException {
257
282
assert sb .length () == 0 ;
258
283
int idx = headerString .indexOf (':' );
259
284
if (idx == -1 )
260
285
return ;
261
- String name = headerString .substring (0 , idx ).trim ();
262
- if (name .isEmpty ())
263
- return ;
264
- String value = headerString .substring (idx + 1 , headerString .length ()).trim ();
286
+ String name = headerString .substring (0 , idx );
287
+
288
+ // compatibility with HttpURLConnection;
289
+ if (name .isEmpty ()) return ;
290
+
291
+ if (!Utils .isValidName (name )) {
292
+ throw protocolException ("Invalid header name \" %s\" " , name );
293
+ }
294
+ String value = headerString .substring (idx + 1 ).trim ();
295
+ if (!Utils .isValidValue (value )) {
296
+ throw protocolException ("Invalid header value \" %s: %s\" " , name , value );
297
+ }
265
298
266
299
privateMap .computeIfAbsent (name .toLowerCase (Locale .US ),
267
300
k -> new ArrayList <>()).add (value );
268
301
}
269
302
270
303
private void resumeOrLF (ByteBuffer input ) {
271
304
assert state == State .HEADER_FOUND_CR || state == State .HEADER_FOUND_LF ;
272
- char c = state == State .HEADER_FOUND_LF ? LF : ( char ) input . get ();
305
+ char c = state == State .HEADER_FOUND_LF ? LF : get (input );
273
306
if (c == LF ) {
274
307
// header value will be flushed by
275
308
// resumeOrSecondCR if next line does not
@@ -285,9 +318,9 @@ private void resumeOrLF(ByteBuffer input) {
285
318
}
286
319
}
287
320
288
- private void resumeOrSecondCR (ByteBuffer input ) {
321
+ private void resumeOrSecondCR (ByteBuffer input ) throws ProtocolException {
289
322
assert state == State .HEADER_FOUND_CR_LF ;
290
- char c = ( char ) input . get ();
323
+ char c = get (input );
291
324
if (c == CR || c == LF ) {
292
325
if (sb .length () > 0 ) {
293
326
// no continuation line - flush
@@ -322,7 +355,7 @@ private void resumeOrSecondCR(ByteBuffer input) {
322
355
323
356
private void resumeOrEndHeaders (ByteBuffer input ) throws ProtocolException {
324
357
assert state == State .HEADER_FOUND_CR_LF_CR ;
325
- char c = ( char ) input . get ();
358
+ char c = get (input );
326
359
if (c == LF ) {
327
360
state = State .FINISHED ;
328
361
headers = HttpHeaders .of (privateMap , ACCEPT_ALL );
0 commit comments