Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   *
   * Copyright (c) 2007-2010 Oracle and/or its affiliates. All rights reserved.
   *
   * The contents of this file are subject to the terms of either the GNU
   * General Public License Version 2 only ("GPL") or the Common Development
   * and Distribution License("CDDL") (collectively, the "License").  You
   * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
  * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
  * or packager/legal/LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
  * file and include the License file at packager/legal/LICENSE.txt.
  *
  * GPL Classpath Exception:
  * Oracle designates this particular file as subject to the "Classpath"
  * exception as provided by Oracle in the GPL Version 2 section of the License
  * file that accompanied this code.
  *
  * Modifications:
  * If applicable, add the following below the License Header, with the fields
  * enclosed by brackets [] replaced by your own identifying information:
  * "Portions Copyright [year] [name of copyright owner]"
  *
  * Contributor(s):
  * If you wish your version of this file to be governed by only the CDDL or
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
  * elects to include this software in this distribution under the [CDDL or GPL
  * Version 2] license."  If you don't indicate a single choice of license, a
  * recipient has the option to distribute your version of this file under
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
  * its licensees as provided above.  However, if you add GPL Version 2 code
  * and therefore, elected the GPL Version 2 license, then the option applies
  * only if the new code is made subject to such option by the copyright
  * holder.
  *
  *
  * This file incorporates work covered by the following copyright and
  * permission notice:
  *
  * Copyright 2004 The Apache Software 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.util.http;
 
 

Author(s):
Costin Manolache
 
 public final class Parameters {
 
     private static com.sun.org.apache.commons.logging.Log log=
             com.sun.org.apache.commons.logging.LogFactory.getLogParameters.class );
 
     protected static final StringManager sm =
             StringManager.getManager("org.apache.tomcat.util.http.res");
 
     // START PWC 6057385
             new LinkedHashMap<StringArrayList<String>>();
     // END PWC 6057385
     private boolean didQueryParameters = false;
     private boolean didMerge = false;
 
 
     UDecoder urlDec;
     MessageBytes decodedQuery = MessageBytes.newInstance();
    // Garbage-less parameter merging.
    // In a sub-request with parameters, the new parameters
    // will be stored in child. When a getParameter happens,
    // the 2 are merged togheter. The child will be altered
    // to contain the merged values - the parent is allways the
    // original request.
    private Parameters child = null;
    private Parameters parent = null;
    private Parameters currentChild = null;
    String encoding = null;
    String queryStringEncoding = null;
    private int limit = -1;
    private int parameterCount = 0;

    
    public Parameters() {
    }
    public void setQuery(MessageBytes queryMB) {
        this. = queryMB;
    }
    public void setLimit(int limit) {
        this. = limit;
    }
    public void setHeaders(MimeHeaders headers) {
        this. = headers;
    }
    public void setEncoding(String s) {
         = s;
        if ( > 0) {
            log("Set encoding to " + s);
        }
    }
    public void setQueryStringEncoding(String s) {
         = s;
        if ( > 0) {
            log("Set query string encoding to " + s);
        }
    }
    public void recycle() {
         = 0;
        .clear();
         = false;
         = null;
         = false;
         = null;
        .recycle();
    }
    // -------------------- Sub-request support --------------------
    public Parameters getCurrentSet() {
        if ( == null) {
            return this;
        }
        return ;
    }

    
Create ( or reuse ) a child that will be used during a sub-request. All future changes ( setting query string, adding parameters ) will affect the child ( the parent request is never changed ). Both setters and getters will return the data from the deepest child, merged with data from parents.
    public void push() {
        // We maintain a linked list, that will grow to the size of the
        // longest include chain.
        // The list has 2 points of interest:
        // - request.parameters() is the original request and head,
        // - request.parameters().currentChild() is the current set.
        // The ->child and parent<- links are preserved ( currentChild is not
        // the last in the list )
        // create a new element in the linked list
        // note that we reuse the child, if any - pop will not
        // set child to null !
        if ( == null) {
             = new Parameters();
            .setURLDecoder();
            . = this;
            return;
        }
        if (. == null) {
            . = new Parameters();
            .setURLDecoder();
            .. = ;
        } // it is not null if this object already had a child
        // i.e. a deeper include() ( we keep it )
        // the head will be the new element.
         = .;
    }

    
Discard the last child. This happens when we return from a sub-request and the parameters are locally modified.
    public void pop() {
        if ( == null) {
            throw new RuntimeException("Attempt to pop without a push");
        }
        .recycle();
         = .;
        // don't remove the top.
    }
    // -------------------- Data access --------------------
    // Access to the current name/values, no side effect ( processing ).
    // You must explicitely call handleQueryParameters and the post methods.
    // This is the original data representation ( hash of String->String[])
    public void addParameterValues(String keyString[] newValues) {
        if (key == null) {
            return;
        }
        ArrayList<Stringvalues = null;
        if (.containsKey(key)) {
            values = .get(key);
        } else {
            values = new ArrayList<String>(1);
            .put(keyvalues);
        }
        values.ensureCapacity(values.size() + newValues.length);
        for (String newValue : newValues) {
            values.add(newValue);
        }
    }
    public String[] getParameterValues(String name) {
        handleQueryParameters();
        ArrayList<Stringvalues = null;
        // sub-request
        if ( != null) {
            .merge();
            values = ..get(name);
        } else {
            // no "facade"
            values = .get(name);
        }
        return ((values != null) ? values.toArray(new String[values.size()]) : null);
    }
    public Enumeration<StringgetParameterNames() {
        handleQueryParameters();
        // Slow - the original code
        if ( != null) {
            .merge();
            /* START PWC 6057385
            return currentChild.paramHashStringArray.keys();
            */
            // START PWC 6057385
            return Collections.enumeration(
                    ..keySet());
            // END PWC 6057385
        }
        // merge in child
        /* START PWC 6057385
        return paramHashStringArray.keys();
        */
        // START PWC 6057385
        return Collections.enumeration(.keySet());
        // END PWC 6057385
    }

    
Combine the parameters from parent with our local ones
    private void merge() {
        // recursive
        if ( > 0) {
            log("Before merging " + this + " " +  + " " + );
            log(paramsAsString());
        }
        // Local parameters first - they take precedence as in spec.
        handleQueryParameters();
        // we already merged with the parent
        if () {
            return;
        }
        // we are the top level
        if ( == null) {
            return;
        }
        // Add the parent props to the child ( lower precedence )
        .merge();
        /* START PWC 6057385
        Hashtable parentProps=parent.paramHashStringArray;
        */
        // START PWC 6057385
        LinkedHashMap<StringArrayList<String>> parentProps = .;
        // END PWC 6057385
        merge2(parentProps);
         = true;
        if ( > 0) {
            log("After " + paramsAsString());
        }
    }
    // Shortcut.
    public String getParameter(String name) {
        ArrayList<Stringvalues = .get(name);
        if (values != null) {
            if (values.size() == 0) {
                return "";
            }
            return values.get(0);
        } else {
            return null;
        }
    }
    // -------------------- Processing --------------------

    
Process the query string into parameters
    public void handleQueryParameters() {
        if () {
            return;
        }
         = true;
        if ( == null || .isNull()) {
            return;
        }
        if ( > 0) {
            log("Decoding query " +  + " " + );
        }
        try {
            .duplicate();
        } catch (IOException e) {
            // Can't happen, as decodedQuery can't overflow
            e.printStackTrace();
        }
    }
    // --------------------

    
Combine 2 hashtables into a new one. ( two will be added to one ). Used to combine child parameters ( RequestDispatcher's query ) with parent parameters ( original query or parent dispatcher )
    /* START PWC 6057385
    private static void merge2(Hashtable one, Hashtable two ) {
        Enumeration e = two.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
    */
    // START PWC 6057385
    private static void merge2(LinkedHashMap<StringArrayList<String>> one,
            LinkedHashMap<StringArrayList<String>> two) {
        Iterator<Stringe = two.keySet().iterator();
        while (e.hasNext()) {
            String name = e.next();
            // END PWC 6057385
            ArrayList<StringoneValue = one.get(name);
            ArrayList<StringtwoValue = two.get(name);
            ArrayList<StringcombinedValue;
            if (twoValue == null) {
                continue;
            } else {
                if (oneValue == null) {
                    combinedValue = new ArrayList<String>(twoValue);
                } else {
                    combinedValue = new ArrayList<String>(oneValue.size() +
                            twoValue.size());
                    combinedValue.addAll(oneValue);
                    combinedValue.addAll(twoValue);
                }
                one.put(namecombinedValue);
            }
        }
    }
    // incredibly inefficient data representation for parameters,
    // until we test the new one
    public void addParameter(String keyString value)
            throws IllegalStateException {
        if (key == null) {
            return;
        }
        ++;
        if ( > -1 &&  > ) {
            // Processing this parameter will push us over the limit. ISE is
            // what Request.parseParts() uses for requests that are too big
            throw new IllegalStateException(.getString(
                    "parameters.maxCountFail", Integer.valueOf()));
        }
        ArrayList<Stringvalues = .get(key);
        if (values == null) {
            values = new ArrayList<String>(1);
            .put(keyvalues);
        }
        values.add(value);
    }
    public void setURLDecoder(UDecoder u) {
         = u;
    }
    // -------------------- Parameter parsing --------------------
    // This code is not used right now - it's the optimized version
    // 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();
    private ByteChunk origName=new ByteChunk();
    private ByteChunk origValue=new ByteChunk();
    CharChunk tmpNameC = new CharChunk(1024);
    CharChunk tmpValueC = new CharChunk(1024);
    public static final String DEFAULT_ENCODING = "ISO-8859-1";
    public static final Charset DEFAULT_CHARSET = Charset.forName();
    public void processParameters(byte bytes[], int startint len) {
        processParameters(bytesstartlengetCharset());
    }
    public void processParameters(byte bytes[], int startint len,
            Charset charset) {
        if ( > 0) {
            try {
                log(.getString("parameters.bytes",
                        // JDK 1.5 compliant
                        new String(bytesstartlen)));
            } catch(UnsupportedEncodingException e) {
                // Should never happen...
                .error(.getString("parameters.convertBytesFail"), e);
            }
        }
        int decodeFailCount = 0;
        int end = start + len;
        int pos = start;
        while (pos < end) {
            
            int nameStart = pos;
            int nameEnd = -1;
            int valueStart = -1;
            int valueEnd = -1;
            boolean parsingName = true;
            boolean decodeName = false;
            boolean decodeValue = false;
            boolean parameterComplete = false;
            do {
                switch(bytes[pos]) {
                    case '=':
                        if (parsingName) {
                            // Name finished. Value starts from next character
                            nameEnd = pos;
                            parsingName = false;
                            valueStart = ++pos;
                        } else {
                            // Equals character in value
                            pos++;
                        }
                        break;
                    case '&':
                        if (parsingName) {
                            // Name finished. No value.
                            nameEnd = pos;
                        } else {
                            // Value finished
                            valueEnd  = pos;
                        }
                        parameterComplete = true;
                        pos++;
                        break;
                    case '%':
                    case '+':
                        // Decoding required
                        if (parsingName) {
                            decodeName = true;
                        } else {
                            decodeValue = true;
                        }
                        pos ++;
                        break;
                    default:
                        pos ++;
                        break;
                }
            } while (!parameterComplete && pos < end);
            if (pos == end) {
                if (nameEnd == -1) {
                    nameEnd = pos;
                } else if (valueStart > -1 && valueEnd == -1) {
                    valueEnd = pos;
                }
            }
            if ( > 0 && valueStart == -1) {
                try {
                    log(.getString("parameters.noequal",
                            Integer.valueOf(nameStart), Integer.valueOf(nameEnd),
                            // JDK 1.5 compliant
                            new String(bytesnameStartnameEnd-nameStart,
                                    )));
                } catch(UnsupportedEncodingException e) {
                    // Should never happen...
                    .error(.getString("parameters.convertBytesFail"), e);
                }
            }
            if (nameEnd <= nameStart) {
                if (.isInfoEnabled()) {
                    String extract;
                    if (valueEnd >= nameStart) {
                        try {
                            // JDK 1.5 compliant
                            extract = new String(bytesnameStart,
                                    valueEnd - nameStart);
                        } catch(UnsupportedEncodingException e) {
                            // Should never happen...
                            .error(.getString("parameters.convertBytesFail"), e);
                        }
                    } else {
                        .info(.getString("parameters.invalidChunk",
                                Integer.valueOf(nameStart),
                                Integer.valueOf(nameEnd),
                               null));
                    }
                }
                continue;
                // invalid chunk - it's better to ignore
            }
            .setCharset(charset);
            .setCharset(charset);
            .setBytes(bytesnameStartnameEnd - nameStart);
            .setBytes(bytesvalueStartvalueEnd - valueStart);
            // Take copies as if anything goes wrong originals will be
            // corrupted. This means original values can be logged.
            // For performance - only done for debug
            if ( > 0) {
                try {
                    .append(bytesnameStartnameEnd - nameStart);
                    .append(bytesvalueStartvalueEnd - valueStart);
                } catch (IOException ioe) {
                    // Should never happen...
                    .error(.getString("paramerers.copyFail"), ioe);
                }
            }
            try {
                String name;
                String value;
                if (decodeName) {
                    name = urlDecode();
                } else {
                    name = .toString();
                }
                if (decodeValue) {
                    value = urlDecode();
                } else {
                    value = .toString();
                }
                try {
                    addParameter(namevalue);
                } catch (IllegalStateException ise) {
                    // Hitting limit stops processing further params but does
                    // not cause request to fail.
                    .warn(ise.getMessage());
                    break;
                }
            } catch (IOException e) {
                decodeFailCount++;
                if (decodeFailCount == 1 ||  > 0) {
                    if ( > 0) {
                        log(.getString("parameters.decodeFail.debug",
                                .toString(), .toString()), e);
                    } else if (.isInfoEnabled()) {
                        .info(.getString("parameters.decodeFail.info",
                                .toString(), .toString()), e);
                    }
                }
            }
            .recycle();
            .recycle();
            // Only recycle copies if we used them
            if ( > 0) {
                .recycle();
                .recycle();
            }
        }
        if (decodeFailCount > 1 &&  <= 0) {
            .info(.getString("parameters.multipleDecodingFail",
                        Integer.valueOf(decodeFailCount)));
        }
    }
    private String urlDecode(ByteChunk bc)
            throws IOException {
        if ( == null) {
             = new UDecoder();
        }
        .convert(bc);
        return bc.toString();
    }
    public void processParameters(char chars[], int startint len) {
        int end = start + len;
        int pos = start;
        if ( > 0) {
            log("Chars: " + new String(charsstartlen));
        }
        do {
            boolean noEq = false;
            int nameStart = pos;
            int valStart = -1;
            int valEnd = -1;
            int nameEnd = CharChunk.indexOf(charsnameStartend'=');
            int nameEnd2 = CharChunk.indexOf(charsnameStartend'&');
            if ((nameEnd2 != -1) &&
                    (nameEnd == -1 || nameEnd > nameEnd2)) {
                nameEnd = nameEnd2;
                noEq = true;
                valStart = nameEnd;
                valEnd = nameEnd;
                if ( > 0) {
                    log("no equal " + nameStart + " " + nameEnd + " " + new String(charsnameStart,
                            nameEnd - nameStart));
                }
            }
            if (nameEnd == -1) {
                nameEnd = end;
            }
            if (!noEq) {
                valStart = (nameEnd < end) ? nameEnd + 1 : end;
                valEnd = CharChunk.indexOf(charsvalStartend'&');
                if (valEnd == -1) {
                    valEnd = (valStart < end) ? end : valStart;
                }
            }
            pos = valEnd + 1;
            if (nameEnd <= nameStart) {
                continue;
                // invalid chunk - no name, it's better to ignore
                // XXX log it ?
            }
            try {
                .append(charsnameStartnameEnd - nameStart);
                .append(charsvalStartvalEnd - valStart);
                if ( > 0) {
                    log( + "= " + );
                }
                if ( == null) {
                     = new UDecoder();
                }
                .convert();
                .convert();
                if ( > 0) {
                    log( + "= " + );
                }
                addParameter(.toString(), .toString());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            .recycle();
            .recycle();
        } while (pos < end);
    }
    public void processParameters(MessageBytes data) {
        processParameters(data);
    }
    public void processParameters(MessageBytes dataString encoding) {
        if (data == null || data.isNull() || data.getLength() <= 0) {
            return;
        }
        if (data.getType() == .) {
            ByteChunk bc = data.getByteChunk();
            processParameters(bc.getBytes(), bc.getOffset(),
                    bc.getLength(), getCharset(encoding));
        } else {
            if (data.getType() != .) {
                data.toChars();
            }
            CharChunk cc = data.getCharChunk();
            processParameters(cc.getChars(), cc.getOffset(),
                    cc.getLength());
        }
    }

    
Debug purpose
    public String paramsAsString() {
        StringBuilder sb = new StringBuilder();
        /* START PWC 6057385
        Enumeration en= paramHashStringArray.keys();
        while( en.hasMoreElements() ) {
            String k=(String)en.nextElement();
        */
        // START PWC 6057385
        Iterator<Stringen = .keySet().iterator();
        while (en.hasNext()) {
            String k = en.next();
            // END PWC 6057385
            sb.append(k).append("=");
            ArrayList<Stringvalues = .get(k);
            if (values != null) {
                for (String value : values) {
                    sb.append(value).append(",");
                }
            }
            sb.append("\n");
        }
        return sb.toString();
    }
    private static int debug = 0;
    private void log(String s) {
        if (.isDebugEnabled()) {
            .debug("Parameters: " + s);
        }
    }
    private void log(String sThrowable t) {
        if (.isDebugEnabled()) {
            .debug("Parameters: " + st);
        }
    }
    // -------------------- Old code, needs rewrite --------------------

    
Used by RequestDispatcher
    public void processSingleParameters(String str) {
        int end = str.length();
        int pos = 0;
        if ( > 0) {
            log("String: " + str);
        }
        do {
            boolean noEq = false;
            int valStart = -1;
            int valEnd = -1;
            int nameStart = pos;
            int nameEnd = str.indexOf('='nameStart);
            int nameEnd2 = str.indexOf('&'nameStart);
            if (nameEnd2 == -1) {
                nameEnd2 = end;
            }
            if ((nameEnd2 != -1) &&
                    (nameEnd == -1 || nameEnd > nameEnd2)) {
                nameEnd = nameEnd2;
                noEq = true;
                valStart = nameEnd;
                valEnd = nameEnd;
                if ( > 0) {
                    log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStartnameEnd));
                }
            }
            if (nameEnd == -1) {
                nameEnd = end;
            }
            if (!noEq) {
                valStart = nameEnd + 1;
                valEnd = str.indexOf('&'valStart);
                if (valEnd == -1) {
                    valEnd = (valStart < end) ? end : valStart;
                }
            }
            pos = valEnd + 1;
            if (nameEnd <= nameStart) {
                continue;
            }
            if ( > 0) {
                log("XXX " + nameStart + " " + nameEnd + " "
                        + valStart + " " + valEnd);
            }
            try {
                .append(strnameStartnameEnd - nameStart);
                .append(strvalStartvalEnd - valStart);
                if ( > 0) {
                    log( + "= " + );
                }
                if ( == null) {
                     = new UDecoder();
                }
                .convert();
                .convert();
                if ( > 0) {
                    log( + "= " + );
                }
                if (str.compareTo(.toString()) == 0) {
                    addParameter(.toString(), .toString());
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            .recycle();
            .recycle();
        } while (pos < end);
    }
    public void processParameters(String str) {
        int end = str.length();
        int pos = 0;
        if ( > 0) {
            log("String: " + str);
        }
        do {
            boolean noEq = false;
            int valStart = -1;
            int valEnd = -1;
            int nameStart = pos;
            int nameEnd = str.indexOf('='nameStart);
            int nameEnd2 = str.indexOf('&'nameStart);
            if (nameEnd2 == -1) {
                nameEnd2 = end;
            }
            if ((nameEnd2 != -1) &&
                    (nameEnd == -1 || nameEnd > nameEnd2)) {
                nameEnd = nameEnd2;
                noEq = true;
                valStart = nameEnd;
                valEnd = nameEnd;
                if ( > 0) {
                    log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStartnameEnd));
                }
            }
            if (nameEnd == -1) {
                nameEnd = end;
            }
            if (!noEq) {
                valStart = nameEnd + 1;
                valEnd = str.indexOf('&'valStart);
                if (valEnd == -1) {
                    valEnd = (valStart < end) ? end : valStart;
                }
            }
            pos = valEnd + 1;
            if (nameEnd <= nameStart) {
                continue;
            }
            if ( > 0) {
                log("XXX " + nameStart + " " + nameEnd + " "
                        + valStart + " " + valEnd);
            }
            try {
                .append(strnameStartnameEnd - nameStart);
                .append(strvalStartvalEnd - valStart);
                if ( > 0) {
                    log( + "= " + );
                }
                if ( == null) {
                     = new UDecoder();
                }
                .convert();
                .convert();
                if ( > 0) {
                    log( + "= " + );
                }
                addParameter(.toString(), .toString());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            .recycle();
            .recycle();
        } while (pos < end);
    }
    private Charset getCharset(String encoding) {
        if (encoding == null) {
            return ;
        }
        try {
            return Charsets.lookupCharset(encoding);
        } catch(IllegalArgumentException e) {
            return ;
        }
    }
New to GrepCode? Check out our FAQ X