jdk/src/java.rmi/share/classes/sun/rmi/transport/proxy/HttpInputStream.java
changeset 37947 f69560487686
parent 37946 e420b9f05aaf
parent 37936 428ebc487445
child 37948 caf97b37ebec
equal deleted inserted replaced
37946:e420b9f05aaf 37947:f69560487686
     1 /*
       
     2  * Copyright (c) 1996, 2014, 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     @SuppressWarnings("deprecation")
       
    49     public HttpInputStream(InputStream in) throws IOException
       
    50     {
       
    51         super(in);
       
    52 
       
    53         if (in.markSupported())
       
    54             in.mark(0); // prevent resetting back to old marks
       
    55 
       
    56         // pull out header, looking for content length
       
    57 
       
    58         DataInputStream dis = new DataInputStream(in);
       
    59         String key = "Content-length:".toLowerCase();
       
    60         boolean contentLengthFound = false;
       
    61         String line;
       
    62         do {
       
    63             line = dis.readLine();
       
    64 
       
    65             if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
       
    66                 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
       
    67                     "received header line: \"" + line + "\"");
       
    68             }
       
    69 
       
    70             if (line == null)
       
    71                 throw new EOFException();
       
    72 
       
    73             if (line.toLowerCase().startsWith(key)) {
       
    74                 if (contentLengthFound) {
       
    75                     throw new IOException(
       
    76                             "Multiple Content-length entries found.");
       
    77                 } else {
       
    78                     bytesLeft =
       
    79                         Integer.parseInt(line.substring(key.length()).trim());
       
    80                     contentLengthFound = true;
       
    81                 }
       
    82             }
       
    83 
       
    84             // The idea here is to go past the first blank line.
       
    85             // Some DataInputStream.readLine() documentation specifies that
       
    86             // it does include the line-terminating character(s) in the
       
    87             // returned string, but it actually doesn't, so we'll cover
       
    88             // all cases here...
       
    89         } while ((line.length() != 0) &&
       
    90                  (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
       
    91 
       
    92         if (!contentLengthFound || bytesLeft < 0) {
       
    93             // This really shouldn't happen, but if it does, shoud we fail??
       
    94             // For now, just give up and let a whole lot of bytes through...
       
    95             bytesLeft = Integer.MAX_VALUE;
       
    96         }
       
    97         bytesLeftAtMark = bytesLeft;
       
    98 
       
    99         if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
       
   100             RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
       
   101                 "content length: " + bytesLeft);
       
   102         }
       
   103     }
       
   104 
       
   105     /**
       
   106      * Returns the number of bytes that can be read with blocking.
       
   107      * Make sure that this does not exceed the number of bytes remaining
       
   108      * in the proper content of the message.
       
   109      */
       
   110     public int available() throws IOException
       
   111     {
       
   112         int bytesAvailable = in.available();
       
   113         if (bytesAvailable > bytesLeft)
       
   114             bytesAvailable = bytesLeft;
       
   115 
       
   116         return bytesAvailable;
       
   117     }
       
   118 
       
   119     /**
       
   120      * Read a byte of data from the stream.  Make sure that one is available
       
   121      * from the proper content of the message, else -1 is returned to
       
   122      * indicate to the user that the end of the stream has been reached.
       
   123      */
       
   124     public int read() throws IOException
       
   125     {
       
   126         if (bytesLeft > 0) {
       
   127             int data = in.read();
       
   128             if (data != -1)
       
   129                 -- bytesLeft;
       
   130 
       
   131             if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
       
   132                 RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
       
   133                    "received byte: '" +
       
   134                     ((data & 0x7F) < ' ' ? " " : String.valueOf((char) data)) +
       
   135                     "' " + data);
       
   136             }
       
   137 
       
   138             return data;
       
   139         }
       
   140         else {
       
   141             RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
       
   142                                                 "read past content length");
       
   143 
       
   144             return -1;
       
   145         }
       
   146     }
       
   147 
       
   148     public int read(byte b[], int off, int len) throws IOException
       
   149     {
       
   150         if (bytesLeft == 0 && len > 0) {
       
   151             RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
       
   152                                                 "read past content length");
       
   153 
       
   154             return -1;
       
   155         }
       
   156         if (len > bytesLeft)
       
   157             len = bytesLeft;
       
   158         int bytesRead = in.read(b, off, len);
       
   159         bytesLeft -= bytesRead;
       
   160 
       
   161         if (RMIMasterSocketFactory.proxyLog.isLoggable(Log.VERBOSE)) {
       
   162             RMIMasterSocketFactory.proxyLog.log(Log.VERBOSE,
       
   163                 "read " + bytesRead + " bytes, " + bytesLeft + " remaining");
       
   164         }
       
   165 
       
   166         return bytesRead;
       
   167     }
       
   168 
       
   169     /**
       
   170      * Mark the current position in the stream (for future calls to reset).
       
   171      * Remember where we are within the proper content of the message, so
       
   172      * that a reset method call can recreate our state properly.
       
   173      * @param readlimit how many bytes can be read before mark becomes invalid
       
   174      */
       
   175     public void mark(int readlimit)
       
   176     {
       
   177         in.mark(readlimit);
       
   178         if (in.markSupported())
       
   179             bytesLeftAtMark = bytesLeft;
       
   180     }
       
   181 
       
   182     /**
       
   183      * Repositions the stream to the last marked position.  Make sure to
       
   184      * adjust our position within the proper content accordingly.
       
   185      */
       
   186     public void reset() throws IOException
       
   187     {
       
   188         in.reset();
       
   189         bytesLeft = bytesLeftAtMark;
       
   190     }
       
   191 
       
   192     /**
       
   193      * Skips bytes of the stream.  Make sure to adjust our
       
   194      * position within the proper content accordingly.
       
   195      * @param n number of bytes to be skipped
       
   196      */
       
   197     public long skip(long n) throws IOException
       
   198     {
       
   199         if (n > bytesLeft)
       
   200             n = bytesLeft;
       
   201         long bytesSkipped = in.skip(n);
       
   202         bytesLeft -= bytesSkipped;
       
   203         return bytesSkipped;
       
   204     }
       
   205 }