e0d361cea9
Reviewed-by: lancea, wetmore, naoto, iris, kevinw, xuelei
176 lines
6.6 KiB
Java
176 lines
6.6 KiB
Java
/*
|
|
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/**
|
|
* @test
|
|
* @bug 8164704
|
|
* @modules java.net.http
|
|
* jdk.httpserver
|
|
* java.base/sun.net.www
|
|
* @run main MessageHeadersTest
|
|
* @summary Tests expected behavior of MessageHeader. This test
|
|
* cannot be used to verify 8164704 - it simply verifies
|
|
* the assumptions on which the fix is based.
|
|
*/
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.nio.ByteBuffer;
|
|
|
|
|
|
public class MessageHeadersTest {
|
|
|
|
static final String BODY =
|
|
"This is the body dude,\r\n"
|
|
+ "not a header!\r\n";
|
|
|
|
static final String MESSAGE_OK =
|
|
"HTTP/1.1 200 OK\r\n"
|
|
+ "Content-Length: " + BODY.length() + "\r\n"
|
|
+ "MY-Folding-Header: YES\r\n"
|
|
+ " OR\r\n"
|
|
+ " NO\r\n"
|
|
+ "\r\n"
|
|
+ BODY;
|
|
|
|
static final String MESSAGE_NOK =
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
+ "\r\n";
|
|
|
|
static final class ByteBufferInputStream extends InputStream {
|
|
final ByteBuffer buffer;
|
|
int lastRead = -1;
|
|
ByteBufferInputStream(ByteBuffer buffer) {
|
|
this.buffer = buffer;
|
|
}
|
|
@Override
|
|
public int read() throws IOException {
|
|
if (buffer.hasRemaining()) {
|
|
return lastRead = buffer.get();
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
testMessageHeaders(MESSAGE_OK);
|
|
testMessageHeaders(MESSAGE_NOK);
|
|
}
|
|
|
|
/**
|
|
* Verifies that MessageHeader behave as we expect.
|
|
* @param msg The response string.
|
|
* @throws IOException should not happen.
|
|
*/
|
|
static void testMessageHeaders(String msg) throws IOException {
|
|
byte[] bytes = msg.getBytes("US-ASCII");
|
|
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
|
|
|
// Read status line
|
|
String statusLine = readStatusLine(buffer);
|
|
System.out.println("StatusLine: " + statusLine);
|
|
if (!statusLine.startsWith("HTTP/1.1")) {
|
|
throw new AssertionError("bad status line: " + statusLine);
|
|
}
|
|
|
|
// Wrap the buffer into an input stream and pass
|
|
// that to MessageHeader to read the header.
|
|
// We have two cases:
|
|
// - MESSAGE_OK: there will be some headers to read,
|
|
// - MESSAGE_NOK: there will be no headers to read.
|
|
ByteBufferInputStream bbis = new ByteBufferInputStream(buffer);
|
|
sun.net.www.MessageHeader mh = new sun.net.www.MessageHeader(bbis);
|
|
|
|
// Now get the expected length of the body
|
|
String contentLengthValue = mh.findValue("Content-length");
|
|
int contentLength = contentLengthValue == null ? 0
|
|
: Integer.parseInt(contentLengthValue);
|
|
|
|
// We again have two cases:
|
|
// - MESSAGE_OK: there should be a Content-length: header
|
|
// - MESSAGE_NOK: there should be no Content-length: header
|
|
if (contentLengthValue == null) {
|
|
// MESSAGE_NOK has no headers and no body and therefore
|
|
// no Content-length: header.
|
|
if (!MESSAGE_NOK.equals(msg)) {
|
|
throw new AssertionError("Content-length: header not found");
|
|
}
|
|
// In that case we expect MessageHeader to read the CR but
|
|
// leave the LF in the buffer. We therefore need to consume
|
|
// the LF in order to get an empty (all consumed) buffer.
|
|
// This is what ResponseHeaders does.
|
|
byte c = buffer.get();
|
|
if (c != '\n' || bbis.lastRead != '\r') {
|
|
throw new AssertionError("Unexpected byte sequence for empty body"
|
|
+ ": " + bbis.lastRead + " " + c + " expected "
|
|
+ (byte)'\r' + " " + (byte)'\n');
|
|
}
|
|
} else {
|
|
if (MESSAGE_NOK.equals(msg)) {
|
|
throw new AssertionError("Content-length: header found in"
|
|
+ " error 101 message");
|
|
}
|
|
}
|
|
|
|
// Now read the remaining bytes. It should either be
|
|
// the empty string (MESSAGE_NOK) or BODY (MESSAGE_OK),
|
|
// and it should not contains any leading CR or LF"
|
|
String remaining = readRemainingBytes(buffer);
|
|
System.out.println("Body: <<<" + remaining + ">>>");
|
|
if (remaining.length() != contentLength) {
|
|
throw new AssertionError("Unexpected body length: " + remaining.length()
|
|
+ " expected " + contentLengthValue);
|
|
}
|
|
if (contentLengthValue != null) {
|
|
if (!BODY.equals(remaining)) {
|
|
throw new AssertionError("Body does not match!");
|
|
}
|
|
}
|
|
}
|
|
|
|
static String readRemainingBytes(ByteBuffer buffer) throws UnsupportedEncodingException {
|
|
byte[] res = new byte[buffer.limit() - buffer.position()];
|
|
System.arraycopy(buffer.array(), buffer.position(), res, 0, res.length);
|
|
buffer.position(buffer.limit());
|
|
return new String(res, "US-ASCII");
|
|
}
|
|
|
|
static String readStatusLine(ByteBuffer buffer) throws IOException {
|
|
buffer.mark();
|
|
int p = buffer.position();
|
|
while(buffer.hasRemaining()) {
|
|
char c = (char)buffer.get();
|
|
if (c == '\r') {
|
|
c = (char)buffer.get();
|
|
if (c == '\n') {
|
|
byte[] res = new byte[buffer.position() - p -2];
|
|
System.arraycopy(buffer.array(), p, res, 0, res.length);
|
|
return new String(res, "US-ASCII");
|
|
}
|
|
}
|
|
}
|
|
throw new IOException("Status line not found");
|
|
}
|
|
}
|