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 2008/03/25 07:01:57 UTC
svn commit: r640706 [6/12] - in /tomcat/sandbox/tomcat-lite/tomcat-coyote:
./ org/ org/apache/ org/apache/coyote/ org/apache/coyote/http11/
org/apache/coyote/http11/filters/ org/apache/juli/ org/apache/juli/logging/
org/apache/tomcat/ org/apache/tomcat...
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.collections;
+
+import java.util.Enumeration;
+
+/** Enumerate the distinct header names.
+ Each nextElement() is O(n) ( a comparation is
+ done with all previous elements ).
+
+ This is less frequesnt than add() -
+ we want to keep add O(1).
+*/
+public final class MultiMapNamesEnumeration implements Enumeration {
+ int pos;
+ int size;
+ String next;
+ MultiMap headers;
+
+ // toString and unique options are not implemented -
+ // we allways to toString and unique.
+
+ /** Create a new multi-map enumeration.
+ * @param headers the collection to enumerate
+ * @param toString convert each name to string
+ * @param unique return only unique names
+ */
+ MultiMapNamesEnumeration(MultiMap headers, boolean toString,
+ boolean unique) {
+ this.headers=headers;
+ pos=0;
+ size = headers.size();
+ findNext();
+ }
+
+ private void findNext() {
+ next=null;
+ for( ; pos< size; pos++ ) {
+ next=headers.getName( pos ).toString();
+ for( int j=0; j<pos ; j++ ) {
+ if( headers.getName( j ).equalsIgnoreCase( next )) {
+ // duplicate.
+ next=null;
+ break;
+ }
+ }
+ if( next!=null ) {
+ // it's not a duplicate
+ break;
+ }
+ }
+ // next time findNext is called it will try the
+ // next element
+ pos++;
+ }
+
+ public boolean hasMoreElements() {
+ return next!=null;
+ }
+
+ public Object nextElement() {
+ String current=next;
+ findNext();
+ return current;
+ }
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.collections;
+
+import java.util.Enumeration;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/** Enumerate the values for a (possibly ) multiple
+ * value element.
+ */
+class MultiMapValuesEnumeration implements Enumeration {
+ int pos;
+ int size;
+ MessageBytes next;
+ MultiMap headers;
+ String name;
+
+ MultiMapValuesEnumeration(MultiMap headers, String name,
+ boolean toString) {
+ this.name=name;
+ this.headers=headers;
+ pos=0;
+ size = headers.size();
+ findNext();
+ }
+
+ private void findNext() {
+ next=null;
+ for( ; pos< size; pos++ ) {
+ MessageBytes n1=headers.getName( pos );
+ if( n1.equalsIgnoreCase( name )) {
+ next=headers.getValue( pos );
+ break;
+ }
+ }
+ pos++;
+ }
+
+ public boolean hasMoreElements() {
+ return next!=null;
+ }
+
+ public Object nextElement() {
+ MessageBytes current=next;
+ findNext();
+ return current.toString();
+ }
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/Queue.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/Queue.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/Queue.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/Queue.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.collections;
+
+import java.util.Vector;
+
+/**
+ * A simple FIFO queue class which causes the calling thread to wait
+ * if the queue is empty and notifies threads that are waiting when it
+ * is not empty.
+ *
+ * @author Anil V (akv@eng.sun.com)
+ */
+public class Queue {
+ private Vector vector = new Vector();
+ private boolean stopWaiting=false;
+ private boolean waiting=false;
+
+ /**
+ * Put the object into the queue.
+ *
+ * @param object the object to be appended to the
+ * queue.
+ */
+ public synchronized void put(Object object) {
+ vector.addElement(object);
+ notify();
+ }
+
+ /** Break the pull(), allowing the calling thread to exit
+ */
+ public synchronized void stop() {
+ stopWaiting=true;
+ // just a hack to stop waiting
+ if( waiting ) notify();
+ }
+
+ /**
+ * Pull the first object out of the queue. Wait if the queue is
+ * empty.
+ */
+ public synchronized Object pull() {
+ while (isEmpty()) {
+ try {
+ waiting=true;
+ wait();
+ } catch (InterruptedException ex) {
+ }
+ waiting=false;
+ if( stopWaiting ) return null;
+ }
+ return get();
+ }
+
+ /**
+ * Get the first object out of the queue. Return null if the queue
+ * is empty.
+ */
+ public synchronized Object get() {
+ Object object = peek();
+ if (object != null)
+ vector.removeElementAt(0);
+ return object;
+ }
+
+ /**
+ * Peek to see if something is available.
+ */
+ public Object peek() {
+ if (isEmpty())
+ return null;
+ return vector.elementAt(0);
+ }
+
+ /**
+ * Is the queue empty?
+ */
+ public boolean isEmpty() {
+ return vector.isEmpty();
+ }
+
+ /**
+ * How many elements are there in this queue?
+ */
+ public int size() {
+ return vector.size();
+ }
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimpleHashtable.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimpleHashtable.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimpleHashtable.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimpleHashtable.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.collections;
+
+import java.util.Enumeration;
+
+/* **************************************** Stolen from Crimson ******************** */
+/* From Crimson/Parser - in a perfect world we'll just have a common set of
+ utilities, and all apache project will just use those.
+
+*/
+
+// can't be replaced using a Java 2 "Collections" API
+// since this package must also run on JDK 1.1
+
+
+/**
+ * This class implements a special purpose hashtable. It works like a
+ * normal <code>java.util.Hashtable</code> except that: <OL>
+ *
+ * <LI> Keys to "get" are strings which are known to be interned,
+ * so that "==" is used instead of "String.equals". (Interning
+ * could be document-relative instead of global.)
+ *
+ * <LI> It's not synchronized, since it's to be used only by
+ * one thread at a time.
+ *
+ * <LI> The keys () enumerator allocates no memory, with live
+ * updates to the data disallowed.
+ *
+ * <LI> It's got fewer bells and whistles: fixed threshold and
+ * load factor, no JDK 1.2 collection support, only keys can be
+ * enumerated, things can't be removed, simpler inheritance; more.
+ *
+ * </OL>
+ *
+ * <P> The overall result is that it's less expensive to use these in
+ * performance-critical locations, in terms both of CPU and memory,
+ * than <code>java.util.Hashtable</code> instances. In this package
+ * it makes a significant difference when normalizing attributes,
+ * which is done for each start-element construct.
+ *
+ */
+public final class SimpleHashtable implements Enumeration
+{
+
+ private static org.apache.juli.logging.Log log=
+ org.apache.juli.logging.LogFactory.getLog( SimpleHashtable.class );
+
+ // entries ...
+ private Entry table[];
+
+ // currently enumerated key
+ private Entry current = null;
+ private int currentBucket = 0;
+
+ // number of elements in hashtable
+ private int count;
+ private int threshold;
+
+ private static final float loadFactor = 0.75f;
+
+
+ /**
+ * Constructs a new, empty hashtable with the specified initial
+ * capacity.
+ *
+ * @param initialCapacity the initial capacity of the hashtable.
+ */
+ public SimpleHashtable(int initialCapacity) {
+ if (initialCapacity < 0)
+ throw new IllegalArgumentException("Illegal Capacity: "+
+ initialCapacity);
+ if (initialCapacity==0)
+ initialCapacity = 1;
+ table = new Entry[initialCapacity];
+ threshold = (int)(initialCapacity * loadFactor);
+ }
+
+ /**
+ * Constructs a new, empty hashtable with a default capacity.
+ */
+ public SimpleHashtable() {
+ this(11);
+ }
+
+ /**
+ */
+ public void clear ()
+ {
+ count = 0;
+ currentBucket = 0;
+ current = null;
+ for (int i = 0; i < table.length; i++)
+ table [i] = null;
+ }
+
+ /**
+ * Returns the number of keys in this hashtable.
+ *
+ * @return the number of keys in this hashtable.
+ */
+ public int size() {
+ return count;
+ }
+
+ /**
+ * Returns an enumeration of the keys in this hashtable.
+ *
+ * @return an enumeration of the keys in this hashtable.
+ * @see Enumeration
+ */
+ public Enumeration keys() {
+ currentBucket = 0;
+ current = null;
+ hasMoreElements();
+ return this;
+ }
+
+ /**
+ * Used to view this as an enumeration; returns true if there
+ * are more keys to be enumerated.
+ */
+ public boolean hasMoreElements ()
+ {
+ if (current != null)
+ return true;
+ while (currentBucket < table.length) {
+ current = table [currentBucket++];
+ if (current != null)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Used to view this as an enumeration; returns the next key
+ * in the enumeration.
+ */
+ public Object nextElement ()
+ {
+ Object retval;
+
+ if (current == null)
+ throw new IllegalStateException ();
+ retval = current.key;
+ current = current.next;
+ // Advance to the next position ( we may call next after next,
+ // without hasMore )
+ hasMoreElements();
+ return retval;
+ }
+
+
+ /**
+ * Returns the value to which the specified key is mapped in this hashtable.
+ */
+ public Object getInterned (String key) {
+ Entry tab[] = table;
+ int hash = key.hashCode();
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index] ; e != null ; e = e.next) {
+ if ((e.hash == hash) && (e.key == key))
+ return e.value;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the value to which the specified key is mapped in this
+ * hashtable ... the key isn't necessarily interned, though.
+ */
+ public Object get(String key) {
+ Entry tab[] = table;
+ int hash = key.hashCode();
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index] ; e != null ; e = e.next) {
+ if ((e.hash == hash) && e.key.equals(key))
+ return e.value;
+ }
+ return null;
+ }
+
+ /**
+ * Increases the capacity of and internally reorganizes this
+ * hashtable, in order to accommodate and access its entries more
+ * efficiently. This method is called automatically when the
+ * number of keys in the hashtable exceeds this hashtable's capacity
+ * and load factor.
+ */
+ private void rehash() {
+ int oldCapacity = table.length;
+ Entry oldMap[] = table;
+
+ int newCapacity = oldCapacity * 2 + 1;
+ Entry newMap[] = new Entry[newCapacity];
+
+ threshold = (int)(newCapacity * loadFactor);
+ table = newMap;
+
+ /*
+ System.out.pr intln("rehash old=" + oldCapacity
+ + ", new=" + newCapacity
+ + ", thresh=" + threshold
+ + ", count=" + count);
+ */
+
+ for (int i = oldCapacity ; i-- > 0 ;) {
+ for (Entry old = oldMap[i] ; old != null ; ) {
+ Entry e = old;
+ old = old.next;
+
+ int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+ e.next = newMap[index];
+ newMap[index] = e;
+ }
+ }
+ }
+
+ /**
+ * Maps the specified <code>key</code> to the specified
+ * <code>value</code> in this hashtable. Neither the key nor the
+ * value can be <code>null</code>.
+ *
+ * <P>The value can be retrieved by calling the <code>get</code> method
+ * with a key that is equal to the original key.
+ */
+ public Object put(Object key, Object value) {
+ // Make sure the value is not null
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ // Makes sure the key is not already in the hashtable.
+ Entry tab[] = table;
+ int hash = key.hashCode();
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index] ; e != null ; e = e.next) {
+ // if ((e.hash == hash) && e.key.equals(key)) {
+ if ((e.hash == hash) && (e.key == key)) {
+ Object old = e.value;
+ e.value = value;
+ return old;
+ }
+ }
+
+ if (count >= threshold) {
+ // Rehash the table if the threshold is exceeded
+ rehash();
+
+ tab = table;
+ index = (hash & 0x7FFFFFFF) % tab.length;
+ }
+
+ // Creates the new entry.
+ Entry e = new Entry(hash, key, value, tab[index]);
+ tab[index] = e;
+ count++;
+ return null;
+ }
+
+ public Object remove(Object key) {
+ Entry tab[] = table;
+ Entry prev=null;
+ int hash = key.hashCode();
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ if( dL > 0 ) d("Idx " + index + " " + tab[index] );
+ for (Entry e = tab[index] ; e != null ; prev=e, e = e.next) {
+ if( dL > 0 ) d("> " + prev + " " + e.next + " " + e + " " + e.key);
+ if ((e.hash == hash) && e.key.equals(key)) {
+ if( prev!=null ) {
+ prev.next=e.next;
+ } else {
+ tab[index]=e.next;
+ }
+ if( dL > 0 ) d("Removing from list " + tab[index] + " " + prev +
+ " " + e.value);
+ count--;
+ Object res=e.value;
+ e.value=null;
+ return res;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Hashtable collision list.
+ */
+ private static class Entry {
+ int hash;
+ Object key;
+ Object value;
+ Entry next;
+
+ protected Entry(int hash, Object key, Object value, Entry next) {
+ this.hash = hash;
+ this.key = key;
+ this.value = value;
+ this.next = next;
+ }
+ }
+
+ private static final int dL=0;
+ private void d(String s ) {
+ if (log.isDebugEnabled())
+ log.debug( "SimpleHashtable: " + s );
+ }
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimplePool.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimplePool.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimplePool.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/SimplePool.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.collections;
+
+/**
+ * Simple object pool. Based on ThreadPool and few other classes
+ *
+ * The pool will ignore overflow and return null if empty.
+ *
+ * @author Gal Shachor
+ * @author Costin Manolache
+ */
+public final class SimplePool {
+
+
+ private static org.apache.juli.logging.Log log=
+ org.apache.juli.logging.LogFactory.getLog(SimplePool.class );
+
+ /*
+ * Where the threads are held.
+ */
+ private Object pool[];
+
+ private int max;
+ private int last;
+ private int current=-1;
+
+ private Object lock;
+ public static final int DEFAULT_SIZE=32;
+ static final int debug=0;
+
+ public SimplePool() {
+ this(DEFAULT_SIZE,DEFAULT_SIZE);
+ }
+
+ public SimplePool(int size) {
+ this(size, size);
+ }
+
+ public SimplePool(int size, int max) {
+ this.max=max;
+ pool=new Object[size];
+ this.last=size-1;
+ lock=new Object();
+ }
+
+ public void set(Object o) {
+ put(o);
+ }
+
+ /**
+ * Add the object to the pool, silent nothing if the pool is full
+ */
+ public void put(Object o) {
+ synchronized( lock ) {
+ if( current < last ) {
+ current++;
+ pool[current] = o;
+ } else if( current < max ) {
+ // realocate
+ int newSize=pool.length*2;
+ if( newSize > max ) newSize=max+1;
+ Object tmp[]=new Object[newSize];
+ last=newSize-1;
+ System.arraycopy( pool, 0, tmp, 0, pool.length);
+ pool=tmp;
+ current++;
+ pool[current] = o;
+ }
+ if( debug > 0 ) log("put " + o + " " + current + " " + max );
+ }
+ }
+
+ /**
+ * Get an object from the pool, null if the pool is empty.
+ */
+ public Object get() {
+ Object item = null;
+ synchronized( lock ) {
+ if( current >= 0 ) {
+ item = pool[current];
+ pool[current] = null;
+ current -= 1;
+ }
+ if( debug > 0 )
+ log("get " + item + " " + current + " " + max);
+ }
+ return item;
+ }
+
+ /**
+ * Return the size of the pool
+ */
+ public int getMax() {
+ return max;
+ }
+
+ /**
+ * Number of object in the pool
+ */
+ public int getCount() {
+ return current+1;
+ }
+
+
+ public void shutdown() {
+ }
+
+ private void log( String s ) {
+ if (log.isDebugEnabled())
+ log.debug("SimplePool: " + s );
+ }
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/package.html
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/package.html?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/package.html (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/collections/package.html Mon Mar 24 23:01:43 2008
@@ -0,0 +1,33 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<html>
+<head>
+<title>util.collections</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<h1>Specialized collections</h1>
+
+This package includes a number of special collections, tunned for server-side
+applications.
+
+The utils are not tomcat specific, but use MessageBytes and few other
+top-level utils.
+
+</body>
+</html>
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/AcceptLanguage.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/AcceptLanguage.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/AcceptLanguage.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/AcceptLanguage.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.http;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Util to process the "Accept-Language" header. Used by facade to implement
+ * getLocale() and by StaticInterceptor.
+ *
+ * Not optimized - it's very slow.
+ *
+ * @author James Duncan Davidson [duncan@eng.sun.com]
+ * @author James Todd [gonzo@eng.sun.com]
+ * @author Jason Hunter [jch@eng.sun.com]
+ * @author Harish Prabandham
+ * @author costin@eng.sun.com
+ */
+public class AcceptLanguage {
+
+ public static Locale getLocale(String acceptLanguage) {
+ if( acceptLanguage == null ) return Locale.getDefault();
+
+ Hashtable<String,Vector<String>> languages =
+ new Hashtable<String,Vector<String>>();
+ Vector<Double> quality = new Vector<Double>();
+ processAcceptLanguage(acceptLanguage, languages, quality);
+
+ if (languages.size() == 0) return Locale.getDefault();
+
+ Vector<Locale> l = new Vector<Locale>();
+ extractLocales( languages,quality, l);
+
+ return (Locale)l.elementAt(0);
+ }
+
+ public static Enumeration getLocales(String acceptLanguage) {
+ // Short circuit with an empty enumeration if null header
+ if (acceptLanguage == null) {
+ Vector<Locale> v = new Vector<Locale>();
+ v.addElement(Locale.getDefault());
+ return v.elements();
+ }
+
+ Hashtable<String,Vector<String>> languages =
+ new Hashtable<String,Vector<String>>();
+ Vector<Double> quality=new Vector<Double>();
+ processAcceptLanguage(acceptLanguage, languages , quality);
+
+ if (languages.size() == 0) {
+ Vector<Locale> v = new Vector<Locale>();
+ v.addElement(Locale.getDefault());
+ return v.elements();
+ }
+ Vector<Locale> l = new Vector<Locale>();
+ extractLocales( languages, quality , l);
+ return l.elements();
+ }
+
+ private static void processAcceptLanguage( String acceptLanguage,
+ Hashtable<String,Vector<String>> languages, Vector<Double> q)
+ {
+ StringTokenizer languageTokenizer =
+ new StringTokenizer(acceptLanguage, ",");
+
+ while (languageTokenizer.hasMoreTokens()) {
+ String language = languageTokenizer.nextToken().trim();
+ int qValueIndex = language.indexOf(';');
+ int qIndex = language.indexOf('q');
+ int equalIndex = language.indexOf('=');
+ Double qValue = new Double(1);
+
+ if (qValueIndex > -1 &&
+ qValueIndex < qIndex &&
+ qIndex < equalIndex) {
+ String qValueStr = language.substring(qValueIndex + 1);
+ language = language.substring(0, qValueIndex);
+ qValueStr = qValueStr.trim().toLowerCase();
+ qValueIndex = qValueStr.indexOf('=');
+ qValue = new Double(0);
+ if (qValueStr.startsWith("q") &&
+ qValueIndex > -1) {
+ qValueStr = qValueStr.substring(qValueIndex + 1);
+ try {
+ qValue = new Double(qValueStr.trim());
+ } catch (NumberFormatException nfe) {
+ }
+ }
+ }
+
+ // XXX
+ // may need to handle "*" at some point in time
+
+ if (! language.equals("*")) {
+ String key = qValue.toString();
+ Vector<String> v;
+ if (languages.containsKey(key)) {
+ v = languages.get(key) ;
+ } else {
+ v= new Vector<String>();
+ q.addElement(qValue);
+ }
+ v.addElement(language);
+ languages.put(key, v);
+ }
+ }
+ }
+
+ private static void extractLocales(Hashtable languages, Vector q,
+ Vector<Locale> l)
+ {
+ // XXX We will need to order by q value Vector in the Future ?
+ Enumeration e = q.elements();
+ while (e.hasMoreElements()) {
+ Vector v =
+ (Vector)languages.get(((Double)e.nextElement()).toString());
+ Enumeration le = v.elements();
+ while (le.hasMoreElements()) {
+ String language = (String)le.nextElement();
+ String country = "";
+ int countryIndex = language.indexOf("-");
+ if (countryIndex > -1) {
+ country = language.substring(countryIndex + 1).trim();
+ language = language.substring(0, countryIndex).trim();
+ }
+ l.addElement(new Locale(language, country));
+ }
+ }
+ }
+
+
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/BaseRequest.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/BaseRequest.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/BaseRequest.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/BaseRequest.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,346 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/***************************************************************************
+ * Description: Base http request object. *
+ * Author: Keving Seguin [seguin@apache.org] *
+ * Version: $Revision: 553700 $ *
+ ***************************************************************************/
+
+package org.apache.tomcat.util.http;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * A general-purpose object for representing an HTTP
+ * request.
+ */
+public class BaseRequest {
+
+ // scheme constants
+ public static final String SCHEME_HTTP = "http";
+ public static final String SCHEME_HTTPS = "https";
+
+ // request attributes
+ MessageBytes method = MessageBytes.newInstance();
+ MessageBytes protocol = MessageBytes.newInstance();
+ MessageBytes requestURI = MessageBytes.newInstance();
+ MessageBytes remoteAddr = MessageBytes.newInstance();
+ MessageBytes remoteHost = MessageBytes.newInstance();
+ MessageBytes serverName = MessageBytes.newInstance();
+ int serverPort = 80;
+ MessageBytes remoteUser = MessageBytes.newInstance();
+ MessageBytes authType = MessageBytes.newInstance();
+ MessageBytes queryString = MessageBytes.newInstance();
+ MessageBytes authorization = MessageBytes.newInstance();
+ String scheme = SCHEME_HTTP;
+ boolean secure = false;
+ int contentLength = 0;
+ MessageBytes contentType = MessageBytes.newInstance();
+ MimeHeaders headers = new MimeHeaders();
+ Cookies cookies = new Cookies();
+ HashMap<String,Object> attributes = new HashMap<String,Object>();
+
+ MessageBytes tomcatInstanceId = MessageBytes.newInstance();
+
+ /**
+ * Recycles this object and readies it further use.
+ */
+ public void recycle() {
+ method.recycle();
+ protocol.recycle();
+ requestURI.recycle();
+ remoteAddr.recycle();
+ remoteHost.recycle();
+ serverName.recycle();
+ serverPort = 80;
+ remoteUser.recycle();
+ authType.recycle();
+ queryString.recycle();
+ authorization.recycle();
+ scheme = SCHEME_HTTP;
+ secure = false;
+ contentLength = 0;
+ contentType.recycle();
+ headers.recycle();
+ cookies.recycle();
+ attributes.clear();
+ tomcatInstanceId.recycle();
+ }
+
+ /**
+ * Get the method.
+ * @return the method
+ */
+ public MessageBytes method() {
+ return method;
+ }
+
+ /**
+ * Get the protocol
+ * @return the protocol
+ */
+ public MessageBytes protocol() {
+ return protocol;
+ }
+
+ /**
+ * Get the request uri
+ * @return the request uri
+ */
+ public MessageBytes requestURI() {
+ return requestURI;
+ }
+
+ /**
+ * Get the remote address
+ * @return the remote address
+ */
+ public MessageBytes remoteAddr() {
+ return remoteAddr;
+ }
+
+ /**
+ * Get the remote host
+ * @return the remote host
+ */
+ public MessageBytes remoteHost() {
+ return remoteHost;
+ }
+
+ /**
+ * Get the server name
+ * @return the server name
+ */
+ public MessageBytes serverName() {
+ return serverName;
+ }
+
+ /**
+ * Get the server port
+ * @return the server port
+ */
+ public int getServerPort() {
+ return serverPort;
+ }
+
+ /**
+ * Set the server port
+ * @param i the server port
+ */
+ public void setServerPort(int i) {
+ serverPort = i;
+ }
+
+ /**
+ * Get the remote user
+ * @return the remote user
+ */
+ public MessageBytes remoteUser() {
+ return remoteUser;
+ }
+
+ /**
+ * Get the auth type
+ * @return the auth type
+ */
+ public MessageBytes authType() {
+ return authType;
+ }
+
+ /**
+ * Get the query string
+ * @return the query string
+ */
+ public MessageBytes queryString() {
+ return queryString;
+ }
+
+ /**
+ * Get the authorization credentials
+ * @return the authorization credentials
+ */
+ public MessageBytes authorization() {
+ return authorization;
+ }
+
+ /**
+ * Get the scheme
+ * @return the scheme
+ */
+ public String getScheme() {
+ return scheme;
+ }
+
+ /**
+ * Set the scheme.
+ * @param s the scheme
+ */
+ public void setScheme(String s) {
+ scheme = s;
+ }
+
+ /**
+ * Get whether the request is secure or not.
+ * @return <code>true</code> if the request is secure.
+ */
+ public boolean getSecure() {
+ return secure;
+ }
+
+ /**
+ * Set whether the request is secure or not.
+ * @param b <code>true</code> if the request is secure.
+ */
+ public void setSecure(boolean b) {
+ secure = b;
+ }
+
+ /**
+ * Get the content length
+ * @return the content length
+ */
+ public int getContentLength() {
+ return contentLength;
+ }
+
+ /**
+ * Set the content length
+ * @param i the content length
+ */
+ public void setContentLength(int i) {
+ contentLength = i;
+ }
+
+ /**
+ * Get the content type
+ * @return the content type
+ */
+ public MessageBytes contentType() {
+ return contentType;
+ }
+
+ /**
+ * Get this request's headers
+ * @return request headers
+ */
+ public MimeHeaders headers() {
+ return headers;
+ }
+
+ /**
+ * Get cookies.
+ * @return request cookies.
+ */
+ public Cookies cookies() {
+ return cookies;
+ }
+
+ /**
+ * Set an attribute on the request
+ * @param name attribute name
+ * @param value attribute value
+ */
+ public void setAttribute(String name, Object value) {
+ if (name == null || value == null) {
+ return;
+ }
+ attributes.put(name, value);
+ }
+
+ /**
+ * Get an attribute on the request
+ * @param name attribute name
+ * @return attribute value
+ */
+ public Object getAttribute(String name) {
+ if (name == null) {
+ return null;
+ }
+
+ return attributes.get(name);
+ }
+
+ /**
+ * Get iterator over attribute names
+ * @return iterator over attribute names
+ */
+ public Iterator getAttributeNames() {
+ return attributes.keySet().iterator();
+ }
+
+ /**
+ * Get the host id ( or jvmRoute )
+ * @return the jvm route
+ */
+ public MessageBytes instanceId() {
+ return tomcatInstanceId;
+ }
+
+ // backward compat - jvmRoute is the id of this tomcat instance,
+ // used by a load balancer on the server side to implement sticky
+ // sessions, and on the tomcat side to format the session ids.
+ public MessageBytes jvmRoute() {
+ return tomcatInstanceId;
+ }
+
+ private Object notes[]=new Object[16];
+
+ public final Object getNote(int id) {
+ return notes[id];
+ }
+
+ public final void setNote(int id, Object cr) {
+ notes[id]=cr;
+ }
+
+ /**
+ * ** SLOW ** for debugging only!
+ */
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+
+ pw.println("=== BaseRequest ===");
+ pw.println("method = " + method.toString());
+ pw.println("protocol = " + protocol.toString());
+ pw.println("requestURI = " + requestURI.toString());
+ pw.println("remoteAddr = " + remoteAddr.toString());
+ pw.println("remoteHost = " + remoteHost.toString());
+ pw.println("serverName = " + serverName.toString());
+ pw.println("serverPort = " + serverPort);
+ pw.println("remoteUser = " + remoteUser.toString());
+ pw.println("authType = " + authType.toString());
+ pw.println("queryString = " + queryString.toString());
+ pw.println("scheme = " + scheme.toString());
+ pw.println("secure = " + secure);
+ pw.println("contentLength = " + contentLength);
+ pw.println("contentType = " + contentType);
+ pw.println("attributes = " + attributes.toString());
+ pw.println("headers = " + headers.toString());
+ pw.println("cookies = " + cookies.toString());
+ pw.println("jvmRoute = " + tomcatInstanceId.toString());
+ return sw.toString();
+ }
+
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/ContentType.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/ContentType.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/ContentType.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/ContentType.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.http;
+
+
+/**
+ * Usefull methods for Content-Type processing
+ *
+ * @author James Duncan Davidson [duncan@eng.sun.com]
+ * @author James Todd [gonzo@eng.sun.com]
+ * @author Jason Hunter [jch@eng.sun.com]
+ * @author Harish Prabandham
+ * @author costin@eng.sun.com
+ */
+public class ContentType {
+
+ /**
+ * Parse the character encoding from the specified content type header.
+ * If the content type is null, or there is no explicit character encoding,
+ * <code>null</code> is returned.
+ *
+ * @param contentType a content type header
+ */
+ public static String getCharsetFromContentType(String contentType) {
+
+ if (contentType == null)
+ return (null);
+ int start = contentType.indexOf("charset=");
+ if (start < 0)
+ return (null);
+ String encoding = contentType.substring(start + 8);
+ int end = encoding.indexOf(';');
+ if (end >= 0)
+ encoding = encoding.substring(0, end);
+ encoding = encoding.trim();
+ if ((encoding.length() > 2) && (encoding.startsWith("\""))
+ && (encoding.endsWith("\"")))
+ encoding = encoding.substring(1, encoding.length() - 1);
+ return (encoding.trim());
+
+ }
+
+
+ /**
+ * Returns true if the given content type contains a charset component,
+ * false otherwise.
+ *
+ * @param type Content type
+ * @return true if the given content type contains a charset component,
+ * false otherwise
+ */
+ public static boolean hasCharset(String type) {
+
+ boolean hasCharset = false;
+
+ int len = type.length();
+ int index = type.indexOf(';');
+ while (index != -1) {
+ index++;
+ while (index < len && Character.isSpace(type.charAt(index))) {
+ index++;
+ }
+ if (index+8 < len
+ && type.charAt(index) == 'c'
+ && type.charAt(index+1) == 'h'
+ && type.charAt(index+2) == 'a'
+ && type.charAt(index+3) == 'r'
+ && type.charAt(index+4) == 's'
+ && type.charAt(index+5) == 'e'
+ && type.charAt(index+6) == 't'
+ && type.charAt(index+7) == '=') {
+ hasCharset = true;
+ break;
+ }
+ index = type.indexOf(';', index);
+ }
+
+ return hasCharset;
+ }
+
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/Cookies.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/Cookies.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/Cookies.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/Cookies.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,587 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.http;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.StringTokenizer;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * A collection of cookies - reusable and tuned for server side performance.
+ * Based on RFC2965 ( and 2109 )
+ *
+ * This class is not synchronized.
+ *
+ * @author Costin Manolache
+ * @author kevin seguin
+ */
+public final class Cookies { // extends MultiMap {
+
+ private static org.apache.juli.logging.Log log=
+ org.apache.juli.logging.LogFactory.getLog(Cookies.class );
+
+ // expected average number of cookies per request
+ public static final int INITIAL_SIZE=4;
+ ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE];
+ int cookieCount=0;
+ boolean unprocessed=true;
+
+ MimeHeaders headers;
+
+ /*
+ List of Separator Characters (see isSeparator())
+ Excluding the '/' char violates the RFC, but
+ it looks like a lot of people put '/'
+ in unquoted values: '/': ; //47
+ '\t':9 ' ':32 '\"':34 '\'':39 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60
+ '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
+ */
+ public static final char SEPARATORS[] = { '\t', ' ', '\"', '\'', '(', ')', ',',
+ ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' };
+
+ protected static final boolean separators[] = new boolean[128];
+ static {
+ for (int i = 0; i < 128; i++) {
+ separators[i] = false;
+ }
+ for (int i = 0; i < SEPARATORS.length; i++) {
+ separators[SEPARATORS[i]] = true;
+ }
+ }
+
+ /**
+ * Construct a new cookie collection, that will extract
+ * the information from headers.
+ *
+ * @param headers Cookies are lazy-evaluated and will extract the
+ * information from the provided headers.
+ */
+ public Cookies(MimeHeaders headers) {
+ this.headers=headers;
+ }
+
+ /**
+ * Construct a new uninitialized cookie collection.
+ * Use {@link #setHeaders} to initialize.
+ */
+ // [seguin] added so that an empty Cookies object could be
+ // created, have headers set, then recycled.
+ public Cookies() {
+ }
+
+ /**
+ * Set the headers from which cookies will be pulled.
+ * This has the side effect of recycling the object.
+ *
+ * @param headers Cookies are lazy-evaluated and will extract the
+ * information from the provided headers.
+ */
+ // [seguin] added so that an empty Cookies object could be
+ // created, have headers set, then recycled.
+ public void setHeaders(MimeHeaders headers) {
+ recycle();
+ this.headers=headers;
+ }
+
+ /**
+ * Recycle.
+ */
+ public void recycle() {
+ for( int i=0; i< cookieCount; i++ ) {
+ if( scookies[i]!=null )
+ scookies[i].recycle();
+ }
+ cookieCount=0;
+ unprocessed=true;
+ }
+
+ /**
+ * EXPENSIVE!!! only for debugging.
+ */
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ pw.println("=== Cookies ===");
+ int count = getCookieCount();
+ for (int i = 0; i < count; ++i) {
+ pw.println(getCookie(i).toString());
+ }
+ return sw.toString();
+ }
+
+ // -------------------- Indexed access --------------------
+
+ public ServerCookie getCookie( int idx ) {
+ if( unprocessed ) {
+ getCookieCount(); // will also update the cookies
+ }
+ return scookies[idx];
+ }
+
+ public int getCookieCount() {
+ if( unprocessed ) {
+ unprocessed=false;
+ processCookies(headers);
+ }
+ return cookieCount;
+ }
+
+ // -------------------- Adding cookies --------------------
+
+ /** Register a new, unitialized cookie. Cookies are recycled, and
+ * most of the time an existing ServerCookie object is returned.
+ * The caller can set the name/value and attributes for the cookie
+ */
+ public ServerCookie addCookie() {
+ if( cookieCount >= scookies.length ) {
+ ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount];
+ System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);
+ scookies=scookiesTmp;
+ }
+
+ ServerCookie c = scookies[cookieCount];
+ if( c==null ) {
+ c= new ServerCookie();
+ scookies[cookieCount]=c;
+ }
+ cookieCount++;
+ return c;
+ }
+
+
+ // code from CookieTools
+
+ /** Add all Cookie found in the headers of a request.
+ */
+ public void processCookies( MimeHeaders headers ) {
+ if( headers==null )
+ return;// nothing to process
+ // process each "cookie" header
+ int pos=0;
+ while( pos>=0 ) {
+ // Cookie2: version ? not needed
+ pos=headers.findHeader( "Cookie", pos );
+ // no more cookie headers headers
+ if( pos<0 ) break;
+
+ MessageBytes cookieValue=headers.getValue( pos );
+ if( cookieValue==null || cookieValue.isNull() ) {
+ pos++;
+ continue;
+ }
+
+ // Uncomment to test the new parsing code
+ if( cookieValue.getType() == MessageBytes.T_BYTES ) {
+ if( dbg>0 ) log( "Parsing b[]: " + cookieValue.toString());
+ ByteChunk bc=cookieValue.getByteChunk();
+ processCookieHeader( bc.getBytes(),
+ bc.getOffset(),
+ bc.getLength());
+ } else {
+ if( dbg>0 ) log( "Parsing S: " + cookieValue.toString());
+ processCookieHeader( cookieValue.toString() );
+ }
+ pos++;// search from the next position
+ }
+ }
+
+ // XXX will be refactored soon!
+ public static boolean equals( String s, byte b[], int start, int end) {
+ int blen = end-start;
+ if (b == null || blen != s.length()) {
+ return false;
+ }
+ int boff = start;
+ for (int i = 0; i < blen; i++) {
+ if (b[boff++] != s.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ // ---------------------------------------------------------
+ // -------------------- DEPRECATED, OLD --------------------
+
+ private void processCookieHeader( String cookieString )
+ {
+ if( dbg>0 ) log( "Parsing cookie header " + cookieString );
+ // normal cookie, with a string value.
+ // This is the original code, un-optimized - it shouldn't
+ // happen in normal case
+
+ StringTokenizer tok = new StringTokenizer(cookieString,
+ ";", false);
+ while (tok.hasMoreTokens()) {
+ String token = tok.nextToken();
+ int i = token.indexOf("=");
+ if (i > -1) {
+
+ // XXX
+ // the trims here are a *hack* -- this should
+ // be more properly fixed to be spec compliant
+
+ String name = token.substring(0, i).trim();
+ String value = token.substring(i+1, token.length()).trim();
+ // RFC 2109 and bug
+ value=stripQuote( value );
+ ServerCookie cookie = addCookie();
+
+ cookie.getName().setString(name);
+ cookie.getValue().setString(value);
+ if( dbg > 0 ) log( "Add cookie " + name + "=" + value);
+ } else {
+ // we have a bad cookie.... just let it go
+ }
+ }
+ }
+
+ /**
+ *
+ * Strips quotes from the start and end of the cookie string
+ * This conforms to RFC 2965
+ *
+ * @param value a <code>String</code> specifying the cookie
+ * value (possibly quoted).
+ *
+ * @see #setValue
+ *
+ */
+ private static String stripQuote( String value )
+ {
+ // log("Strip quote from " + value );
+ if (value.startsWith("\"") && value.endsWith("\"")) {
+ try {
+ return value.substring(1,value.length()-1);
+ } catch (Exception ex) {
+ }
+ }
+ return value;
+ }
+
+
+ // log
+ static final int dbg=0;
+ public void log(String s ) {
+ if (log.isDebugEnabled())
+ log.debug("Cookies: " + s);
+ }
+
+
+ /**
+ * Returns true if the byte is a separator character as
+ * defined in RFC2619. Since this is called often, this
+ * function should be organized with the most probable
+ * outcomes first.
+ * JVK
+ */
+ public static final boolean isSeparator(final byte c) {
+ if (c > 0 && c < 126)
+ return separators[c];
+ else
+ return false;
+ }
+
+ /**
+ * Returns true if the byte is a whitespace character as
+ * defined in RFC2619
+ * JVK
+ */
+ public static final boolean isWhiteSpace(final byte c) {
+ // This switch statement is slightly slower
+ // for my vm than the if statement.
+ // Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164)
+ /*
+ switch (c) {
+ case ' ':;
+ case '\t':;
+ case '\n':;
+ case '\r':;
+ case '\f':;
+ return true;
+ default:;
+ return false;
+ }
+ */
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f')
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Parses a cookie header after the initial "Cookie:"
+ * [WS][$]token[WS]=[WS](token|QV)[;|,]
+ * RFC 2965
+ * JVK
+ */
+ public final void processCookieHeader(byte bytes[], int off, int len){
+ if( len<=0 || bytes==null ) return;
+ int end=off+len;
+ int pos=off;
+ int nameStart=0;
+ int nameEnd=0;
+ int valueStart=0;
+ int valueEnd=0;
+ int version = 0;
+ ServerCookie sc=null;
+ boolean isSpecial;
+ boolean isQuoted;
+
+ while (pos < end) {
+ isSpecial = false;
+ isQuoted = false;
+
+ // Skip whitespace and non-token characters (separators)
+ while (pos < end &&
+ (isSeparator(bytes[pos]) || isWhiteSpace(bytes[pos])))
+ {pos++; }
+
+ if (pos >= end)
+ return;
+
+ // Detect Special cookies
+ if (bytes[pos] == '$') {
+ isSpecial = true;
+ pos++;
+ }
+
+ // Get the cookie name. This must be a token
+ valueEnd = valueStart = nameStart = pos;
+ pos = nameEnd = getTokenEndPosition(bytes,pos,end);
+
+ // Skip whitespace
+ while (pos < end && isWhiteSpace(bytes[pos])) {pos++; };
+
+
+ // Check for an '=' -- This could also be a name-only
+ // cookie at the end of the cookie header, so if we
+ // are past the end of the header, but we have a name
+ // skip to the name-only part.
+ if (pos < end && bytes[pos] == '=') {
+
+ // Skip whitespace
+ do {
+ pos++;
+ } while (pos < end && isWhiteSpace(bytes[pos]));
+
+ if (pos >= end)
+ return;
+
+ // Determine what type of value this is, quoted value,
+ // token, name-only with an '=', or other (bad)
+ switch (bytes[pos]) {
+ case '"':; // Quoted Value
+ isQuoted = true;
+ valueStart=pos + 1; // strip "
+ // getQuotedValue returns the position before
+ // at the last qoute. This must be dealt with
+ // when the bytes are copied into the cookie
+ valueEnd=getQuotedValueEndPosition(bytes,
+ valueStart, end);
+ // We need pos to advance
+ pos = valueEnd;
+ // Handles cases where the quoted value is
+ // unterminated and at the end of the header,
+ // e.g. [myname="value]
+ if (pos >= end)
+ return;
+ break;
+ case ';':
+ case ',':
+ // Name-only cookie with an '=' after the name token
+ // This may not be RFC compliant
+ valueStart = valueEnd = -1;
+ // The position is OK (On a delimiter)
+ break;
+ default:;
+ if (!isSeparator(bytes[pos])) {
+ // Token
+ valueStart=pos;
+ // getToken returns the position at the delimeter
+ // or other non-token character
+ valueEnd=getTokenEndPosition(bytes, valueStart, end);
+ // We need pos to advance
+ pos = valueEnd;
+ } else {
+ // INVALID COOKIE, advance to next delimiter
+ // The starting character of the cookie value was
+ // not valid.
+ log("Invalid cookie. Value not a token or quoted value");
+ while (pos < end && bytes[pos] != ';' &&
+ bytes[pos] != ',')
+ {pos++; };
+ pos++;
+ // Make sure no special avpairs can be attributed to
+ // the previous cookie by setting the current cookie
+ // to null
+ sc = null;
+ continue;
+ }
+ }
+ } else {
+ // Name only cookie
+ valueStart = valueEnd = -1;
+ pos = nameEnd;
+
+ }
+
+ // We should have an avpair or name-only cookie at this
+ // point. Perform some basic checks to make sure we are
+ // in a good state.
+
+ // Skip whitespace
+ while (pos < end && isWhiteSpace(bytes[pos])) {pos++; };
+
+
+ // Make sure that after the cookie we have a separator. This
+ // is only important if this is not the last cookie pair
+ while (pos < end && bytes[pos] != ';' && bytes[pos] != ',') {
+ pos++;
+ }
+
+ pos++;
+
+ /*
+ if (nameEnd <= nameStart || valueEnd < valueStart ) {
+ // Something is wrong, but this may be a case
+ // of having two ';' characters in a row.
+ // log("Cookie name/value does not conform to RFC 2965");
+ // Advance to next delimiter (ignoring everything else)
+ while (pos < end && bytes[pos] != ';' && bytes[pos] != ',')
+ { pos++; };
+ pos++;
+ // Make sure no special cookies can be attributed to
+ // the previous cookie by setting the current cookie
+ // to null
+ sc = null;
+ continue;
+ }
+ */
+
+ // All checks passed. Add the cookie, start with the
+ // special avpairs first
+ if (isSpecial) {
+ isSpecial = false;
+ // $Version must be the first avpair in the cookie header
+ // (sc must be null)
+ if (equals( "Version", bytes, nameStart, nameEnd) &&
+ sc == null) {
+ // Set version
+ if( bytes[valueStart] =='1' && valueEnd == (valueStart+1)) {
+ version=1;
+ } else {
+ // unknown version (Versioning is not very strict)
+ }
+ continue;
+ }
+
+ // We need an active cookie for Path/Port/etc.
+ if (sc == null) {
+ continue;
+ }
+
+ // Domain is more common, so it goes first
+ if (equals( "Domain", bytes, nameStart, nameEnd)) {
+ sc.getDomain().setBytes( bytes,
+ valueStart,
+ valueEnd-valueStart);
+ continue;
+ }
+
+ if (equals( "Path", bytes, nameStart, nameEnd)) {
+ sc.getPath().setBytes( bytes,
+ valueStart,
+ valueEnd-valueStart);
+ continue;
+ }
+
+
+ if (equals( "Port", bytes, nameStart, nameEnd)) {
+ // sc.getPort is not currently implemented.
+ // sc.getPort().setBytes( bytes,
+ // valueStart,
+ // valueEnd-valueStart );
+ continue;
+ }
+
+ // Unknown cookie, complain
+ log("Unknown Special Cookie");
+
+ } else { // Normal Cookie
+ sc = addCookie();
+ sc.setVersion( version );
+ sc.getName().setBytes( bytes, nameStart,
+ nameEnd-nameStart);
+
+ if (valueStart != -1) { // Normal AVPair
+ sc.getValue().setBytes( bytes, valueStart,
+ valueEnd-valueStart);
+ if (isQuoted) {
+ // We know this is a byte value so this is safe
+ ServerCookie.unescapeDoubleQuotes(
+ sc.getValue().getByteChunk());
+ }
+ } else {
+ // Name Only
+ sc.getValue().setString("");
+ }
+ continue;
+ }
+ }
+ }
+
+ /**
+ * Given the starting position of a token, this gets the end of the
+ * token, with no separator characters in between.
+ * JVK
+ */
+ public static final int getTokenEndPosition(byte bytes[], int off, int end){
+ int pos = off;
+ while (pos < end && !isSeparator(bytes[pos])) {pos++; };
+
+ if (pos > end)
+ return end;
+ return pos;
+ }
+
+ /**
+ * Given a starting position after an initial quote chracter, this gets
+ * the position of the end quote. This escapes anything after a '\' char
+ * JVK RFC 2616
+ */
+ public static final int getQuotedValueEndPosition(byte bytes[], int off, int end){
+ int pos = off;
+ while (pos < end) {
+ if (bytes[pos] == '"') {
+ return pos;
+ } else if (bytes[pos] == '\\' && pos < (end - 1)) {
+ pos+=2;
+ } else {
+ pos++;
+ }
+ }
+ // Error, we have reached the end of the header w/o a end quote
+ return end;
+ }
+
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/FastHttpDateFormat.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/FastHttpDateFormat.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/FastHttpDateFormat.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/FastHttpDateFormat.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.http;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Utility class to generate HTTP dates.
+ *
+ * @author Remy Maucherat
+ */
+public final class FastHttpDateFormat {
+
+
+ // -------------------------------------------------------------- Variables
+
+
+ protected static final int CACHE_SIZE =
+ Integer.parseInt(System.getProperty("org.apache.tomcat.util.http.FastHttpDateFormat.CACHE_SIZE", "1000"));
+
+
+ /**
+ * HTTP date format.
+ */
+ protected static final SimpleDateFormat format =
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
+
+
+ /**
+ * The set of SimpleDateFormat formats to use in getDateHeader().
+ */
+ protected static final SimpleDateFormat formats[] = {
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+ };
+
+
+ protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT");
+
+
+ /**
+ * GMT timezone - all HTTP dates are on GMT
+ */
+ static {
+
+ format.setTimeZone(gmtZone);
+
+ formats[0].setTimeZone(gmtZone);
+ formats[1].setTimeZone(gmtZone);
+ formats[2].setTimeZone(gmtZone);
+
+ }
+
+
+ /**
+ * Instant on which the currentDate object was generated.
+ */
+ protected static long currentDateGenerated = 0L;
+
+
+ /**
+ * Current formatted date.
+ */
+ protected static String currentDate = null;
+
+
+ /**
+ * Formatter cache.
+ */
+ protected static final ConcurrentHashMap<Long, String> formatCache =
+ new ConcurrentHashMap<Long, String>(CACHE_SIZE);
+
+
+ /**
+ * Parser cache.
+ */
+ protected static final ConcurrentHashMap<String, Long> parseCache =
+ new ConcurrentHashMap<String, Long>(CACHE_SIZE);
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Get the current date in HTTP format.
+ */
+ public static final String getCurrentDate() {
+
+ long now = System.currentTimeMillis();
+ if ((now - currentDateGenerated) > 1000) {
+ synchronized (format) {
+ if ((now - currentDateGenerated) > 1000) {
+ currentDateGenerated = now;
+ currentDate = format.format(new Date(now));
+ }
+ }
+ }
+ return currentDate;
+
+ }
+
+
+ /**
+ * Get the HTTP format of the specified date.
+ */
+ public static final String formatDate
+ (long value, DateFormat threadLocalformat) {
+
+ Long longValue = new Long(value);
+ String cachedDate = formatCache.get(longValue);
+ if (cachedDate != null)
+ return cachedDate;
+
+ String newDate = null;
+ Date dateValue = new Date(value);
+ if (threadLocalformat != null) {
+ newDate = threadLocalformat.format(dateValue);
+ updateFormatCache(longValue, newDate);
+ } else {
+ synchronized (formatCache) {
+ synchronized (format) {
+ newDate = format.format(dateValue);
+ }
+ updateFormatCache(longValue, newDate);
+ }
+ }
+ return newDate;
+
+ }
+
+
+ /**
+ * Try to parse the given date as a HTTP date.
+ */
+ public static final long parseDate(String value,
+ DateFormat[] threadLocalformats) {
+
+ Long cachedDate = parseCache.get(value);
+ if (cachedDate != null)
+ return cachedDate.longValue();
+
+ Long date = null;
+ if (threadLocalformats != null) {
+ date = internalParseDate(value, threadLocalformats);
+ updateParseCache(value, date);
+ } else {
+ synchronized (parseCache) {
+ date = internalParseDate(value, formats);
+ updateParseCache(value, date);
+ }
+ }
+ if (date == null) {
+ return (-1L);
+ } else {
+ return date.longValue();
+ }
+
+ }
+
+
+ /**
+ * Parse date with given formatters.
+ */
+ private static final Long internalParseDate
+ (String value, DateFormat[] formats) {
+ Date date = null;
+ for (int i = 0; (date == null) && (i < formats.length); i++) {
+ try {
+ date = formats[i].parse(value);
+ } catch (ParseException e) {
+ ;
+ }
+ }
+ if (date == null) {
+ return null;
+ }
+ return new Long(date.getTime());
+ }
+
+
+ /**
+ * Update cache.
+ */
+ private static void updateFormatCache(Long key, String value) {
+ if (value == null) {
+ return;
+ }
+ if (formatCache.size() > CACHE_SIZE) {
+ formatCache.clear();
+ }
+ formatCache.put(key, value);
+ }
+
+
+ /**
+ * Update cache.
+ */
+ private static void updateParseCache(String key, Long value) {
+ if (value == null) {
+ return;
+ }
+ if (parseCache.size() > CACHE_SIZE) {
+ parseCache.clear();
+ }
+ parseCache.put(key, value);
+ }
+
+
+}
Added: tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/HttpMessages.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/HttpMessages.java?rev=640706&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/HttpMessages.java (added)
+++ tomcat/sandbox/tomcat-lite/tomcat-coyote/org/apache/tomcat/util/http/HttpMessages.java Mon Mar 24 23:01:43 2008
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.util.http;
+
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Handle (internationalized) HTTP messages.
+ *
+ * @author James Duncan Davidson [duncan@eng.sun.com]
+ * @author James Todd [gonzo@eng.sun.com]
+ * @author Jason Hunter [jch@eng.sun.com]
+ * @author Harish Prabandham
+ * @author costin@eng.sun.com
+ */
+public class HttpMessages {
+ // XXX move message resources in this package
+ protected static StringManager sm =
+ StringManager.getManager("org.apache.tomcat.util.http.res");
+
+ static String st_200=null;
+ static String st_302=null;
+ static String st_400=null;
+ static String st_404=null;
+
+ /** Get the status string associated with a status code.
+ * No I18N - return the messages defined in the HTTP spec.
+ * ( the user isn't supposed to see them, this is the last
+ * thing to translate)
+ *
+ * Common messages are cached.
+ *
+ */
+ public static String getMessage( int status ) {
+ // method from Response.
+
+ // Does HTTP requires/allow international messages or
+ // are pre-defined? The user doesn't see them most of the time
+ switch( status ) {
+ case 200:
+ if( st_200==null ) st_200=sm.getString( "sc.200");
+ return st_200;
+ case 302:
+ if( st_302==null ) st_302=sm.getString( "sc.302");
+ return st_302;
+ case 400:
+ if( st_400==null ) st_400=sm.getString( "sc.400");
+ return st_400;
+ case 404:
+ if( st_404==null ) st_404=sm.getString( "sc.404");
+ return st_404;
+ }
+ return sm.getString("sc."+ status);
+ }
+
+ /**
+ * Filter the specified message string for characters that are sensitive
+ * in HTML. This avoids potential attacks caused by including JavaScript
+ * codes in the request URL that is often reported in error messages.
+ *
+ * @param message The message string to be filtered
+ */
+ public static String filter(String message) {
+
+ if (message == null)
+ return (null);
+
+ char content[] = new char[message.length()];
+ message.getChars(0, message.length(), content, 0);
+ StringBuffer result = new StringBuffer(content.length + 50);
+ for (int i = 0; i < content.length; i++) {
+ switch (content[i]) {
+ case '<':
+ result.append("<");
+ break;
+ case '>':
+ result.append(">");
+ break;
+ case '&':
+ result.append("&");
+ break;
+ case '"':
+ result.append(""");
+ break;
+ default:
+ result.append(content[i]);
+ }
+ }
+ return (result.toString());
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org