Path: blob/master/test/jdk/sun/net/www/http/KeepAliveStream/KeepAliveStreamCloseWithWrongContentLength.java
66646 views
/*1* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 4533243 826336426* @summary Closing a keep alive stream should not give NullPointerException and should accept a connection from a27* client only from this test28* @library /test/lib29* @run main/othervm/timeout=30 KeepAliveStreamCloseWithWrongContentLength30*/3132import java.net.*;33import java.io.*;34import jdk.test.lib.net.URIBuilder;35import java.nio.ByteBuffer;36import java.nio.channels.ServerSocketChannel;37import java.nio.channels.SocketChannel;3839public class KeepAliveStreamCloseWithWrongContentLength {4041private final static String path = "/KeepAliveStreamCloseWithWrongContentLength";42private final static String getRequest1stLine = "GET %s".formatted(path);4344static class XServer extends Thread implements AutoCloseable {4546final ServerSocket serverSocket;47volatile Socket clientSocket;4849XServer (InetAddress address) throws IOException {50ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();51ServerSocket serversocket = serverSocketChannel.socket();52serversocket.bind(new InetSocketAddress(address, 0));53this.serverSocket = serversocket;54}5556public int getLocalPort() {57return serverSocket.getLocalPort();58}5960public void run() {6162try {63ByteArrayOutputStream clientBytes;64clientSocket = null;6566// in a concurrent test environment it can happen that other rouge clients connect to this server67// so we need to identify and connect only to the client from this test68// if the rouge client sends as least bytes as there is in getRequest1stLine it will be discarded and69// the test should proceed otherwise it should timeout on readNBytes below70do {71if (clientSocket != null) {72final String client = "%s:%d".formatted(73clientSocket.getInetAddress().getHostAddress(),74clientSocket.getPort()75);76try {77clientSocket.close();78}79catch (IOException ioe) {80ioe.printStackTrace();81}82finally {83System.err.println("rogue client (%s) connection attempt, ignoring".formatted(client));84}85}86clientSocket = serverSocket.accept();87// read HTTP request from client88clientBytes = new ByteArrayOutputStream();89clientBytes.write(clientSocket.getInputStream().readNBytes(getRequest1stLine.getBytes().length));90}91while(!getRequest1stLine.equals(clientBytes.toString()));92}93catch (Exception e) {94e.printStackTrace();95}96try {97OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream());98outputStreamWriter.write("HTTP/1.0 200 OK\n");99100// Note: The client expects 10 bytes.101outputStreamWriter.write("Content-Length: 10\n");102outputStreamWriter.write("Content-Type: text/html\n");103104// Note: If this line is missing, everything works fine.105outputStreamWriter.write("Connection: Keep-Alive\n");106outputStreamWriter.write("\n");107108// Note: The (buggy) server only sends 9 bytes.109outputStreamWriter.write("123456789");110outputStreamWriter.flush();111clientSocket.getChannel().shutdownOutput();112}113catch (Exception e) {114e.printStackTrace();115}116}117118@Override119public void close() throws Exception {120final var clientSocket = this.clientSocket;121try {122long drained = drain(clientSocket.getChannel());123System.err.printf("Server drained %d bytes from the channel%n", drained);124} catch (Exception x) {125System.err.println("Server failed to drain client socket: " + x);126x.printStackTrace();127}128serverSocket.close();129}130131}132133static long drain(SocketChannel channel) throws IOException {134if (!channel.isOpen()) return 0;135System.err.println("Not reading server: draining socket");136var blocking = channel.isBlocking();137if (blocking) channel.configureBlocking(false);138long count = 0;139try {140ByteBuffer buffer = ByteBuffer.allocateDirect(8 * 1024);141int read;142while ((read = channel.read(buffer)) > 0) {143count += read;144buffer.clear();145}146return count;147} finally {148if (blocking != channel.isBlocking()) {149channel.configureBlocking(blocking);150}151}152}153154155public static void main (String[] args) throws Exception {156157final InetAddress loopback = InetAddress.getLoopbackAddress();158159try (XServer server = new XServer(loopback)) {160server.start();161URL url = URIBuilder.newBuilder()162.scheme("http")163.loopback()164.path(path)165.port(server.getLocalPort())166.toURL();167HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);168InputStream is = urlc.getInputStream();169int c = 0;170while (c != -1) {171try {172c=is.read();173System.out.println("client reads: "+c);174} catch (IOException ioe) {175is.read ();176break;177}178}179is.close();180}181182}183}184185186