001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free SoftwareFoundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.connection;
031:
032: import com.caucho.log.Log;
033: import com.caucho.util.CharCursor;
034: import com.caucho.util.HashMapImpl;
035: import com.caucho.util.StringCharCursor;
036: import com.caucho.vfs.ByteToChar;
037:
038: import java.io.IOException;
039: import java.io.InputStream;
040: import java.io.UnsupportedEncodingException;
041: import java.util.logging.Level;
042: import java.util.logging.Logger;
043:
044: /**
045: * Form handling.
046: */
047: public class Form {
048: static final Logger log = Log.open(Form.class);
049:
050: private final ByteToChar _converter = ByteToChar.create();
051:
052: /**
053: * Parses the values from a query string.
054: *
055: * @param table the hashtable which will contain the results
056: * @param query the query string to evaluate
057: * @param javaEncoding the Java name for the charset
058: */
059: public void parseQueryString(HashMapImpl<String, String[]> table,
060: String query, String javaEncoding, boolean isTop)
061: throws IOException {
062: CharCursor is = new StringCharCursor(query);
063:
064: ByteToChar converter = _converter;
065: try {
066: converter.setEncoding(javaEncoding);
067: } catch (UnsupportedEncodingException e) {
068: log.log(Level.FINE, e.toString(), e);
069: }
070:
071: int ch = is.current();
072: while (ch != is.DONE) {
073: for (; Character.isWhitespace((char) ch) || ch == '&'; ch = is
074: .next()) {
075: }
076:
077: converter.clear();
078: for (; ch != is.DONE && ch != '=' && ch != '&'; ch = is
079: .next())
080: readChar(converter, is, ch, isTop);
081:
082: String key = converter.getConvertedString();
083:
084: converter.clear();
085: if (ch == '=')
086: ch = is.next();
087: for (; ch != is.DONE && ch != '&'; ch = is.next())
088: readChar(converter, is, ch, isTop);
089:
090: String value = converter.getConvertedString();
091:
092: if (log.isLoggable(Level.FINE))
093: log.fine("query: " + key + "=" + value);
094:
095: String[] oldValue = table.get(key);
096:
097: if (key == null || key.equals("")) {
098: } else if (oldValue == null)
099: table.put(key, new String[] { value });
100: else {
101: String[] newValue = new String[oldValue.length + 1];
102: System.arraycopy(oldValue, 0, newValue, 0,
103: oldValue.length);
104: newValue[oldValue.length] = value;
105: table.put(key, newValue);
106: }
107: }
108: }
109:
110: /**
111: * Scans the next character from the input stream, adding it to the
112: * converter.
113: *
114: * @param converter the byte-to-character converter
115: * @param is the form's input stream
116: * @param ch the next character
117: */
118: private static void readChar(ByteToChar converter, CharCursor is,
119: int ch, boolean isTop) throws IOException {
120: if (ch == '+')
121: converter.addByte(' ');
122: else if (ch == '%') {
123: int ch1 = is.next();
124:
125: if (ch1 == 'u') {
126: ch1 = is.next();
127: int ch2 = is.next();
128: int ch3 = is.next();
129: int ch4 = is.next();
130:
131: converter
132: .addChar((char) ((toHex(ch1) << 12)
133: + (toHex(ch2) << 8) + (toHex(ch3) << 4) + (toHex(ch4))));
134: } else {
135: int ch2 = is.next();
136:
137: converter.addByte(((toHex(ch1) << 4) + toHex(ch2)));
138: }
139: } else if (isTop)
140: converter.addByte((byte) ch);
141: else
142: converter.addChar((char) ch);
143: }
144:
145: /**
146: * Parses the values from a post data
147: *
148: * @param table the hashtable which will contain the results
149: * @param is an input stream containing the data
150: * @param javaEncoding the Java name for the charset
151: */
152: void parsePostData(HashMapImpl<String, String[]> table,
153: InputStream is, String javaEncoding) throws IOException {
154: ByteToChar converter = _converter;
155: try {
156: converter.setEncoding(javaEncoding);
157: } catch (UnsupportedEncodingException e) {
158: log.log(Level.FINE, e.toString(), e);
159: }
160:
161: int ch = is.read();
162: while (ch >= 0) {
163: for (; Character.isWhitespace((char) ch) || ch == '&'; ch = is
164: .read()) {
165: }
166:
167: converter.clear();
168: for (; ch >= 0 && ch != '=' && ch != '&'
169: && !Character.isWhitespace((char) ch); ch = is
170: .read()) {
171: readChar(converter, is, ch);
172: }
173:
174: String key = converter.getConvertedString();
175:
176: for (; Character.isWhitespace((char) ch); ch = is.read()) {
177: }
178:
179: converter.clear();
180: if (ch == '=') {
181: ch = is.read();
182: for (; Character.isWhitespace((char) ch); ch = is
183: .read()) {
184: }
185: }
186:
187: for (; ch >= 0 && ch != '&'; ch = is.read())
188: readChar(converter, is, ch);
189:
190: String value = converter.getConvertedString();
191:
192: /* Could show passwords
193: if (log.isLoggable(Level.FINE))
194: log.fine("post: " + key + "=" + value);
195: */
196:
197: String[] oldValue = table.get(key);
198:
199: if (key == null || key.equals("")) {
200: } else if (oldValue == null)
201: table.put(key, new String[] { value });
202: else {
203: String[] newValue = new String[oldValue.length + 1];
204: System.arraycopy(oldValue, 0, newValue, 0,
205: oldValue.length);
206: newValue[oldValue.length] = value;
207: table.put(key, newValue);
208: }
209: }
210: }
211:
212: /**
213: * Scans the next character from the input stream, adding it to the
214: * converter.
215: *
216: * @param converter the byte-to-character converter
217: * @param is the form's input stream
218: * @param ch the next character
219: */
220: private static void readChar(ByteToChar converter, InputStream is,
221: int ch) throws IOException {
222: if (ch == '+')
223: converter.addByte(' ');
224: else if (ch == '%') {
225: int ch1 = is.read();
226:
227: if (ch1 == 'u') {
228: ch1 = is.read();
229: int ch2 = is.read();
230: int ch3 = is.read();
231: int ch4 = is.read();
232:
233: converter
234: .addChar((char) ((toHex(ch1) << 12)
235: + (toHex(ch2) << 8) + (toHex(ch3) << 4) + (toHex(ch4))));
236: } else {
237: int ch2 = is.read();
238:
239: converter.addByte(((toHex(ch1) << 4) + toHex(ch2)));
240: }
241: } else
242: converter.addByte(ch);
243: }
244:
245: /**
246: * Converts a hex character to a byte
247: */
248: private static int toHex(int ch) {
249: if (ch >= '0' && ch <= '9')
250: return ch - '0';
251: else if (ch >= 'a' && ch <= 'f')
252: return ch - 'a' + 10;
253: else if (ch >= 'A' && ch <= 'F')
254: return ch - 'A' + 10;
255: else
256: return -1;
257: }
258: }
|