205 lines
7.0 KiB
Java
205 lines
7.0 KiB
Java
/*
|
|
* Copyright (c) 1996, 2012, 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. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* 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.
|
|
*/
|
|
package sun.rmi.transport.proxy;
|
|
|
|
import java.io.*;
|
|
|
|
import sun.rmi.runtime.Log;
|
|
|
|
/**
|
|
* The HttpInputStream class assists the HttpSendSocket and HttpReceiveSocket
|
|
* classes by filtering out the header for the message as well as any
|
|
* data after its proper content length.
|
|
*/
|
|
class HttpInputStream extends FilterInputStream {
|
|
|
|
/** bytes remaining to be read from proper content of message */
|
|
protected int bytesLeft;
|
|
|
|
/** bytes remaining to be read at time of last mark */
|
|
protected int bytesLeftAtMark;
|
|
|
|
/**
|
|
* Create new filter on a given input stream.
|
|
* @param in the InputStream to filter from
|
|
*/
|
|
public HttpInputStream(InputStream in) throws IOException
|
|
{
|
|
super(in);
|
|
|
|
if (in.markSupported())
|
|
in.mark(0); // prevent resetting back to old marks
|
|
|
|
// pull out header, looking for content length
|
|
|
|
DataInputStream dis = new DataInputStream(in);
|
|
String key = "Content-length:".toLowerCase();
|
|
boolean contentLengthFound = false;
|
|
String line;
|
|
do {
|
|
line = dis.readLine();
|
|
|
|
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
|
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
|
"received header line: \"" + line + "\"");
|
|
}
|
|
|
|
if (line == null)
|
|
throw new EOFException();
|
|
|
|
if (line.toLowerCase().startsWith(key)) {
|
|
if (contentLengthFound) {
|
|
throw new IOException(
|
|
"Multiple Content-length entries found.");
|
|
} else {
|
|
bytesLeft =
|
|
Integer.parseInt(line.substring(key.length()).trim());
|
|
contentLengthFound = true;
|
|
}
|
|
}
|
|
|
|
// The idea here is to go past the first blank line.
|
|
// Some DataInputStream.readLine() documentation specifies that
|
|
// it does include the line-terminating character(s) in the
|
|
// returned string, but it actually doesn't, so we'll cover
|
|
// all cases here...
|
|
} while ((line.length() != 0) &&
|
|
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
|
|
|
|
if (!contentLengthFound || bytesLeft < 0) {
|
|
// This really shouldn't happen, but if it does, shoud we fail??
|
|
// For now, just give up and let a whole lot of bytes through...
|
|
bytesLeft = Integer.MAX_VALUE;
|
|
}
|
|
bytesLeftAtMark = bytesLeft;
|
|
|
|
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
|
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
|
"content length: " + bytesLeft);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the number of bytes that can be read with blocking.
|
|
* Make sure that this does not exceed the number of bytes remaining
|
|
* in the proper content of the message.
|
|
*/
|
|
public int available() throws IOException
|
|
{
|
|
int bytesAvailable = in.available();
|
|
if (bytesAvailable > bytesLeft)
|
|
bytesAvailable = bytesLeft;
|
|
|
|
return bytesAvailable;
|
|
}
|
|
|
|
/**
|
|
* Read a byte of data from the stream. Make sure that one is available
|
|
* from the proper content of the message, else -1 is returned to
|
|
* indicate to the user that the end of the stream has been reached.
|
|
*/
|
|
public int read() throws IOException
|
|
{
|
|
if (bytesLeft > 0) {
|
|
int data = in.read();
|
|
if (data != -1)
|
|
-- bytesLeft;
|
|
|
|
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
|
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
|
"received byte: '" +
|
|
((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) +
|
|
"' " + data);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
else {
|
|
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
|
"read past content length");
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public int read(byte b[], int off, int len) throws IOException
|
|
{
|
|
if (bytesLeft == 0 && len > 0) {
|
|
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
|
"read past content length");
|
|
|
|
return -1;
|
|
}
|
|
if (len > bytesLeft)
|
|
len = bytesLeft;
|
|
int bytesRead = in.read(b, off, len);
|
|
bytesLeft -= bytesRead;
|
|
|
|
if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
|
|
RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
|
|
"read " + bytesRead + " bytes, " + bytesLeft + " remaining");
|
|
}
|
|
|
|
return bytesRead;
|
|
}
|
|
|
|
/**
|
|
* Mark the current position in the stream (for future calls to reset).
|
|
* Remember where we are within the proper content of the message, so
|
|
* that a reset method call can recreate our state properly.
|
|
* @param readlimit how many bytes can be read before mark becomes invalid
|
|
*/
|
|
public void mark(int readlimit)
|
|
{
|
|
in.mark(readlimit);
|
|
if (in.markSupported())
|
|
bytesLeftAtMark = bytesLeft;
|
|
}
|
|
|
|
/**
|
|
* Repositions the stream to the last marked position. Make sure to
|
|
* adjust our position within the proper content accordingly.
|
|
*/
|
|
public void reset() throws IOException
|
|
{
|
|
in.reset();
|
|
bytesLeft = bytesLeftAtMark;
|
|
}
|
|
|
|
/**
|
|
* Skips bytes of the stream. Make sure to adjust our
|
|
* position within the proper content accordingly.
|
|
* @param n number of bytes to be skipped
|
|
*/
|
|
public long skip(long n) throws IOException
|
|
{
|
|
if (n > bytesLeft)
|
|
n = bytesLeft;
|
|
long bytesSkipped = in.skip(n);
|
|
bytesLeft -= bytesSkipped;
|
|
return bytesSkipped;
|
|
}
|
|
}
|