001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov, Vasily Zakharov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi.transport.proxy;
023:
024: import java.io.DataInputStream;
025: import java.io.EOFException;
026: import java.io.FilterInputStream;
027: import java.io.IOException;
028: import java.io.InputStream;
029:
030: import org.apache.harmony.rmi.common.RMILog;
031: import org.apache.harmony.rmi.internal.nls.Messages;
032:
033: /**
034: * InputStream for HTTP connections. Unwraps data from HTTP packets.
035: *
036: * @author Mikhail A. Markov, Vasily Zakharov
037: * @version $Revision: 1.1.2.2 $
038: */
039: public class HttpInputStream extends FilterInputStream implements
040: ProxyConstants {
041:
042: /**
043: * If this is inbound connection stream.
044: */
045: private boolean inbound;
046:
047: /**
048: * Amount of data available in the stream.
049: */
050: private int available;
051:
052: /**
053: * Constructs this stream from the given input stream.
054: * The stream is considered operational after <code>expect</code>
055: * string is received from the stream.
056: * If <code>expect</code> is <code>null</code>,
057: * the stream is considered operational immediately.
058: *
059: * @param in
060: * Input stream.
061: *
062: * @param inbound
063: * If this is inbound connection stream.
064: */
065: public HttpInputStream(InputStream in, boolean inbound) {
066: super (new DataInputStream(in));
067: this .inbound = inbound;
068: this .available = (-1);
069: }
070:
071: /**
072: * Always returns <code>false</code> (mark operations are not supported).
073: *
074: * @return <code>false</code>
075: */
076: public final boolean markSupported() {
077: return false;
078: }
079:
080: /**
081: * {@inheritDoc}
082: */
083: public final int available() throws IOException {
084: if (available < 0) {
085: readHeader();
086: }
087:
088: return available;
089: }
090:
091: /**
092: * {@inheritDoc}
093: */
094: public final int read() throws IOException {
095: if (available < 0) {
096: readHeader();
097: }
098:
099: if (available < 1) {
100: return (-1);
101: }
102:
103: int data = in.read();
104:
105: if (data != (-1)) {
106: available--;
107:
108: if (proxyTransportLog.isLoggable(RMILog.VERBOSE)) {
109: // rmi.log.128=Read 1 byte, {0} remaining.
110: proxyTransportLog.log(RMILog.VERBOSE, Messages
111: .getString("rmi.log.128", available)); //$NON-NLS-1$
112: }
113: }
114:
115: return data;
116: }
117:
118: /**
119: * {@inheritDoc}
120: */
121: public final int read(byte[] b, int off, int len)
122: throws IOException {
123: if (available < 0) {
124: readHeader();
125: }
126:
127: if (available < 1) {
128: return (-1);
129: }
130:
131: if (len > available) {
132: len = available;
133: }
134:
135: int readSize = in.read(b, off, len);
136:
137: // rmi.8D=readSize is greater than len
138: assert (readSize <= len) : Messages.getString("rmi.8D"); //$NON-NLS-1$
139:
140: available -= readSize;
141:
142: // rmi.log.129=Read {0} bytes, {1} remaining.
143: if (proxyTransportLog.isLoggable(RMILog.VERBOSE)) {
144: proxyTransportLog.log(RMILog.VERBOSE, Messages.getString(
145: "rmi.log.129", //$NON-NLS-1$
146: readSize, available));
147: }
148:
149: return readSize;
150: }
151:
152: /**
153: * Reads the next line of text from the stream
154: * using {@link DataInputStream#readLine()}.
155: *
156: * @return Next line of text from the input stream,
157: * or <code>null</code> if end of file is encountered
158: * before even one byte can be read.
159: *
160: * @throws IOException
161: * If I/O error occurs.
162: */
163: public final String readLine() throws IOException {
164: if (available < 0) {
165: readHeader();
166: }
167:
168: return ((DataInputStream) in).readLine();
169: }
170:
171: /**
172: * Reads HTTP header, sets {@link #available} amount of data.
173: *
174: * @throws IOException
175: * If I/O error occurs.
176: */
177: private void readHeader() throws IOException {
178: String expectName;
179: String expectHeader;
180:
181: if (inbound) {
182: expectName = "POST request"; //$NON-NLS-1$
183: expectHeader = HTTP_REQUEST_SIGNATURE;
184: } else {
185: expectName = "HTTP response"; //$NON-NLS-1$
186: expectHeader = HTTP_RESPONSE_HEADER_SIGNATURE;
187: }
188:
189: String[] errorMessages = {
190: // rmi.log.12A=Unable to read header data, couldn't find {0}
191: Messages.getString("rmi.log.12A", expectName), //$NON-NLS-1$
192: // rmi.log.12B=Unable to read header data, Content-Length not specified
193: Messages.getString("rmi.log.12B"), //$NON-NLS-1$
194: // rmi.log.12C=Unable to read input stream data, no data found
195: Messages.getString("rmi.log.12C") //$NON-NLS-1$
196: };
197:
198: // Looking for headers phases sequentially.
199: for (int phase = 0;; phase++) {
200: // rmi.89=Incorrect phase: {0}
201: assert ((phase >= 0) && (phase <= 2)) : (Messages
202: .getString("rmi.89", phase)); //$NON-NLS-1$
203:
204: String expectSubject;
205: String expectString;
206: int expectStringLength;
207:
208: switch (phase) {
209: case 0:
210: expectSubject = expectName;
211: expectString = expectHeader;
212: expectStringLength = expectHeader.length();
213: break;
214: case 1:
215: expectSubject = "Content-Length specification"; //$NON-NLS-1$
216: expectString = CONTENT_LENGTH_SIGNATURE;
217: expectStringLength = CONTENT_LENGTH_SIGNATURE_LENGTH;
218: break;
219: default: // 2
220: expectSubject = null;
221: expectString = null;
222: expectStringLength = 0;
223: break;
224: }
225:
226: // Searching for the expected string for this phase.
227: //
228: // Note: here we ignore the following for simplicity:
229: // Header fields can be extended over multiple lines
230: // by preceding extra lines with spaces(s) or tab(s).
231: // (See RFC 2616 4.2)
232: while (true) {
233: String line = ((DataInputStream) in).readLine();
234:
235: // Checking for EOF.
236: if (line == null) {
237: throw new EOFException(errorMessages[phase]);
238: }
239:
240: // Diagnostic print.
241: if (proxyTransportLog.isLoggable(RMILog.VERBOSE)) {
242: // rmi.log.12D=Header line received: [{0}].
243: proxyTransportLog.log(RMILog.VERBOSE, Messages
244: .getString("rmi.log.12D", line)); //$NON-NLS-1$
245: }
246:
247: // Checking for empty line.
248: if (line.length() < 1) {
249: if (phase < 2) {
250: throw new EOFException(errorMessages[phase]);
251: } else { // phase == 2
252: // Empty line found, end of headers, everything's fine.
253: if (proxyTransportLog
254: .isLoggable(RMILog.VERBOSE)) {
255: // rmi.log.12E=Input stream data found, stream ready.
256: proxyTransportLog.log(RMILog.VERBOSE,
257: Messages.getString("rmi.log.12E")); //$NON-NLS-1$
258: }
259: return;
260: }
261: }
262:
263: if (phase > 1) {
264: // Just skip non-empty lines after Content-Length is found.
265: continue;
266: }
267:
268: // Checking for expected line, using case sensitive comparison
269: // for phase 0 and case insensitive comparison for phase 1.
270: //
271: // Note: The reason phrase should be ignored.
272: // (See RFC 2616 6.1.1)
273: //
274: // Note: here we ignore codes other than 200 for simplicity.
275: // (See RFC 2616 6.1.1)
276: if (line.regionMatches((phase == 1), 0, expectString,
277: 0, expectStringLength)) {
278: if (proxyTransportLog.isLoggable(RMILog.VERBOSE)) {
279: // rmi.log.12F={0} found.
280: proxyTransportLog.log(RMILog.VERBOSE,
281: Messages.getString(
282: "rmi.log.12F", expectSubject)); //$NON-NLS-1$
283: }
284:
285: if (phase == 1) {
286: // Found Content-Length specification.
287: try {
288: available = Integer.parseInt(line
289: .substring(expectStringLength)
290: .trim());
291: } catch (NumberFormatException e) {
292: // rmi.8A=Content-Length specified incorrectly: {0}
293: throw new IOException(Messages.getString(
294: "rmi.8A", line));//$NON-NLS-1$
295: }
296:
297: if (available < 0) {
298: // rmi.8B=Invalid Content-Length: {0}
299: throw new IOException(Messages.getString(
300: "rmi.8B", available)); //$NON-NLS-1$
301: }
302:
303: if (proxyTransportLog
304: .isLoggable(RMILog.VERBOSE)) {
305: // rmi.8C=Content-Length received: {0}
306: proxyTransportLog.log(RMILog.VERBOSE,
307: Messages.getString(
308: "rmi.8C", available)); //$NON-NLS-1$
309: }
310: }
311: // Move to the next phase.
312: break;
313: }
314: // Skipping this line.
315: }
316: }
317: }
318: }
|