|
What this is
Other links
The source code/* * Copyright 1999-2004 The Apache Sofware Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.tomcat.modules.server; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.io.RecycleBufferedInputStream; import org.apache.tomcat.util.log.Log; public class Http10 { private Socket socket; private boolean moreRequests = false; RecycleBufferedInputStream sin; protected OutputStream sout; byte[] buf; int bufSize=2048; // default int off=0; int count=0; protected static final int DEFAULT_HEAD_BUFFER_SIZE = 1024; protected byte[] oBuffer = new byte[DEFAULT_HEAD_BUFFER_SIZE]; protected int oBufferCount = 0; static final byte CRLF[]= { (byte)'\r', (byte)'\n' }; Log loghelper = Log.getLog("tc_log", this); public Http10() { super(); buf=new byte[bufSize]; } public void setSocket(Socket socket) throws IOException { if( sin==null) sin = new RecycleBufferedInputStream ( socket.getInputStream()); else sin.setInputStream( socket.getInputStream()); this.socket = socket; moreRequests = true; sout=socket.getOutputStream(); } public void recycle() { off=0; count=0; oBufferCount=0; if( sin!=null ) sin.recycle(); } // -------------------- HTTP input methods -------------------- public int doRead() throws IOException { return sin.read(); } public int doRead(byte[] b, int off, int len) throws IOException { return sin.read(b, off, len); } static class Location { int off; int end; Location( int start , int end ) { this.off=start; this.end=end; } } private int readLine( Location line ) throws IOException { while (true) { line.end=line.off; int len = buf.length - line.off; if (len > 0) { len = readLine(sin, buf, line.off, len); if (len == -1) { return 400; } line.end += len; if (len == 0 || buf[line.end-1] == '\n') { // strip \n if( line.end> line.off && buf[line.end-1]=='\n' ) --line.end; // strip off trailing "\r\n" if (line.end > line.off && buf[line.end-1] == '\r') { --line.end; } return 0; // Empty line || end of line } } // overflowed buffer, so temporarily expand and continue // XXX DOS - if the length is too big - stop and throw exception byte[] tmp = new byte[buf.length * 2]; System.arraycopy(buf, 0, tmp, 0, buf.length); buf = tmp; // read more ( the buffer was resized ) } } Location headerArea=new Location( off, -1 ); Location line=new Location( off, -1 ); Location nextLine=new Location( off, -1); /** * Reads header fields from the specified servlet input stream until * a blank line is encountered. * @param in the servlet input stream * @exception IllegalArgumentException if the header format was invalid * @exception IOException if an I/O error has occurred */ public int readHeaders( MimeHeaders headers ) throws IOException { // use pre-allocated buffer if possible off = count; // where the request line ended headerArea.off=off; boolean firstLine=true; while (true) { if( firstLine ) { // first line line.off=off; int status=readLine( line ); if( status != 0 ) return status; off=line.end; if( d > 0 ) debug( "Read1: " + new String( buf, line.off, line.end-line.off)); firstLine=false; } else { line.off=nextLine.off; line.end=nextLine.end; } if (line.off == line.end) { // Empty line, end of headers break; } // Read next lines, maybe we have a multi-line header while( true ) { nextLine.off=line.end; int status=readLine( nextLine ); if( status!= 0 ) return status; if( d > 0 ) debug( "Read2: " + new String( buf, nextLine.off, nextLine.end-nextLine.off)); off=nextLine.end; // if continuation, concat with line, and continue // if a not - break, the current line will be parsed and // then nextLine will take it's place if (nextLine.off == nextLine.end) { // Empty line, end of headers break; } char firstB=(char)buf[nextLine.off]; if( firstB != ' ' && firstB != '\t' ) break; // normal line line.end=nextLine.end; if(d>0) debug("Continuation: " + firstB + " " + new String( buf, line.off, line.end-line.off)); // continue reading the next line } // XXX this does not currently handle headers which // are folded to take more than one line. if( ! parseHeaderField(headers, buf, line.off, line.end - line.off) ) { // error parsing header return 200; } } return 200; } /** * Parses a header field from a subarray of bytes. * @param b the bytes to parse * @param off the start offset of the bytes * @param len the length of the bytes * @exception IllegalArgumentException if the header format was invalid */ public final boolean parseHeaderField(MimeHeaders headers, byte[] b, int off, int len) { int start = off; byte c; while ((c = b[off++]) != ':' && c != ' ') { if (c == '\n') { loghelper.log("Parse error, empty line: " + new String( b, off, len ), Log.ERROR); return false; } } int nS=start; int nE=off - start - 1; while (c == ' ') { c = b[off++]; } if (c != ':') { loghelper.log("Parse error, missing : in " + new String( b, off, len ), Log.ERROR); loghelper.log("Full " + new String( b, 0, b.length ), Log.ERROR); return false; } while ((c = b[off++]) == ' '); headers.addValue( b, nS, nE). setBytes(b, off-1, len - (off - start - 1)); return true; } /** Parse a request line */ public final int processRequestLine(MessageBytes methodMB, MessageBytes uriMB, MessageBytes queryMB, MessageBytes protocolMB) throws IOException { count = readLine(sin,buf, 0, buf.length); if (count < 0 ) { return 400; } off=0; // if end of line is reached before we scan all 3 components - // we're fine, off=count and remain unchanged if( buf[count-1]!= '\r' && buf[count-1]!= '\n' ) { return 414; //HttpServletResponse.SC_REQUEST_URI_TOO_LONG; } int startMethod=skipSpaces(); int endMethod=findSpace(); int startReq=skipSpaces(); int endReq=findSpace(); int startProto=skipSpaces(); int endProto=findSpace(); if( startReq < 0 ) { // we don't have 2 "words", probably only method // startReq>0 => method is fine, request has at least one char return 400; } methodMB.setBytes( buf, startMethod, endMethod - startMethod ); // optimization - detect common strings, no allocations // buf[startMethod] == 'g' ||, ignoreCase // the idea is that we don't allocate new strings - but set // to constants. ( probably not needed, it's has a tiny impact ) if( buf[startMethod] == 'G') { if( methodMB.equals( "GET" )) methodMB.setString("GET"); } if( buf[startMethod] == 'P' ) { if( methodMB.equals( "POST" )) methodMB.setString("POST"); if( methodMB.equals( "PUT" )) methodMB.setString("PUT"); } if( endReq < 0 ) { endReq=count; } else { if( startProto > 0 ) { if( endProto < 0 ) endProto = count; protocolMB.setBytes( buf, startProto, endProto-startProto); if( protocolMB.equalsIgnoreCase( "http/1.0" )) protocolMB.setString("HTTP/1.0"); if( protocolMB.equalsIgnoreCase( "http/1.1" )) protocolMB.setString("HTTP/1.1"); } else { protocolMB.setString(""); } } int qryIdx= findChar( '?', startReq, endReq ); if( qryIdx <0 ) { uriMB.setBytes(buf, startReq, endReq - startReq ); //= new String( buf, startReq, endReq - startReq ); } else { uriMB.setBytes( buf, startReq, qryIdx - startReq ); queryMB.setBytes( buf, qryIdx+1, endReq - qryIdx -1 ); } // Perform URL decoding only if necessary // if ((uriMB.indexOf('%') >= 0) || (uriMB.indexOf('+') >= 0)) { // try { // uriMB.unescapeURL(); // } catch (Exception e) { // return 400; // } // } // XXX what about query strings ? return 200; } // -------------------- Output methods -------------------- /** Format and send the output headers */ public void sendHeaders(MimeHeaders headers) throws IOException { int count=headers.size(); for( int i=0; i |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.