1 /* 2 * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.rmi.transport.proxy; 26 27 import java.io.*; 28 29 import sun.rmi.runtime.Log; 30 31 /** 32 * The HttpInputStream class assists the HttpSendSocket and HttpReceiveSocket 33 * classes by filtering out the header for the message as well as any 34 * data after its proper content length. 35 */ 36 class HttpInputStream extends FilterInputStream { 37 38 /** bytes remaining to be read from proper content of message */ 39 protected int bytesLeft; 40 41 /** bytes remaining to be read at time of last mark */ 42 protected int bytesLeftAtMark; 43 44 /** 45 * Create new filter on a given input stream. 46 * @param in the InputStream to filter from 47 */ 48 public HttpInputStream(InputStream in) throws IOException 49 { 50 super(in); 51 52 if (in.markSupported()) 53 in.mark(0); // prevent resetting back to old marks 54 55 // pull out header, looking for content length 56 57 DataInputStream dis = new DataInputStream(in); 58 String key = "Content-length:".toLowerCase(); 59 boolean contentLengthFound = false; 60 String line; 61 do { 62 line = dis.readLine(); 63 64 if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { 65 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, 66 "received header line: \"" + line + "\""); 67 } 68 69 if (line == null) 70 throw new EOFException(); 71 72 if (line.toLowerCase().startsWith(key)) { 73 if (contentLengthFound) 74 ; // what would we want to do in this case?? 75 bytesLeft = 76 Integer.parseInt(line.substring(key.length()).trim()); 77 contentLengthFound = true; 78 } 79 80 // The idea here is to go past the first blank line. 81 // Some DataInputStream.readLine() documentation specifies that 82 // it does include the line-terminating character(s) in the 83 // returned string, but it actually doesn't, so we'll cover 84 // all cases here... 85 } while ((line.length() != 0) && 86 (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); 87 88 if (!contentLengthFound || bytesLeft < 0) { 89 // This really shouldn't happen, but if it does, shoud we fail?? 90 // For now, just give up and let a whole lot of bytes through... 91 bytesLeft = Integer.MAX_VALUE; 92 } 93 bytesLeftAtMark = bytesLeft; 94 95 if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { 96 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, 97 "content length: " + bytesLeft); 98 } 99 } 100 101 /** 102 * Returns the number of bytes that can be read with blocking. 103 * Make sure that this does not exceed the number of bytes remaining 104 * in the proper content of the message. 105 */ 106 public int available() throws IOException 107 { 108 int bytesAvailable = in.available(); 109 if (bytesAvailable > bytesLeft) 110 bytesAvailable = bytesLeft; 111 112 return bytesAvailable; 113 } 114 115 /** 116 * Read a byte of data from the stream. Make sure that one is available 117 * from the proper content of the message, else -1 is returned to 118 * indicate to the user that the end of the stream has been reached. 119 */ 120 public int read() throws IOException 121 { 122 if (bytesLeft > 0) { 123 int data = in.read(); 124 if (data != -1) 125 -- bytesLeft; 126 127 if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { 128 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, 129 "received byte: '" + 130 ((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) + 131 "' " + data); 132 } 133 134 return data; 135 } 136 else { 137 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, 138 "read past content length"); 139 140 return -1; 141 } 142 } 143 144 public int read(byte b[], int off, int len) throws IOException 145 { 146 if (bytesLeft == 0 && len > 0) { 147 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, 148 "read past content length"); 149 150 return -1; 151 } 152 if (len > bytesLeft) 153 len = bytesLeft; 154 int bytesRead = in.read(b, off, len); 155 bytesLeft -= bytesRead; 156 157 if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) { 158 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE, 159 "read " + bytesRead + " bytes, " + bytesLeft + " remaining"); 160 } 161 162 return bytesRead; 163 } 164 165 /** 166 * Mark the current position in the stream (for future calls to reset). 167 * Remember where we are within the proper content of the message, so 168 * that a reset method call can recreate our state properly. 169 * @param readlimit how many bytes can be read before mark becomes invalid 170 */ 171 public void mark(int readlimit) 172 { 173 in.mark(readlimit); 174 if (in.markSupported()) 175 bytesLeftAtMark = bytesLeft; 176 } 177 178 /** 179 * Repositions the stream to the last marked position. Make sure to 180 * adjust our position within the proper content accordingly. 181 */ 182 public void reset() throws IOException 183 { 184 in.reset(); 185 bytesLeft = bytesLeftAtMark; 186 } 187 188 /** 189 * Skips bytes of the stream. Make sure to adjust our 190 * position within the proper content accordingly. 191 * @param n number of bytes to be skipped 192 */ 193 public long skip(long n) throws IOException 194 { 195 if (n > bytesLeft) 196 n = bytesLeft; 197 long bytesSkipped = in.skip(n); 198 bytesLeft -= bytesSkipped; 199 return bytesSkipped; 200 } 201 }