/* * Created on 23-Jun-2004 * Created by Paul Gardner * Copyright (C) 2004 Aelitis, All Rights Reserved. * * 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. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SARL au capital de 30,000 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. * */ package com.aelitis.azureus.core.util; /** * @author parg * */ import java.io.*; import java.util.*; public class MultiPartDecoder { public FormField[] decode( String boundary, InputStream is ) throws IOException { // -----------------------------7d4f2a310bca //Content-Disposition: form-data; name="upfile"; filename="C:\Temp\banana_custard.torrent" //Content-Type: application/octet-stream // // <data> // -----------------------------7d4f2a310bca // Content-Disposition: form-data; name="category" // //Music // -----------------------------7d4f2a310bca-- byte[] header_end_bytes = "\r\n\r\n".getBytes( "ISO-8859-1" ); byte[] boundary_bytes = ( "\r\n--" + boundary ).getBytes( "ISO-8859-1" ); int boundary_len = boundary_bytes.length; byte[] buffer = new byte[65536]; int buffer_pos = 0; boolean in_header = true; byte[] current_target = header_end_bytes; int current_target_length = 4; FormField current_field = null; List fields = new ArrayList(); while( true ){ int buffer_pos_start = buffer_pos; int len = is.read( buffer, buffer_pos, buffer.length - buffer_pos ); if ( len < 0 ){ len = 0; } buffer_pos += len; boolean found_target = false; for (int i=0;i<=buffer_pos-current_target_length;i++){ if ( buffer[i] == current_target[0] ){ found_target = true; for (int j=1;j<current_target_length;j++){ if ( buffer[i+j] != current_target[j]){ found_target = false; break; } } if ( found_target ){ if ( in_header ){ if ( current_field != null ){ current_field.complete(); } String header = new String( buffer, 0, i+4 ); int cdl_pos = header.toLowerCase().indexOf("content-disposition"); if ( cdl_pos == -1 ){ throw( new IOException( "invalid header '" + header + "'" )); } int cd_nl = header.indexOf( "\r\n", cdl_pos ); String cd_line = header.substring( cdl_pos, cd_nl ); int cd_pos = 0; Map attributes = new HashMap(); while(true){ int p1 = cd_line.indexOf( ";", cd_pos ); String bit; if ( p1 == -1 ){ bit = cd_line.substring( cd_pos ); }else{ bit = cd_line.substring( cd_pos, p1 ); cd_pos = p1+1; } int ep = bit.indexOf( "=" ); if ( ep != -1 ){ String lhs = bit.substring(0,ep).trim(); String rhs = bit.substring(ep+1).trim(); if ( rhs.startsWith("\"")){ rhs = rhs.substring(1); } if( rhs.endsWith("\"")){ rhs = rhs.substring(0,rhs.length()-1); } attributes.put( lhs.toLowerCase(), rhs ); } if ( p1 == -1 ){ break; } } String field_name = (String)attributes.get("name"); if( field_name == null ){ throw( new IOException( cd_line + " missing 'name' attribute" )); } current_field = new FormField( field_name, attributes ); fields.add( current_field ); }else{ current_field.write( buffer, 0, i ); } int rem = buffer_pos - (i+current_target_length); if ( rem > 0 ){ System.arraycopy( buffer, i+current_target_length, buffer, 0, rem ); } buffer_pos = rem; if ( in_header ){ in_header = false; current_target = boundary_bytes; current_target_length = boundary_len; }else{ in_header = true; current_target = header_end_bytes; current_target_length = 4; } break; } } } // if we didn't find the target and we're not in the header then // any remaining data in the buffer (less current target length) // is part of a body and can be written out if ( !(found_target || in_header )){ int rem = buffer_pos - current_target_length; if ( rem > 0 ){ // process buffer 0 length rem current_field.write( buffer, 0, rem ); System.arraycopy( buffer, rem, buffer, 0, current_target_length ); buffer_pos = current_target_length; } } if ( len == 0 && buffer_pos == buffer_pos_start ){ // nothing read and no progress made break; } } // should end in -- if ( buffer_pos < 2 || buffer[0] != '-' || buffer[1] != '-' ){ throw( new IOException( "Incorrect termination of form upload data")); } if ( current_field != null ){ current_field.complete(); } FormField[] res = new FormField[fields.size()]; fields.toArray( res ); return( res ); } public static class FormField { protected String name; protected Map attributes; protected long total_len; ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); File file; FileOutputStream fos; InputStream returned_stream; protected FormField( String _name, Map _attributes ) { name = _name; attributes = _attributes; // System.out.println( "formField:" + name ); } public String getName() { return( name ); } public String getAttribute( String attr_name ) { return((String)attributes.get(attr_name.toLowerCase())); } public InputStream getInputStream() throws IOException { if ( file == null ){ returned_stream = new ByteArrayInputStream( baos.toByteArray()); }else{ returned_stream = new FileInputStream( file ); } return( returned_stream ); } public String getString() throws IOException { String str = new LineNumberReader(new InputStreamReader( getInputStream())).readLine(); if ( str == null ){ str = ""; } return( str ); } public void destroy() { if ( returned_stream != null ){ try{ returned_stream.close(); }catch( Throwable e ){ } } if ( file != null ){ file.delete(); } } protected void write( byte[] buffer, int start, int len ) throws IOException { total_len += len; if ( fos != null ){ fos.write( buffer, start, len ); }else{ if ( total_len > 1024 ){ file = File.createTempFile( "AZU", null ); file.deleteOnExit(); fos = new FileOutputStream( file ); fos.write( baos.toByteArray()); fos.write( buffer, start, len ); }else{ baos.write( buffer, start, len ); } } } protected void complete() throws IOException { // System.out.println( " total_len = " + total_len ); if ( fos != null ){ fos.close(); } } } }