CGIParser.java Source Code

  • CGIParser Documentation and Examples
  • CGIParser Javadoc
    /*
     * Parse CGI query data.
     * Copyright (C) 2001-2010 Stephen Ostermiller
     * http://ostermiller.org/contact.pl?regarding=Java+Utilities
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * See LICENSE.txt for details.
     */
    
    package com.Ostermiller.util;
    import java.io.*;
    import java.net.URLDecoder;
    import java.util.*;
    
    /**
     * Parses query string data from a CGI request into name value pairs.
     * <p>
     * More information about this class is available from <a target="_top" href=
     * "http://ostermiller.org/utils/CGIParser.html">ostermiller.org</a>.
     *
     * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
     * @since ostermillerutils 1.00.00
     */
    public class CGIParser {
    
    	/**
    	 * Hash of names to Array Lists of values.
    	 */
    	private HashMap<String,ArrayList<String>> nameValuePairHash = new HashMap<String,ArrayList<String>>();
    
    	/**
    	 * Array list of NameValuePair objects.
    	 */
    	private LinkedList<NameValuePair> nameValuePairList = new LinkedList<NameValuePair>();
    
    	/**
    	 * Extract the name, value pairs from the given input stream and
    	 * make them available for retrieval.
    	 * <p>
    	 * The stream is read until the stream contains no more bytes.
    	 * <p>
    	 * Byte to character conversion on the stream is done according the platforms
    	 * default character encoding.
    	 *
    	 * @param in Stream containing CGI Encoded name value pairs.
    	 * @throws IOException If an input error occurs
    	 * @deprecated This method does not decode URLEncoded values properly.  Please use a method that specifies a character set.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	@Deprecated public CGIParser(InputStream in) throws IOException {
    		if (in == null) return;
    		CGILexer lex = new CGILexer(in);
    		parse(lex, "ISO-8859-1");
    	}
    
    	/**
    	 * Extract the name, value pairs from the given input stream and
    	 * make them available for retrieval.
    	 * <p>
    	 * The stream is read until the stream contains no more bytes.
    	 * <p>
    	 * The character set is used both when converting the byte stream to
    	 * a character stream and when decoding URL decoded parameters.
    	 *
    	 * @param in Stream containing CGI Encoded name value pairs.
    	 * @param charset Character encoding to use when converting bytes to characters
    	 * @throws IOException If an input error occurs
    	 * @throws UnsupportedEncodingException If the character set provided is not recognized
    	 *
    	 * @since ostermillerutils 1.03.00
    	 */
    	public CGIParser(InputStream in, String charset) throws IOException, UnsupportedEncodingException {
    		if (in == null) return;
    		CGILexer lex = new CGILexer(new InputStreamReader(in, charset));
    		parse(lex, charset);
    	}
    
    	/**
    	 * Extract the name, value pairs from the given reader and
    	 * make them available for retrieval.
    	 * <p>
    	 * The reader is read until the stream contains no more characters.
    	 *
    	 * @param in Reader containing CGI Encoded name value pairs.
    	 * @throws IOException If an input error occurs
    	 * @deprecated This method does not decode URLEncoded values properly.  Please use a method that specifies a character set.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	@Deprecated public CGIParser(Reader in) throws IOException {
    		if (in == null) return;
    		CGILexer lex = new CGILexer(in);
    		parse(lex, "ISO-8859-1");
    	}
    
    	/**
    	 * Extract the name, value pairs from the given reader and
    	 * make them available for retrieval.
    	 * <p>
    	 * The reader is read until the stream contains no more characters.
    	 *
    	 * @param in Reader containing CGI Encoded name value pairs.
    	 * @param charset Character encoding to use when converting bytes to characters
    	 * @throws IOException If an input error occurs
    	 * @throws UnsupportedEncodingException If the character set provided is not recognized
    	 *
    	 * @since ostermillerutils 1.03.00
    	 */
    	public CGIParser(Reader in, String charset) throws IOException, UnsupportedEncodingException {
    		if (in == null) return;
    		CGILexer lex = new CGILexer(in);
    		parse(lex, charset);
    	}
    
    	/**
    	 * Extract the name, value pairs from the given string and
    	 * make them available for retrieval.
    	 *
    	 * @param s CGI Encoded name value pairs.
    	 * @deprecated This method does not decode URLEncoded values properly.  Please use a method that specifies a character set.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	@Deprecated public CGIParser(String s){
    		if (s == null) return;
    		try {
    			CGILexer lex = new CGILexer(new StringReader(s));
    			parse(lex, "ISO-8859-1");
    		} catch (IOException x){
    			// This shouldn't be able to happen from a string.
    			throw new RuntimeException(x);
    		}
    	}
    
    	/**
    	 * Extract the name, value pairs from the given string and
    	 * make them available for retrieval.
    	 *
    	 * @param s CGI Encoded name value pairs.
    	 * @param charset Character encoding to use when converting bytes to characters
    	 * @throws UnsupportedEncodingException If the character set provided is not recognized
    	 *
    	 * @since ostermillerutils 1.03.00
    	 */
    	public CGIParser(String s, String charset) throws UnsupportedEncodingException {
    		if (s == null) return;
    		try {
    			CGILexer lex = new CGILexer(new StringReader(s));
    			parse(lex, charset);
    		} catch (UnsupportedEncodingException uex){
    			throw uex;
    		} catch (IOException x){
    			// This shouldn't be able to happen from a string.
    			throw new RuntimeException(x);
    		}
    	}
    
    	/**
    	 * Retrieve the name value pairs from the lexer and hash
    	 * them in the CGI hash table.
    	 *
    	 * @param lex Lexer that will return the tokens.
    	 * @throws IOException If an input error occurs
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	private void parse(CGILexer lex, String charset) throws IOException, UnsupportedEncodingException {
    		String nameValue, name, value;
    		while ((nameValue = lex.nextToken()) != null) {
    			int equalInd = nameValue.indexOf("=");
    			if (equalInd == -1){
    				name = nameValue;
    				value = "";
    			} else {
    				name = nameValue.substring(0, equalInd);
    				value = nameValue.substring(equalInd+1, nameValue.length());
    			}
    			try {
    				name = URLDecoder.decode(name, charset);
    			} catch (IllegalArgumentException iax){
    				// May be thrown for for illegal escape sequences such as %s
    				name = "";
    			}
    			try {
    				value = URLDecoder.decode(value, charset);
    			} catch (IllegalArgumentException iax){
    				// May be thrown for for illegal escape sequences such as %s
    				value = "";
    			}
    
    			// Hash
    			ArrayList<String> values = nameValuePairHash.get(name);
    			if (values == null){
    				values = new ArrayList<String>();
    			}
    			values.add(value);
    			nameValuePairHash.put(name, values);
    
    			// List
    			nameValuePairList.add(new NameValuePair(name, value));
    		}
    	}
    
    	/**
    	 * Returns an array of String objects containing all of the values the given request
    	 * parameter has, or null if the parameter does not exist.
    	 * <p>
    	 * If the parameter has a single value, the array has a length of 1.
    	 * @param name a String containing the name of the parameter whose value is requested
    	 * @return an array of String objects containing the parameter's values
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public String[] getParameterValues(String name){
    		ArrayList<String> values = nameValuePairHash.get(name);
    		if (values == null){
    			return null;
    		}
    		String[] valArray = new String[values.size()];
    		return (values.toArray(valArray));
    	}
    
    	/**
    	 * Set a name value pair as used in a URL.
    	 * This method will replace any previously defined values with the single
    	 * value specified. If the value is null, the name is removed.
    	 *
    	 * @param name a String specifying the name of the parameter.
    	 * @param value a String specifying the value of the single parameter, or null to remove.
    	 *
    	 * @since ostermillerutils 1.02.15
    	 */
    	public void setParameter(String name, String value){
    		Iterator<NameValuePair> listIterator = nameValuePairList.iterator();
    		while (listIterator.hasNext()){
    			NameValuePair nameValuePair = listIterator.next();
    			if (nameValuePair.getName().equals(name)){
    				listIterator.remove();
    			}
    		}
    
    		if (value == null){
    			nameValuePairHash.remove(name);
    			return;
    		}
    		ArrayList<String> values = nameValuePairHash.get(name);
    		if (values == null){
    			values = new ArrayList<String>();
    		}
    		values.clear();
    		values.add(value);
    		nameValuePairHash.put(name, values);
    		nameValuePairList.add(new NameValuePair(name, value));
    	}
    
    	/**
    	 * Set a name value pair as used in a URL.
    	 * This method will replace any previously defined values with the single
    	 * value specified. If values is null or empty, the name is removed.
    	 *
    	 * @param name a String specifying the name of the parameter.
    	 * @param values a String array specifying the values for the parameter, or null to remove.
    	 * @throws NullPointerException if any of the values is null.
    	 *
    	 * @since ostermillerutils 1.02.15
    	 */
    	public void setParameter(String name, String[] values){
    		Iterator<NameValuePair> listIterator = nameValuePairList.iterator();
    		while (listIterator.hasNext()){
    			NameValuePair nameValuePair = listIterator.next();
    			if (nameValuePair.getName().equals(name)){
    				listIterator.remove();
    			}
    		}
    
    		if (values == null || values.length == 0){
    			nameValuePairHash.remove(name);
    			return;
    		}
    		for (String element: values) {
    			if (element == null) throw new NullPointerException();
    		}
    		ArrayList<String> valuesVec = nameValuePairHash.get(name);
    		if (valuesVec == null){
    			valuesVec = new ArrayList<String>();
    		}
    		valuesVec.clear();
    		for (String element: values) {
    			valuesVec.add(element);
    			nameValuePairList.add(new NameValuePair(name, element));
    		}
    		nameValuePairHash.put(name, valuesVec);
    	}
    
    	/**
    	 * Set a name value pair as used in a URL.
    	 * This method will add to any previously defined values the values
    	 * specified. If value is null, this method has no effect.
    	 *
    	 * @param name a String specifying the name of the parameter.
    	 * @param value a String specifying the value of the single parameter, or null to remove.
    	 *
    	 * @since ostermillerutils 1.02.15
    	 */
    	public void addParameter(String name, String value){
    		if (value == null){
    			return;
    		}
    		ArrayList<String> values = nameValuePairHash.get(name);
    		if (values == null){
    			values = new ArrayList<String>();
    		}
    		values.add(value);
    		nameValuePairHash.put(name, values);
    		nameValuePairList.add(new NameValuePair(name, value));
    	}
    
    	/**
    	 * Set a name value pair as used in a URL.
    	 * This method will add to any previously defined values the values
    	 * specified. If values is null, this method has no effect.
    	 *
    	 * @param name a String specifying the name of the parameter.
    	 * @param values a String array specifying the values of the parameter, or null to remove.
    	 * @throws NullPointerException if any of the values is null.
    	 *
    	 * @since ostermillerutils 1.02.15
    	 */
    	public void addParameter(String name, String[] values){
    		if (values == null || values.length == 0){
    			return;
    		}
    		for (String element: values) {
    			if (element == null) throw new NullPointerException();
    		}
    		ArrayList<String> valuesVec = nameValuePairHash.get(name);
    		if (valuesVec == null){
    			valuesVec = new ArrayList<String>();
    		}
    		for (String element: values) {
    			valuesVec.add(element);
    			nameValuePairList.add(new NameValuePair(name, element));
    		}
    		nameValuePairHash.put(name, valuesVec);
    	}
    
    	/**
    	 * Returns the value of a request parameter as a String, or null if the parameter does
    	 * not exist. Request parameters are extra information sent with the request.
    	 * <p>
    	 * You should only use this method when you are sure the parameter has only one value.
    	 * If the parameter might have more than one value, use getParameterValues(java.lang.String).
    	 * <P>
    	 * If you use this method with a multiple valued parameter, the value returned is equal to
    	 * the first value in the array returned by getParameterValues.
    	 *
    	 * @param name a String specifying the name of the parameter
    	 * @return a String representing the single value of the parameter
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public String getParameter(String name){
    		ArrayList<String> values = nameValuePairHash.get(name);
    		if (values == null){
    			return null;
    		}
    		return (values.get(0));
    	}
    
    	/**
    	 * Returns an Enumeration of String  objects containing the names of the
    	 * parameters contained in this request. If the request has no parameters,
    	 * the method returns an empty Enumeration.
    	 *
    	 * @return an Enumeration of String objects, each String containing the name
    	 *     of a request parameter; or an empty Enumeration if the request has
    	 *     no parameters
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public Enumeration<String> getParameterNames(){
    		return new IteratorEnumeration<String>(nameValuePairHash.keySet().iterator());
    	}
    
    	/**
    	 * Returns the names of the
    	 * parameters contained in this request. If the request has no parameters,
    	 * the method returns an empty String array.  Each name will appear only
    	 * once, even if it was contained in the request multiple times.  The order
    	 * of the names may not match the order from the request.
    	 *
    	 * @return An array of Strings, each of which is the name
    	 *     of a request parameter; or an array of length zero if the request has
    	 *     no parameters
    	 *
    	 * @since ostermillerutils 1.03.00
    	 */
    	public String[] getParameterNameList(){
    		return nameValuePairHash.keySet().toArray(new String[0]);
    	}
    
    	/**
    	 * Get the all the parameters in the order in which they were added.
    	 *
    	 * @return array of all name value pairs.
    	 */
    	public NameValuePair[] getParameters(){
    		return nameValuePairList.toArray(new NameValuePair[0]);
    	}
    
    	/**
    	 * Returns the name value pairs properly escaped and written in URL format.
    	 *
    	 * @param enc Character encoding to use when escaping characters.
    	 * @return URLEncoded name value pairs.
    	 * @throws  UnsupportedEncodingException If the named encoding is not supported.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public String toString(String enc) throws UnsupportedEncodingException {
    		StringBuffer sb = new StringBuffer();
    		boolean bFirst = true;
    		Iterator<NameValuePair> listIterator = nameValuePairList.iterator();
    		while (listIterator.hasNext()){
    			NameValuePair nameValuePair = listIterator.next();
    			if (!bFirst) sb.append('&');
    			bFirst = false;
    			sb.append(nameValuePair.toString(enc));
    		}
    		return sb.toString();
    	}
    
    	/**
    	 * Returns the name value pairs properly escaped and written in URL format
    	 * with UTF-8 URL encoding.
    	 *
    	 * @return URLEncoded name value pairs.
    	 *
    	 * @since ostermillerutils 1.03.00
    	 */
    	@Override public String toString() {
    		try {
    			return toString("UTF-8");
    		} catch (UnsupportedEncodingException uex){
    			// UTF-8 should be supported
    			throw new RuntimeException(uex);
    		}
    	}
    }