Return-Path: Delivered-To: apmail-jakarta-tomcat-dev-archive@jakarta.apache.org Received: (qmail 9839 invoked by uid 500); 26 May 2001 17:24:17 -0000 Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: list-post: Reply-To: tomcat-dev@jakarta.apache.org Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 9830 invoked by uid 500); 26 May 2001 17:24:17 -0000 Delivered-To: apmail-jakarta-tomcat-cvs@apache.org Date: 26 May 2001 17:24:17 -0000 Message-ID: <20010526172417.9826.qmail@apache.org> From: costin@apache.org To: jakarta-tomcat-cvs@apache.org Subject: cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/http Parameters.java costin 01/05/26 10:24:17 Modified: src/share/org/apache/tomcat/util/http Parameters.java Log: Few big changes here... The "new" code is now in use ( has been here for few months, but we kept using the old code for safety ). The most important thing is that now we corectly decode ( if charset is provided ) - the old code didn't. There is still some old code in use ( only used by RequestDispatcher), but the common code is now fixed. Revision Changes Path 1.12 +182 -84 jakarta-tomcat/src/share/org/apache/tomcat/util/http/Parameters.java Index: Parameters.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/http/Parameters.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- Parameters.java 2001/02/20 03:14:11 1.11 +++ Parameters.java 2001/05/26 17:24:17 1.12 @@ -59,9 +59,7 @@ package org.apache.tomcat.util.http; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.*; import org.apache.tomcat.util.collections.MultiMap; import java.io.*; import java.util.*; @@ -72,6 +70,7 @@ * @author Costin Manolache */ public final class Parameters extends MultiMap { + // Transition: we'll use the same Hashtable( String->String[] ) // for the beginning. When we are sure all accesses happen through // this class - we can switch to MultiMap @@ -81,6 +80,9 @@ MessageBytes queryMB; MimeHeaders headers; + + UDecoder urlDec; + MessageBytes decodedQuery=new MessageBytes(); public static final int INITIAL_SIZE=4; @@ -94,6 +96,8 @@ private Parameters parent=null; private Parameters currentChild=null; + String encoding=null; + /** * */ @@ -109,12 +113,18 @@ this.headers=headers; } + public void setEncoding( String s ) { + encoding=s; + } + public void recycle() { super.recycle(); paramHashStringArray.clear(); didQueryParameters=false; currentChild=null; didMerge=false; + encoding=null; + decodedQuery.recycle(); } // -------------------- Sub-request support -------------------- @@ -145,11 +155,13 @@ // set child to null ! if( currentChild==null ) { currentChild=new Parameters(); + currentChild.setURLDecoder( urlDec ); currentChild.parent=this; return; } if( currentChild.child==null ) { currentChild.child=new Parameters(); + currentChild.setURLDecoder( urlDec ); currentChild.child.parent=currentChild; } // it is not null if this object already had a child // i.e. a deeper include() ( we keep it ) @@ -205,9 +217,10 @@ */ private void merge() { // recursive - // System.out.println("Merging " + this + " with " + - // parent + " " + didMerge); - //System.out.println( "Before " + paramsAsString()); + if( debug > 0 ) { + log("Before merging " + this + " " + parent + " " + didMerge ); + log( paramsAsString()); + } // Local parameters first - they take precedence as in spec. handleQueryParameters(); @@ -222,7 +235,8 @@ Hashtable parentProps=parent.paramHashStringArray; merge2( paramHashStringArray , parentProps); didMerge=true; - //System.out.println( "After " + paramsAsString()); + if(debug > 0 ) + log("After " + paramsAsString()); } @@ -231,54 +245,34 @@ String[] values = getParameterValues(name); if (values != null) { if( values.length==0 ) return ""; - //System.out.println("XXX " + name + "=" + values[0] ); return values[0]; } else { - // System.out.println("XXX " + name + "=null" ); return null; } } // -------------------- Processing -------------------- - /** Process the query string into parameters */ public void handleQueryParameters() { if( didQueryParameters ) return; didQueryParameters=true; - if( queryMB==null ) + if( debug > 0 ) + log( "Decoding query " + queryMB + " " + encoding); + + if( queryMB==null || queryMB.isNull() ) return; - String qString=queryMB.toString(); - if(qString!=null) { - processFormData( qString ); - } - } - - public void processParameters(String data) { - processFormData( data ); - } - - // XXX ENCODING !! - public void processData(byte data[]) { - // make sure the request line query is processed - handleQueryParameters(); try { - String postedBody = new String(data, 0, data.length, - "8859_1"); - // XXX encoding !!! - - processFormData( postedBody ); - - //Hashtable postParameters=new Hashtable(); - //Parameters.processFormData( postedBody, postParameters); - // Parameters.merge2(paramHashStringArray, postParameters); - - } catch( UnsupportedEncodingException ex ) { - // return postParameters; + decodedQuery.duplicate( queryMB ); + } catch( IOException ex ) { } + if( debug > 0 ) + log( "Decoding query " + decodedQuery + " " + encoding); + + processParameters( decodedQuery ); } - + // -------------------- /** Combine 2 hashtables into a new one. @@ -315,51 +309,50 @@ } } - // XXX XXX Optimize - private void processFormData(String data) { - // there's got to be a faster way of doing this. - if( data==null ) return; // no parameters - - StringTokenizer tok = new StringTokenizer(data, "&", false); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int pos = pair.indexOf('='); - if (pos != -1) { - String key = CharChunk.unescapeURL(pair.substring(0, pos)); - String value = CharChunk.unescapeURL(pair.substring(pos+1, - pair.length())); - String values[]; - if (paramHashStringArray.containsKey(key)) { - String oldValues[] = (String[])paramHashStringArray. - get(key); - values = new String[oldValues.length + 1]; - for (int i = 0; i < oldValues.length; i++) { - values[i] = oldValues[i]; - } - values[oldValues.length] = value; - } else { - values = new String[1]; - values[0] = value; - } - paramHashStringArray.put(key, values); - } else { - // we don't have a valid chunk of form data, ignore + // incredibly inefficient data representation for parameters, + // until we test the new one + private void addParam( String key, String value ) { + String values[]; + if (paramHashStringArray.containsKey(key)) { + String oldValues[] = (String[])paramHashStringArray. + get(key); + values = new String[oldValues.length + 1]; + for (int i = 0; i < oldValues.length; i++) { + values[i] = oldValues[i]; } - } + values[oldValues.length] = value; + } else { + values = new String[1]; + values[0] = value; + } + + + paramHashStringArray.put(key, values); + } + + public void setURLDecoder( UDecoder u ) { + urlDec=u; } // -------------------- Parameter parsing -------------------- // This code is not used right now - it's the optimized version - // of the above. + // of the above. + + // we are called from a single thread - we can do it the hard way + // if needed + ByteChunk tmpName=new ByteChunk(); + ByteChunk tmpValue=new ByteChunk(); + CharChunk tmpNameC=new CharChunk(1024); + CharChunk tmpValueC=new CharChunk(1024); - /** - * - */ public void processParameters( byte bytes[], int start, int len ) { int end=start+len; int pos=start; + if( debug>0 ) + log( "Bytes: " + new String( bytes, start, len )); + do { int nameStart=pos; int nameEnd=ByteChunk.indexOf(bytes, nameStart, end, '=' ); @@ -376,12 +369,32 @@ // invalid chunk - it's better to ignore // XXX log it ? } + tmpName.setBytes( bytes, nameStart, nameEnd-nameStart ); + tmpValue.setBytes( bytes, valStart, valEnd-valStart ); + tmpName.setEncoding( encoding ); + tmpValue.setEncoding( encoding ); - int field=this.addField(); - this.getName( field ).setBytes( bytes, - nameStart, nameEnd ); - this.getValue( field ).setBytes( bytes, - valStart, valEnd ); + try { + if( debug > 0 ) + log( tmpName + "= " + tmpValue); + + if( urlDec==null ) { + urlDec=new UDecoder(); + } + urlDec.convert( tmpName ); + urlDec.convert( tmpValue ); + + if( debug > 0 ) + log( tmpName + "= " + tmpValue); + + addParam( tmpName.toString(), tmpValue.toString() ); + } catch( IOException ex ) { + ex.printStackTrace(); + } + + tmpName.recycle(); + tmpValue.recycle(); + } while( pos0 ) + log( "Chars: " + new String( chars, start, len )); do { int nameStart=pos; int nameEnd=CharChunk.indexOf(chars, nameStart, end, '=' ); @@ -405,17 +420,36 @@ // XXX log it ? } - int field=this.addField(); - this.getName( field ).setChars( chars, - nameStart, nameEnd ); - this.getValue( field ).setChars( chars, - valStart, valEnd ); + try { + tmpNameC.append( chars, nameStart, nameEnd-nameStart ); + tmpValueC.append( chars, valStart, valEnd-valStart ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + if( urlDec==null ) { + urlDec=new UDecoder(); + } + + urlDec.convert( tmpNameC ); + urlDec.convert( tmpValueC ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + addParam( tmpNameC.toString(), tmpValueC.toString() ); + } catch( IOException ex ) { + ex.printStackTrace(); + } + + tmpNameC.recycle(); + tmpValueC.recycle(); + } while( pos 0) + log("String: " + str ); + + do { + int nameStart=pos; + int nameEnd=str.indexOf('=', nameStart ); + if( nameEnd== -1 ) nameEnd=end; + + int valStart=nameEnd+1; + int valEnd=str.indexOf('&', valStart); + if( valEnd== -1 ) valEnd=end; + pos=valEnd+1; + + if( nameEnd<=nameStart ) { + continue; + } + if( debug>0) + log( "XXX " + nameStart + " " + nameEnd + " " + + valStart + " " + valEnd ); + + try { + tmpNameC.append(str, nameStart, nameEnd-nameStart ); + tmpValueC.append(str, valStart, valEnd-valStart ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + if( urlDec==null ) { + urlDec=new UDecoder(); + } + + urlDec.convert( tmpNameC ); + urlDec.convert( tmpValueC ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + addParam( tmpNameC.toString(), tmpValueC.toString() ); + } catch( IOException ex ) { + ex.printStackTrace(); + } + + tmpNameC.recycle(); + tmpValueC.recycle(); + + } while( pos