You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2002/02/06 18:11:30 UTC
cvs commit: jakarta-tomcat-connectors/jk/java/org/apache/jk/common JkInputStream.java
costin 02/02/06 09:11:30
Added: jk/java/org/apache/jk/common JkInputStream.java
Log:
Common implementation of the input stream, will be shared by all
containers.
This code is derived from tomcat3.3's implementation, which is newer ( it
happen after j-t-c was forked, in the 3.3 impl. of Ajp13Interceptor ). It
supports buffering and few other optimizations.
We also support the 'chunked encoding' and available.
Revision Changes Path
1.1 jakarta-tomcat-connectors/jk/java/org/apache/jk/common/JkInputStream.java
Index: JkInputStream.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.jk.common;
import java.io.*;
import java.util.List;
import java.util.Iterator;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.Cookies;
import org.apache.tomcat.util.http.ServerCookie;
import org.apache.tomcat.util.http.BaseRequest;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.jk.core.*;
import org.apache.jk.common.*;
import org.apache.jk.util.*;
/** Generic input stream impl on top of ajp
*/
public class JkInputStream extends InputStream {
public JkInputStream() {
}
public int available() throws IOException {
return blen-pos;
}
public void close() throws IOException {
this.closed=true;
}
public void mark(int readLimit) {
}
public boolean markSupported() {
return false;
}
public void reset() throws IOException {
throw new IOException("reset() not supported");
}
public int read() throws IOException {
if( contentLength == -1 ) {
return doRead1();
}
if( available <= 0 ) {
if( dL>0 ) d("doRead() nothing available" );
return -1;
}
available--;
return doRead1();
}
public int read(byte[] b, int off, int len) throws IOException {
int rd=-1;
if( contentLength == -1 ) {
rd=doRead1(b,off,len);
return rd;
}
if( available <= 0 ) {
if( dL>0 ) d("doRead() nothing available" );
return -1;
}
rd=doRead1( b,off, len );
available -= rd;
if( dL > 0 ) d("Read: " + new String( b,off, len ));
return rd;
}
public long skip(long n) throws IOException {
if (n > Integer.MAX_VALUE) {
throw new IOException("can't skip than many: " + n);
}
// XXX if n is big, split this in multiple reads
byte[] b = new byte[(int)n];
return read(b, 0, b.length);
}
// -------------------- Jk specific methods --------------------
Msg bodyMsg=new MsgAjp();
MsgContext mc;
// Total length of the body - maximum we can read
// If -1, we don't use any limit, and we don't count available
int contentLength;
// How much remains unread.
int available;
boolean closed=false;
// Ajp13 specific - needs refactoring for the new model
public static final int MAX_PACKET_SIZE=8192;
public static final int H_SIZE=4; // Size of basic packet header
public static final int MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2;
public static final byte JK_AJP13_GET_BODY_CHUNK = 6;
// Holds incoming chunks of request body data
// XXX We do a copy that could be avoided !
byte []bodyBuff = new byte[MAX_READ_SIZE];
int blen; // Length of current chunk of body data in buffer
int pos; // Current read position within that buffer
boolean end_of_stream; // true if we've received an empty packet
private int doRead1() throws IOException {
if( dL>0 ) d("doRead1 " );
if(pos >= blen) {
if( ! refillReadBuffer()) {
return -1;
}
}
return bodyBuff[pos++] & 0xFF; // prevent sign extension of byte value
}
public int doRead1(byte[] b, int off, int len) throws IOException
{
if( dL>0 ) d("doRead1 " );
if(pos >= blen) {
if( ! refillReadBuffer()) {
return -1;
}
}
if(pos + len <= blen) { // Fear the off by one error
// Sanity check b.length > off + len?
System.arraycopy(bodyBuff, pos, b, off, len);
if( dL > 0 )
d("doRead1: " + pos + " " + len + " " + blen + " " +
new String( b, off, len ) + " " + Thread.currentThread());
pos += len;
return len;
}
// Not enough data (blen < pos + len) or chunked encoded
int toCopy = len;
while(toCopy > 0) {
int bytesRemaining = blen - pos;
if(bytesRemaining < 0)
bytesRemaining = 0;
int c = bytesRemaining < toCopy ? bytesRemaining : toCopy;
System.arraycopy(bodyBuff, pos, b, off, c);
if( dL > 0 ) d("doRead2: " + pos + " " + len + " " + blen + " " +
c + " " + new String( b, off, c ) + " " +
new String( bodyBuff, pos, c ));
toCopy -= c;
off += c;
pos += c; // In case we exactly consume the buffer
if(toCopy > 0)
if( ! refillReadBuffer()) { // Resets blen and pos
break;
}
}
return len - toCopy;
}
/** Must be called after the request is parsed, before
* any input
*/
public void setContentLength( int i ) {
contentLength=i;
available=i;
}
/** Must be called when the stream is created
*/
public void setMsgContext( MsgContext mc ) {
this.mc=mc;
}
/** Must be called before or after each request
*/
public void recycle() {
available=0;
blen = 0;
pos = 0;
closed=false;
end_of_stream = false;
contentLength=-1;
}
/** Receive a chunk of data. Called to implement the
* 'special' packet in ajp13 and to receive the data
* after we send a GET_BODY packet
*/
public boolean receive() throws IOException
{
int err = mc.getChannel().receive(bodyMsg, mc);
if(err < 0) {
throw new IOException();
}
// No data received.
if( bodyMsg.getLen() == 0 ) {
pos=0;
blen=0;
end_of_stream = true;
return false;
}
blen = bodyMsg.peekInt();
pos = 0;
int cpl=bodyMsg.getBytes(bodyBuff);
if( dL > 0 )
d( "Copy into body buffer2 " + bodyBuff + " " +
cpl + " " + blen + " " +
new String( bodyBuff, 0, cpl ));
return (blen > 0);
}
/**
* Get more request body data from the web server and store it in the
* internal buffer.
*
* @return true if there is more data, false if not.
*/
private boolean refillReadBuffer() throws IOException
{
// If the server returns an empty packet, assume that that end of
// the stream has been reached (yuck -- fix protocol??).
if (end_of_stream) {
if( dL>0 ) d("refillReadBuffer: end of stream " );
return false;
}
// Why not use outBuf??
bodyMsg.reset();
bodyMsg.appendByte(JK_AJP13_GET_BODY_CHUNK);
bodyMsg.appendInt(MAX_READ_SIZE);
if( dL>0 ) d("refillReadBuffer " + Thread.currentThread());
mc.getChannel().send(bodyMsg, mc);
return receive();
}
private static final int dL=10;
private static void d(String s ) {
System.err.println( "JkInputStream: " + s );
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>