diff options
Diffstat (limited to 'bundles/org.eclipse.wst.ws.explorer/wsexplorer-src/org/eclipse/wst/ws/internal/explorer/platform/util/MultipartFormDataParser.java')
-rw-r--r-- | bundles/org.eclipse.wst.ws.explorer/wsexplorer-src/org/eclipse/wst/ws/internal/explorer/platform/util/MultipartFormDataParser.java | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.ws.explorer/wsexplorer-src/org/eclipse/wst/ws/internal/explorer/platform/util/MultipartFormDataParser.java b/bundles/org.eclipse.wst.ws.explorer/wsexplorer-src/org/eclipse/wst/ws/internal/explorer/platform/util/MultipartFormDataParser.java new file mode 100644 index 000000000..d442218ec --- /dev/null +++ b/bundles/org.eclipse.wst.ws.explorer/wsexplorer-src/org/eclipse/wst/ws/internal/explorer/platform/util/MultipartFormDataParser.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.ws.internal.explorer.platform.util; + +import java.io.*; +import java.util.*; + +import javax.servlet.http.*; + +public final class MultipartFormDataParser +{ + private Hashtable paramTable_; + + private static final String HEADER_CONTENT_TYPE = "Content-Type"; + private static final String HEADER_MULTIPART = "multipart"; + private static final String HEADER_BOUNDARY = "boundary="; + private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition: form-data"; + private static final String HEADER_NAME = "name=\""; + + private static final byte PARSER_STATE_INITIAL = 0; + private static final byte PARSER_STATE_BOUNDARY = 1; + private static final byte PARSER_STATE_PARAMETER = 2; + private static final byte PARSER_STATE_BLANK = 3; + private static final byte PARSER_STATE_DATA = 4; + + private static String parserStates[] = {"initial","boundary","parameter name","blank line","data"}; + + public MultipartFormDataParser() + { + } + + public MultipartFormDataParser(Hashtable parameters) + { + paramTable_ = new Hashtable(); + for (Iterator it = parameters.keySet().iterator(); it.hasNext();) + { + Object key = it.next(); + Object value = parameters.get(key); + if (value instanceof List) + { + List list = (List)value; + for (Iterator it2 = list.iterator(); it2.hasNext();) + saveData(key.toString(), it2.next().toString()); + } + else if (value.getClass().isArray()) + { + Object[] array = (Object[])value; + for (int i = 0; i < array.length; i++) + saveData(key.toString(), array[i].toString()); + } + else + { + saveData(key.toString(), value.toString()); + } + } + } + + /** + * Parse a multipart/form-data encoded post request with a given encoding. + * If the encoding is null, use the system default encoding. utf-8 is not a + * bad choice for the encoding. + */ + public final void parseRequest(HttpServletRequest request,String encoding) throws MultipartFormDataException + { + // Content-Type header should have the form: + // multipart/form-data; boundary=... + // + // RFC2046 5.1.1 page 19, paragraph 2: + // The Content-Type field for multipart entities requires one parameter, "boundary" (no quotes) + String contentType = request.getHeader(HEADER_CONTENT_TYPE); + if (contentType == null || !contentType.startsWith(HEADER_MULTIPART) || contentType.indexOf(HEADER_BOUNDARY) == -1) + throw new MultipartFormDataException("Content-Type is not multipart/form-data"); + + // RFC2046 5.1.1 page 19, paragraph 4: + // The boundary value may be enclosed in double quotes. Strip these if they are present. + String boundary = contentType.substring(contentType.indexOf(HEADER_BOUNDARY)+HEADER_BOUNDARY.length(),contentType.length()); + if (boundary.charAt(0) == '\"' && boundary.charAt(boundary.length()-1) == '\"') + boundary = boundary.substring(1,boundary.length()-1); + + // RFC2046 5.1.1 page 19, paragraph 2: + // The boundary delimiter line is then defined as a line consisting entirely + // of two hyphen characters. + String delimiter = "--"+boundary; + + if (paramTable_ == null) + paramTable_ = new Hashtable(); + else + paramTable_.clear(); + + try + { + BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(),encoding)); + String line = null; + String parameterName = null; + StringBuffer parameterValue = new StringBuffer(); + byte currentParserState = PARSER_STATE_INITIAL; + while ((line = br.readLine()) != null) + { + // Lines appear in the following sequence. + // 1) boundary indicating the start of a new parameter and end of a data segment. + // 2) Content-Disposition: form-data; name="..." - the name of a new parameter. + // 3) a blank line + // 4) data + // + // For each parameter, the sequence is repeated. + if (line.startsWith(delimiter)) + { + byte[] expectedParserStates = {PARSER_STATE_INITIAL,PARSER_STATE_DATA}; + if (isValidParserState(currentParserState,expectedParserStates)) + { + // Save any current data and prepare for a new parameter name. + if (parameterName != null) + { + saveData(parameterName,parameterValue.toString()); + parameterName = null; + parameterValue.setLength(0); + } + currentParserState = PARSER_STATE_BOUNDARY; + } + else + throw new MultipartFormDataException(getParserExceptionMessage(currentParserState,expectedParserStates)); + } + else if (line.startsWith(HEADER_CONTENT_DISPOSITION)) + { + byte[] expectedParserStates = {PARSER_STATE_BOUNDARY}; + if (isValidParserState(currentParserState,expectedParserStates)) + { + // Obtain the parameter name without the surrounding double quotes. Accounts for RFC 1867 too. + int parameterNameStartingPosition = line.indexOf(HEADER_NAME)+HEADER_NAME.length(); + parameterName = line.substring(parameterNameStartingPosition,+parameterNameStartingPosition+line.substring(parameterNameStartingPosition).indexOf('\"')); + currentParserState = PARSER_STATE_PARAMETER; + } + } + else if (currentParserState == PARSER_STATE_PARAMETER) + { + // A blank line should follow the PARAMETER. Discard the line and move on. + currentParserState = PARSER_STATE_BLANK; + } + else + { + // Expect the line to contain data. + if (parameterValue.length() > 0) + parameterValue.append('\n'); + parameterValue.append(line); + currentParserState = PARSER_STATE_DATA; + } + } + } + catch (Throwable t) + { + throw new MultipartFormDataException(t.getMessage()); + } + //dumpParamTable(); + } + + /** + * Returns the value of a request parameter as a String, or null if the parameter does not exist. + * If the parameter has multiple values, only the first value is returned. Use getParameterValues() + * for parameters with multiple values. + */ + public final String getParameter(String parameter) throws MultipartFormDataException + { + if (paramTable_ == null) + throw new MultipartFormDataException("Parser contains no parsed data"); + Vector values = (Vector)paramTable_.get(parameter); + return ((values != null)?((String)values.elementAt(0)):null); + } + + public final String[] getParameterValues(String parameter) throws MultipartFormDataException + { + if (paramTable_ == null) + throw new MultipartFormDataException("Parser contains no parsed data"); + Vector valuesVector = (Vector)paramTable_.get(parameter); + if (valuesVector == null) + return null; + String[] valuesArray = new String[valuesVector.size()]; + for (int i=0;i<valuesArray.length;i++) + valuesArray[i] = (String)valuesVector.elementAt(i); + return valuesArray; + } + + public final String[] getParameterNames() throws MultipartFormDataException + { + if (paramTable_ == null) + throw new MultipartFormDataException("Parser contains no parsed data"); + + int size = paramTable_.size(); + if (size == 0) + return null; + String[] names = new String[size]; + Enumeration keys = paramTable_.keys(); + for (int i=0;i<size;i++) + names[i] = (String)keys.nextElement(); + return names; + } + + private final void saveData(String parameterName,String parameterValue) + { + Vector values = (Vector)paramTable_.get(parameterName); + if (values == null) + values = new Vector(); + values.addElement(parameterValue); + paramTable_.put(parameterName,values); + } + + private final boolean isValidParserState(byte currentState,byte[] expectedStates) + { + boolean validity = false; + for (int i=0;i<expectedStates.length;i++) + { + if (currentState == expectedStates[i]) + { + validity = true; + break; + } + } + return validity; + } + + private final String getParserExceptionMessage(byte currentState,byte[] expectedStates) + { + StringBuffer msg = new StringBuffer("Parser state inconsistency!"); + msg.append('\n'); + msg.append("Current state : ").append(parserStates[currentState]).append('\n'); + msg.append("Expected state(s): "); + for (int i=0;i<expectedStates.length;i++) + { + msg.append(parserStates[expectedStates[i]]); + if (i != expectedStates.length-1) + msg.append(", "); + } + msg.append('\n'); + return msg.toString(); + } +} |