common/src/main/java/HTTPClient/Codecs.java
/**
     * This method decodes a multipart/form-data encoded string. The boundary
     * is parsed from the <var>cont_type</var> parameter, which must be of the
     * form 'multipart/form-data; boundary=...'. Any encoded files are created
     * in the directory specified by <var>dir</var> using the encoded filename.
     *
     * <P><em>Note:</em> Does not handle nested encodings (yet).
     *
     * <P>Examples: If you're receiving a multipart/form-data encoded response
     * from a server you could use something like:
     * <PRE>
     *     NVPair[] opts = Codecs.mpFormDataDecode(resp.getData(),
     *                                  resp.getHeader("Content-type"), ".");
     * </PRE>
     * If you're using this in a Servlet to decode the body of a request from
     * a client you could use something like:
     * <PRE>
     *     byte[] body = new byte[req.getContentLength()];
     *     new DataInputStream(req.getInputStream()).readFully(body);
     *     NVPair[] opts = Codecs.mpFormDataDecode(body, req.getContentType(),
     *                                             ".");
     * </PRE>
     * (where 'req' is the HttpServletRequest).
     *
     * <P>Assuming the data received looked something like:
     * <PRE>
     * -----------------------------114975832116442893661388290519
     * Content-Disposition: form-data; name="option"
     *                                                         &nbsp;
     * doit
     * -----------------------------114975832116442893661388290519
     * Content-Disposition: form-data; name="comment"; filename="comment.txt"
     *                                                         &nbsp;
     * Gnus and Gnats are not Gnomes.
     * -----------------------------114975832116442893661388290519--
     * </PRE>
     * you would get one file called <VAR>comment.txt</VAR> in the current
     * directory, and opts would contain two elements: {"option", "doit"}
     * and {"comment", "comment.txt"}
     *
     * @param     data        the form-data to decode.
     * @param     cont_type   the content type header (must contain the
     *			      boundary string).
     * @param     dir         the directory to create the files in.
     * @param     mangler     the filename mangler, or null if no mangling is
     *                        to be done. This is invoked just before each
     *                        file is created and written, thereby allowing
     *                        you to control the names of the files.
     * @return                an array of name/value pairs, one for each part;
     *                        the name is the 'name' attribute given in the
     *                        Content-Disposition header; the value is either
     *                        the name of the file if a filename attribute was
     *                        found, or the contents of the part.
     * @exception IOException If any file operation fails.
     * @exception ParseException If an error during parsing occurs.
     */
This method decodes a multipart/form-data encoded string. The boundary
is parsed from the cont_type parameter, which must be of the
form 'multipart/form-data; boundary=...'. Any encoded files are created
in the directory specified by dir using the encoded filename.

Note: Does not handle nested encodings (yet).





@param     data        the form-data to decode.
@param     cont_type   the content type header (must contain the
boundary string).
@param     dir         the directory to create the files in.
@param     mangler     the filename mangler, or null if no mangling is
to be done. This is invoked just before each
file is created and written, thereby allowing
you to control the names of the files.
@return                an array of name/value pairs, one for each part;
the name is the 'name' attribute given in the
Content-Disposition header; the value is either
the name of the file if a filename attribute was
found, or the contents of the part.
@exception IOException If any file operation fails.
@exception ParseException If an error during parsing occurs.
This method decodes a multipart / form - data encoded string . The boundary is parsed from the cont_type parameter which must be of the form ' multipart / form - data ; boundary = ... ' . Any encoded files are created in the directory specified by dir using the encoded filename . Note : Does not handle nested encodings ( yet ) . @param data the form - data to decode . @param cont_type the content type header ( must contain the boundary string ) . @param dir the directory to create the files in . @param mangler the filename mangler or null if no mangling is to be done . This is invoked just before each file is created and written thereby allowing you to control the names of the files . @return an array of name / value pairs one for each part ; the name is the ' name ' attribute given in the Content - Disposition header ; the value is either the name of the file if a filename attribute was found or the contents of the part . @exception IOException If any file operation fails . @exception ParseException If an error during parsing occurs .
public final static NVPair[] mpFormDataDecode(byte[] data, String cont_type,
						  String dir,
						  FilenameMangler mangler)
	    throws IOException, ParseException
    {
	String bndstr = Util.getParameter("boundary", cont_type);
	if (bndstr == null)
	    throw new ParseException("'boundary' parameter not found in Content-type: " + cont_type);
	byte[] srtbndry = (    "--" + bndstr + "\r\n").getBytes("8859_1"),
	       boundary = ("\r\n--" + bndstr + "\r\n").getBytes("8859_1"),
	       endbndry = ("\r\n--" + bndstr + "--"  ).getBytes("8859_1");
	int[] bs = Util.compile_search(srtbndry),
	      bc = Util.compile_search(boundary),
	      be = Util.compile_search(endbndry);
	int start = Util.findStr(srtbndry, bs, data, 0, data.length);
	if (start == -1)	
	    throw new ParseException("Starting boundary not found: " +
				     new String(srtbndry, "8859_1"));
	start += srtbndry.length;
	NVPair[] res  = new NVPair[10];
	boolean  done = false;
	int      idx;
	for (idx=0; !done; idx++)
	{
	    int end = Util.findStr(boundary, bc, data, start, data.length);
	    if (end == -1)		
	    {
		end = Util.findStr(endbndry, be, data, start, data.length);
		if (end == -1)
		    throw new ParseException("Ending boundary not found: " +
					     new String(endbndry, "8859_1"));
		done = true;
	    }
	    String hdr, name=null, value, filename=null, cont_disp = null;
	    while (true)
	    {
		int next = findEOL(data, start) + 2;
		if (next-2 <= start)  break;	
		hdr      = new String(data, start, next-2-start, "8859_1");
		start    = next;
		byte ch;
		while (next < data.length-1  &&
		       ((ch = data[next]) == ' '  ||  ch == '\t'))
		{
		    next   = findEOL(data, start) + 2;
		    hdr   += new String(data, start, next-2-start, "8859_1");
		    start  = next;
		}
		if (!hdr.regionMatches(true, 0, "Content-Disposition", 0, 19))
		    continue;
		Vector<HttpHeaderElement> pcd =
			Util.parseHeader(hdr.substring(hdr.indexOf(':')+1));
		HttpHeaderElement elem = Util.getElement(pcd, "form-data");
		if (elem == null)
		    throw new ParseException("Expected 'Content-Disposition: form-data' in line: "+hdr);
		NVPair[] params = elem.getParams();
		name = filename = null;
		for (int pidx=0; pidx<params.length; pidx++)
		{
		    if (params[pidx].getName().equalsIgnoreCase("name"))
			name = params[pidx].getValue();
		    if (params[pidx].getName().equalsIgnoreCase("filename"))
			filename = params[pidx].getValue();
		}
		if (name == null)
		    throw new ParseException("'name' parameter not found in header: "+hdr);
		cont_disp = hdr;
	    }
	    start += 2;
	    if (start > end)
		throw new ParseException("End of header not found at offset "+end);
	    if (cont_disp == null)
		throw new ParseException("Missing 'Content-Disposition' header at offset "+start);
	    if (filename != null)			
	    {
		if (mangler != null)
		    filename = mangler.mangleFilename(filename, name);
		if (filename != null  &&  filename.length() > 0)
		{
		    File file = new File(dir, filename);
		    FileOutputStream out = new FileOutputStream(file);
		    out.write(data, start, end-start);
		    out.close();
		}
		value = filename;
	    }
	    else					
	    {
		value = new String(data, start, end-start, "8859_1");
	    }
	    if (idx >= res.length)
		res = Util.resizeArray(res, idx+10);
	    res[idx] = new NVPair(name, value);
	    start = end + boundary.length;
	}
	return Util.resizeArray(res, idx);
    }
public final static NVPair [ ] mpFormDataDecode ( byte [ ] data , String cont_type , String dir , FilenameMangler mangler ) throws IOException , ParseException { String bndstr = Util . getParameter ( "boundary" , cont_type ) ; if ( bndstr == null ) throw new ParseException ( "'boundary' parameter not found in Content-type: " + cont_type ) ; byte [ ] srtbndry = ( "--" + bndstr + "\r\n" ) . getBytes ( "8859_1" ) , boundary = ( "\r\n--" + bndstr + "\r\n" ) . getBytes ( "8859_1" ) , endbndry = ( "\r\n--" + bndstr + "--" ) . getBytes ( "8859_1" ) ; int [ ] bs = Util . compile_search ( srtbndry ) , bc = Util . compile_search ( boundary ) , be = Util . compile_search ( endbndry ) ; int start = Util . findStr ( srtbndry , bs , data , 0 , data . length ) ; if ( start == - 1 ) throw new ParseException ( "Starting boundary not found: " + new String ( srtbndry , "8859_1" ) ) ; start += srtbndry . length ; NVPair [ ] res = new NVPair [ 10 ] ; boolean done = false ; int idx ; for ( idx = 0 ; ! done ; idx ++ ) { int end = Util . findStr ( boundary , bc , data , start , data . length ) ; if ( end == - 1 ) { end = Util . findStr ( endbndry , be , data , start , data . length ) ; if ( end == - 1 ) throw new ParseException ( "Ending boundary not found: " + new String ( endbndry , "8859_1" ) ) ; done = true ; } String hdr , name = null , value , filename = null , cont_disp = null ; while ( true ) { int next = findEOL ( data , start ) + 2 ; if ( next - 2 <= start ) break ; hdr = new String ( data , start , next - 2 - start , "8859_1" ) ; start = next ; byte ch ; while ( next < data . length - 1 && ( ( ch = data [ next ] ) == ' ' || ch == '\t' ) ) { next = findEOL ( data , start ) + 2 ; hdr += new String ( data , start , next - 2 - start , "8859_1" ) ; start = next ; } if ( ! hdr . regionMatches ( true , 0 , "Content-Disposition" , 0 , 19 ) ) continue ; Vector < HttpHeaderElement > pcd = Util . parseHeader ( hdr . substring ( hdr . indexOf ( ':' ) + 1 ) ) ; HttpHeaderElement elem = Util . getElement ( pcd , "form-data" ) ; if ( elem == null ) throw new ParseException ( "Expected 'Content-Disposition: form-data' in line: " + hdr ) ; NVPair [ ] params = elem . getParams ( ) ; name = filename = null ; for ( int pidx = 0 ; pidx < params . length ; pidx ++ ) { if ( params [ pidx ] . getName ( ) . equalsIgnoreCase ( "name" ) ) name = params [ pidx ] . getValue ( ) ; if ( params [ pidx ] . getName ( ) . equalsIgnoreCase ( "filename" ) ) filename = params [ pidx ] . getValue ( ) ; } if ( name == null ) throw new ParseException ( "'name' parameter not found in header: " + hdr ) ; cont_disp = hdr ; } start += 2 ; if ( start > end ) throw new ParseException ( "End of header not found at offset " + end ) ; if ( cont_disp == null ) throw new ParseException ( "Missing 'Content-Disposition' header at offset " + start ) ; if ( filename != null ) { if ( mangler != null ) filename = mangler . mangleFilename ( filename , name ) ; if ( filename != null && filename . length ( ) > 0 ) { File file = new File ( dir , filename ) ; FileOutputStream out = new FileOutputStream ( file ) ; out . write ( data , start , end - start ) ; out . close ( ) ; } value = filename ; } else { value = new String ( data , start , end - start , "8859_1" ) ; } if ( idx >= res . length ) res = Util . resizeArray ( res , idx + 10 ) ; res [ idx ] = new NVPair ( name , value ) ; start = end + boundary . length ; } return Util . resizeArray ( res , idx ) ; }
This method decodes a multipart/form-data encoded string.
This method decodes a multipart / form - data encoded string .
// Find and extract boundary string // setup search routines // let's start parsing the actual data // didn't even find the start // find end of this part // must be the last part // parse header(s) // empty line -> end of headers // handle line continuation // handle data for this part // It's a file // It's simple data