Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/net/URLConnection/DisconnectAfterEOF.java
38812 views
/*1* Copyright (c) 2002, 2010, 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 477450326* @summary Calling HttpURLConnection's disconnect method after the27* response has been received causes havoc with persistent28* connections.29*/30import java.net.*;31import java.io.*;32import java.util.*;3334public class DisconnectAfterEOF {3536/*37* Worker thread to service single connection - can service38* multiple http requests on same connection.39*/40static class Worker extends Thread {41Socket s;4243Worker(Socket s) {44this.s = s;45}4647public void run() {48try {49InputStream in = s.getInputStream();50PrintStream out = new PrintStream(51new BufferedOutputStream(52s.getOutputStream() ));53byte b[] = new byte[1024];54int n = -1;55int cl = -1;56int remaining = -1;57StringBuffer sb = new StringBuffer();58boolean close = false;5960boolean inBody = false;61for (;;) {62boolean sendResponse = false;6364try {65n = in.read(b);66} catch (IOException ioe) {67n = -1;68}69if (n <= 0) {70if (inBody) {71System.err.println("ERROR: Client closed before before " +72"entire request received.");73}74return;75}7677// reading entity-body78if (inBody) {79if (n > remaining) {80System.err.println("Receiving more than expected!!!");81return;82}83remaining -= n;8485if (remaining == 0) {86sendResponse = true;87n = 0;88} else {89continue;90}91}9293// reading headers94for (int i=0; i<n; i++) {95char c = (char)b[i];9697if (c != '\n') {98sb.append(c);99continue;100}101102103// Got end-of-line104int len = sb.length();105if (len > 0) {106if (sb.charAt(len-1) != '\r') {107System.err.println("Unexpected CR in header!!");108return;109}110}111sb.setLength(len-1);112113// empty line114if (sb.length() == 0) {115if (cl < 0) {116System.err.println("Content-Length not found!!!");117return;118}119120// the surplus is body data121int dataRead = n - (i+1);122remaining = cl - dataRead;123if (remaining > 0) {124inBody = true;125break;126} else {127// entire body has been read128sendResponse = true;129}130} else {131// non-empty line - check for Content-Length132String line = sb.toString().toLowerCase();133if (line.startsWith("content-length")) {134StringTokenizer st = new StringTokenizer(line, ":");135st.nextToken();136cl = Integer.parseInt(st.nextToken().trim());137}138if (line.startsWith("connection")) {139StringTokenizer st = new StringTokenizer(line, ":");140st.nextToken();141if (st.nextToken().trim().equals("close")) {142close =true;143}144}145}146sb = new StringBuffer();147}148149150if (sendResponse) {151// send a large response152int rspLen = 32000;153154out.print("HTTP/1.1 200 OK\r\n");155out.print("Content-Length: " + rspLen + "\r\n");156out.print("\r\n");157158if (rspLen > 0)159out.write(new byte[rspLen]);160161out.flush();162163if (close)164return;165166sendResponse = false;167inBody = false;168cl = -1;169}170}171172} catch (IOException ioe) {173} finally {174try {175s.close();176} catch (Exception e) { }177System.out.println("+ Worker thread shutdown.");178}179}180}181182/*183* Server thread to accept connection and create worker threads184* to service each connection.185*/186static class Server extends Thread {187ServerSocket ss;188189Server(ServerSocket ss) {190this.ss = ss;191}192193public void run() {194try {195for (;;) {196Socket s = ss.accept();197Worker w = new Worker(s);198w.start();199}200201} catch (IOException ioe) {202}203204System.out.println("+ Server shutdown.");205}206207public void shutdown() {208try {209ss.close();210} catch (IOException ioe) { }211}212}213214static URLConnection doRequest(String uri) throws IOException {215URLConnection uc = (new URL(uri)).openConnection();216uc.setDoOutput(true);217OutputStream out = uc.getOutputStream();218out.write(new byte[16000]);219220// force the request to be sent221uc.getInputStream();222return uc;223}224225static URLConnection doResponse(URLConnection uc) throws IOException {226int cl = ((HttpURLConnection)uc).getContentLength();227byte b[] = new byte[4096];228int n;229do {230n = uc.getInputStream().read(b);231if (n > 0) cl -= n;232} while (n > 0);233if (cl != 0) {234throw new RuntimeException("ERROR: content-length mismatch");235}236return uc;237}238239public static void main(String args[]) throws Exception {240// start server241ServerSocket ss = new ServerSocket(0);242Server svr = new Server(ss);243svr.start();244245String uri = "http://localhost:" +246Integer.toString(ss.getLocalPort()) +247"/foo.html";248249/*250* The following is the test scenario we create here :-251*252* 1. We do a http request/response and read the response253* to EOF. As it's a persistent connection the idle254* connection should go into the keep-alive cache for a255* few seconds.256*257* 2. We start a second request but don't read the response.258* As the request is to the same server we can assume it259* (for our implementation anyway) that it will use the260* same TCP connection.261*262* 3. We "disconnect" the first HttpURLConnection. This263* should be no-op because the connection is in use264* but another request. However with 1.3.1 and 1.4/1.4.1265* this causes the TCP connection for the second request266* to be closed.267*268*/269URLConnection uc1 = doRequest(uri);270doResponse(uc1);271272Thread.sleep(2000);273274URLConnection uc2 = doRequest(uri);275276((HttpURLConnection)uc1).disconnect();277278IOException ioe = null;279try {280doResponse(uc2);281} catch (IOException x) {282ioe = x;283}284285((HttpURLConnection)uc2).disconnect();286287/*288* Shutdown server as we are done. Worker threads created289* by the server will shutdown automatically when the290* client connection closes.291*/292svr.shutdown();293294if (ioe != null) {295throw ioe;296}297}298}299300301