KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > mime > MultipartMimeInput


1
2 /*
3  * Enhydra Java Application Server Project
4  *
5  * The contents of this file are subject to the Enhydra Public License
6  * Version 1.1 (the "License"); you may not use this file except in
7  * compliance with the License. You may obtain a copy of the License on
8  * the Enhydra web site ( http://www.enhydra.org/ ).
9  *
10  * Software distributed under the License is distributed on an "AS IS"
11  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
12  * the License for the specific terms governing rights and limitations
13  * under the License.
14  *
15  * The Initial Developer of the Enhydra Application Server is Lutris
16  * Technologies, Inc. The Enhydra Application Server and portions created
17  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
18  * All Rights Reserved.
19  *
20  * Contributor(s):
21  *
22  * $Id: MultipartMimeInput.java,v 1.2 2005/03/24 10:51:25 slobodan Exp $
23  */

24
25
26
27
28 package com.lutris.mime;
29 import java.io.IOException JavaDoc;
30 import java.io.InputStream JavaDoc;
31
32 import com.lutris.util.BMByteSearch;
33 import com.lutris.util.BMByteSearchStream;
34
35 /**
36  * Presents an incoming Multipart MIME message as a series of
37  * distinct MultipartMimeInputStream streams.
38  */

39 public class MultipartMimeInput
40 {
41     /**
42      * The current section of Multipart input. This is maintained so that
43      * it can be invalidated if a request is made to go to the next
44      * section.
45      */

46     protected MultipartMimeInputStream currentStream;
47     
48     /**
49      * An input stream that does exact pattern searching using an efficient
50      * string matching algorithm.
51      */

52     protected BMByteSearchStream inputSource;
53     
54     /**
55      * The string that represents a newline for this instance of input.
56      * This is necessary because some web browsers (typically on Unix
57      * hosts) send LF instead of the Mime-required CR+LF.
58      */

59     protected String JavaDoc newlineString="\r\n";
60     
61     /**
62      * The boundary string which separates different sections of the
63      * multipart Mime input.
64      */

65     protected String JavaDoc inputSeparator;
66     
67     /**
68      * Pre-compiled Boyer-Moore pattern search object for the Mime
69      * boundary string.
70      */

71     protected BMByteSearch inputPattern;
72     
73     /**
74      * True if the end of the input source has been reached and no
75      * more multipart sections are available to be read.
76      */

77     protected boolean atEOF = false;
78     
79     /**
80      * Constructs a new MultipartMimeInput object from an input source
81      * of type <code>InputStream</code> and a <code>ContentHeader</code>
82      * object. The <code>ContentHeader</code> object will usually be a
83      * <code>Content-Type</code> header and its value <i>must</i> begin
84      * with <code>"multipart/"</code> to indicate multipart Mime input.
85      * Other Mime types will cause a <code>MimeException</code> to be
86      * thrown. In addition, a parameter called <code>"boundary"</code>
87      * <i>must</i> exist in the header, since multipart Mime input
88      * is split using a boundary string passed in the
89      * <code>Content-Type</code> header.
90      *
91      * @param source Input stream from which Mime input will be read.
92      * @param contentHeader <code>ContentHeader</code> object containing
93      * a <code>boundary</code> field and Mime type to
94      * be used in scanning the input.
95      * @exception MimeException Thrown if an illegal header or Mime
96      * type is encountered while processing the
97      * input.
98      */

99     public
100     MultipartMimeInput(InputStream JavaDoc source, ContentHeader contentHeader)
101     throws MimeException
102     {
103     atEOF = false;
104     String JavaDoc value = contentHeader.getValue();
105     if (value == null) {
106         throw new MimeException("Missing content header value.",
107                     MimeException.INVALID_HEADER);
108     }
109     if (!value.toLowerCase().trim().startsWith("multipart/")) {
110         throw new MimeException("Illegal mime type.",
111                     MimeException.INVALID_MIME_TYPE);
112     }
113     String JavaDoc boundary = contentHeader.getParameter("boundary");
114     if (boundary == null) {
115         throw new MimeException("Missing boundary parameter.",
116                     MimeException.INVALID_HEADER);
117     }
118     
119     //
120
// Skip the first boundary.
121
//
122
int skipped=0;
123     try {
124         inputSource = new BMByteSearchStream(source, boundary, 2000);
125         skipped = inputSource.skipPattern();
126     } catch (IOException JavaDoc e) {
127         throw new MimeException("Error while reading to first boundary: "+
128                     e.toString(), MimeException.GENERIC);
129     }
130     if (skipped < 1) {
131         throw new MimeException("Boundary pattern missing in input " +
132                     "stream.", MimeException.GENERIC);
133     }
134     
135     //
136
// Skip newline after first boundary. Also determine whether
137
// "\n\r" (correct), or "\n" (incorrect) is being used. We're
138
// nice and handle both. The catch is that the user must be
139
// consistently right or consistently buggy, not both.
140
//
141
try {
142         switch (inputSource.read()) {
143         case '\r':
144             if (inputSource.read() != '\n') {
145             // This should be rare, but we'll try to accept it.
146
newlineString = "\r";
147             } else {
148             // Newline sequence is RFC2045-compliant (CR+LF).
149
newlineString="\r\n";
150             }
151             break;
152         case '\n':
153             // Input was sent by an off-standard unix browser.
154
// Uses LF only. We'll be nice and accept the input
155
// as long as "LF only" is done consistently. Using
156
// CR+LF later will cause spurious CR's to be appended
157
// to input sections.
158
newlineString="\n"; // Incorrect but accept anyway.
159
break;
160         default:
161             // If the boundary pattern is not followed immediately
162
// by a newline in any know form, then we just give up
163
// and return nothing.
164
atEOF = true; // Corrupt stream - no valid parts.
165
throw new MimeException("Missing newline after boundary.",
166                         MimeException.INVALID_HEADER);
167         }
168     } catch (IOException JavaDoc e) {
169         throw new MimeException("Missing newline after boundary:" +
170                     e.toString(),
171                     MimeException.INVALID_HEADER);
172     }
173     inputSeparator = newlineString + "--" + boundary;
174     inputPattern = new BMByteSearch(inputSeparator);
175     inputSource.setPattern(inputPattern);
176     }
177     
178     /**
179      * Returns the next section of the Multipart MIME stream as a
180      * MultipartMimeInputStream object. Returns <code>null</code> if
181      * the end of the input source has been reached.
182      * <P>
183      * <B>Note:</B><P>
184      * Since Multipart MIME data flows in a single stream, calling
185      * this method causes the previously returned MultipartMimeInputStream
186      * to be automatically closed and its input to be skipped.
187      *
188      * @return A MultipartMimeInputStream object for the next
189      * section of the multipart message.
190      * @exception MimeException If an error occurs while skipping to
191      * the next section of input.
192      */

193     public
194     MultipartMimeInputStream nextPart()
195     throws MimeException
196     {
197     try {
198         if (currentStream != null) {
199         currentStream.close();
200         if (currentStream.lastPart) atEOF = true;
201         }
202         if (atEOF) return null;
203         currentStream = new MultipartMimeInputStream(inputSource,
204                              inputPattern);
205     } catch (MimeEOFException e) {
206         return null;
207     } catch (IOException JavaDoc ioe) {
208         throw new MimeException("IO Error between parts: " +
209                     ioe.toString(), MimeException.GENERIC);
210     }
211     return currentStream;
212     }
213     
214     /**
215      * Closes the input source and the current
216      * <code>MultipartMimeInputStream</code> object. No more parts
217      * will be returned by <code>nextPart</code>.
218      *
219      * @exception MimeException If an error occurs while closing the
220      * input stream.
221      */

222     public
223     void close()
224     throws MimeException
225     {
226     try {
227         currentStream.close();
228         currentStream = null;
229         inputSource.close();
230         inputSource = null;
231         atEOF = true;
232     } catch (IOException JavaDoc ioe) {
233         throw new MimeException("MultipartMimeInput: " +
234                     "IO Error during close: " + ioe.toString(),
235                     MimeException.GENERIC);
236     }
237     }
238 }
239
Popular Tags