source: josm/trunk/src/org/openstreetmap/josm/io/MultiPartFormOutputStream.java@ 1180

Last change on this file since 1180 was 1169, checked in by stoecker, 15 years ago

removed usage of tab stops

  • Property svn:eol-style set to native
File size: 14.8 KB
Line 
1/*
2Taken from forum.java.sun.com
3
4License
5
6Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved.
7Redistribution and use in source and binary forms, with or without modification,
8are permitted provided that the following conditions are met:
9
10 * Redistribution of source code must retain the above copyright notice, this list
11 of conditions and the following disclaimer.
12
13 * Redistribution in binary form must reproduce the above copyright notice, this
14 list of conditions and the following disclaimer in the documentation and/or other
15 materials provided with the distribution.
16
17
18Neither the name of Sun Microsystems, Inc. or the names of contributors may be used to
19endorse or promote products derived from this software without specific prior written
20permission.
21
22This software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR IMPLIED
23CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS,
25INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS
26A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT
27WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
28INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
29REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS
30SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31
32You acknowledge that this software is not designed, licensed or intended for use in the
33design, construction, operation or maintenance of any nuclear facility.
34*/
35
36package org.openstreetmap.josm.io;
37
38import java.io.DataOutputStream;
39import java.io.FileInputStream;
40import java.io.InputStream;
41import java.io.OutputStream;
42import java.net.HttpURLConnection;
43import java.net.URL;
44import java.net.URLConnection;
45
46
47/**
48 * <code>MultiPartFormOutputStream</code> is used to write
49 * "multipart/form-data" to a <code>java.net.URLConnection</code> for
50 * POSTing. This is primarily for file uploading to HTTP servers.
51 *
52 * @since JDK1.3
53 */
54public class MultiPartFormOutputStream extends OsmConnection {
55 /**
56 * The line end characters.
57 */
58 private static final String NEWLINE = "\r\n";
59
60 /**
61 * The boundary prefix.
62 */
63 private static final String PREFIX = "--";
64
65 /**
66 * The output stream to write to.
67 */
68 private DataOutputStream out = null;
69
70 /**
71 * The multipart boundary string.
72 */
73 private String boundary = null;
74
75 /**
76 * Creates a new <code>MultiPartFormOutputStream</code> object using
77 * the specified output stream and boundary. The boundary is required
78 * to be created before using this method, as described in the
79 * description for the <code>getContentType(String)</code> method.
80 * The boundary is only checked for <code>null</code> or empty string,
81 * but it is recommended to be at least 6 characters. (Or use the
82 * static createBoundary() method to create one.)
83 *
84 * @param os the output stream
85 * @param boundary the boundary
86 * @see #createBoundary()
87 * @see #getContentType(String)
88 */
89 public MultiPartFormOutputStream(OutputStream os, String boundary) {
90 if(os == null) {
91 throw new IllegalArgumentException("Output stream is required.");
92 }
93 if(boundary == null || boundary.length() == 0) {
94 throw new IllegalArgumentException("Boundary stream is required.");
95 }
96 this.out = new DataOutputStream(os);
97 this.boundary = boundary;
98 initAuthentication();
99 }
100
101 /**
102 * Writes an boolean field value.
103 *
104 * @param name the field name (required)
105 * @param value the field value
106 * @throws java.io.IOException on input/output errors
107 */
108 public void writeField(String name, boolean value)
109 throws java.io.IOException {
110 writeField(name, new Boolean(value).toString());
111 }
112
113 /**
114 * Writes an double field value.
115 *
116 * @param name the field name (required)
117 * @param value the field value
118 * @throws java.io.IOException on input/output errors
119 */
120 public void writeField(String name, double value)
121 throws java.io.IOException {
122 writeField(name, Double.toString(value));
123 }
124
125 /**
126 * Writes an float field value.
127 *
128 * @param name the field name (required)
129 * @param value the field value
130 * @throws java.io.IOException on input/output errors
131 */
132 public void writeField(String name, float value)
133 throws java.io.IOException {
134 writeField(name, Float.toString(value));
135 }
136
137 /**
138 * Writes an long field value.
139 *
140 * @param name the field name (required)
141 * @param value the field value
142 * @throws java.io.IOException on input/output errors
143 */
144 public void writeField(String name, long value)
145 throws java.io.IOException {
146 writeField(name, Long.toString(value));
147 }
148
149 /**
150 * Writes an int field value.
151 *
152 * @param name the field name (required)
153 * @param value the field value
154 * @throws java.io.IOException on input/output errors
155 */
156 public void writeField(String name, int value)
157 throws java.io.IOException {
158 writeField(name, Integer.toString(value));
159 }
160
161 /**
162 * Writes an short field value.
163 *
164 * @param name the field name (required)
165 * @param value the field value
166 * @throws java.io.IOException on input/output errors
167 */
168 public void writeField(String name, short value)
169 throws java.io.IOException {
170 writeField(name, Short.toString(value));
171 }
172
173 /**
174 * Writes an char field value.
175 *
176 * @param name the field name (required)
177 * @param value the field value
178 * @throws java.io.IOException on input/output errors
179 */
180 public void writeField(String name, char value)
181 throws java.io.IOException {
182 writeField(name, new Character(value).toString());
183 }
184
185 /**
186 * Writes an string field value. If the value is null, an empty string
187 * is sent ("").
188 *
189 * @param name the field name (required)
190 * @param value the field value
191 * @throws java.io.IOException on input/output errors
192 */
193 public void writeField(String name, String value)
194 throws java.io.IOException {
195 if(name == null) {
196 throw new IllegalArgumentException("Name cannot be null or empty.");
197 }
198 if(value == null) {
199 value = "";
200 }
201 /*
202 --boundary\r\n
203 Content-Disposition: form-data; name="<fieldName>"\r\n
204 \r\n
205 <value>\r\n
206 */
207 // write boundary
208 out.writeBytes(PREFIX);
209 out.writeBytes(boundary);
210 out.writeBytes(NEWLINE);
211 // write content header
212 out.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"");
213 out.writeBytes(NEWLINE);
214 out.writeBytes(NEWLINE);
215 // write content
216 out.writeBytes(value);
217 out.writeBytes(NEWLINE);
218 out.flush();
219 }
220
221 /**
222 * Writes a file's contents. If the file is null, does not exists, or
223 * is a directory, a <code>java.lang.IllegalArgumentException</code>
224 * will be thrown.
225 *
226 * @param name the field name
227 * @param mimeType the file content type (optional, recommended)
228 * @param file the file (the file must exist)
229 * @throws java.io.IOException on input/output errors
230 */
231 public void writeFile(String name, String mimeType, java.io.File file)
232 throws java.io.IOException {
233 if(file == null) {
234 throw new IllegalArgumentException("File cannot be null.");
235 }
236 if(!file.exists()) {
237 throw new IllegalArgumentException("File does not exist.");
238 }
239 if(file.isDirectory()) {
240 throw new IllegalArgumentException("File cannot be a directory.");
241 }
242 writeFile(name, mimeType, file.getCanonicalPath(), new FileInputStream(file));
243 }
244
245 /**
246 * Writes a input stream's contents. If the input stream is null, a
247 * <code>java.lang.IllegalArgumentException</code> will be thrown.
248 *
249 * @param name the field name
250 * @param mimeType the file content type (optional, recommended)
251 * @param fileName the file name (required)
252 * @param is the input stream
253 * @throws java.io.IOException on input/output errors
254 */
255 public void writeFile(String name, String mimeType,
256 String fileName, InputStream is)
257 throws java.io.IOException {
258 if(is == null) {
259 throw new IllegalArgumentException("Input stream cannot be null.");
260 }
261 if(fileName == null || fileName.length() == 0) {
262 throw new IllegalArgumentException("File name cannot be null or empty.");
263 }
264 /*
265 --boundary\r\n
266 Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
267 Content-Type: <mime-type>\r\n
268 \r\n
269 <file-data>\r\n
270 */
271 // write boundary
272 out.writeBytes(PREFIX);
273 out.writeBytes(boundary);
274 out.writeBytes(NEWLINE);
275 // write content header
276 out.writeBytes("Content-Disposition: form-data; name=\"" + name +
277 "\"; filename=\"" + fileName + "\"");
278 out.writeBytes(NEWLINE);
279 if(mimeType != null) {
280 out.writeBytes("Content-Type: " + mimeType);
281 out.writeBytes(NEWLINE);
282 }
283 out.writeBytes(NEWLINE);
284 // write content
285 byte[] data = new byte[1024];
286 int r = 0;
287 while((r = is.read(data, 0, data.length)) != -1) {
288 out.write(data, 0, r);
289 }
290 // close input stream, but ignore any possible exception for it
291 try {
292 is.close();
293 } catch(Exception e) {}
294 out.writeBytes(NEWLINE);
295 out.flush();
296 }
297
298 /**
299 * Writes the given bytes. The bytes are assumed to be the contents
300 * of a file, and will be sent as such. If the data is null, a
301 * <code>java.lang.IllegalArgumentException</code> will be thrown.
302 *
303 * @param name the field name
304 * @param mimeType the file content type (optional, recommended)
305 * @param fileName the file name (required)
306 * @param data the file data
307 * @throws java.io.IOException on input/output errors
308 */
309 public void writeFile(String name, String mimeType,
310 String fileName, byte[] data)
311 throws java.io.IOException {
312 if(data == null) {
313 throw new IllegalArgumentException("Data cannot be null.");
314 }
315 if(fileName == null || fileName.length() == 0) {
316 throw new IllegalArgumentException("File name cannot be null or empty.");
317 }
318 /*
319 --boundary\r\n
320 Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
321 Content-Type: <mime-type>\r\n
322 \r\n
323 <file-data>\r\n
324 */
325 // write boundary
326 out.writeBytes(PREFIX);
327 out.writeBytes(boundary);
328 out.writeBytes(NEWLINE);
329 // write content header
330 out.writeBytes("Content-Disposition: form-data; name=\"" + name +
331 "\"; filename=\"" + fileName + "\"");
332 out.writeBytes(NEWLINE);
333 if(mimeType != null) {
334 out.writeBytes("Content-Type: " + mimeType);
335 out.writeBytes(NEWLINE);
336 }
337 out.writeBytes(NEWLINE);
338 // write content
339 out.write(data, 0, data.length);
340 out.writeBytes(NEWLINE);
341 out.flush();
342 }
343
344 /**
345 * Flushes the stream. Actually, this method does nothing, as the only
346 * write methods are highly specialized and automatically flush.
347 */
348 public void flush() {
349 // out.flush();
350 }
351
352 /**
353 * Closes the stream. <br/>
354 * <br/>
355 * <b>NOTE:</b> This method <b>MUST</b> be called to finalize the
356 * multipart stream.
357 *
358 * @throws java.io.IOException on input/output errors
359 */
360 public void close() throws java.io.IOException {
361 // write final boundary
362 out.writeBytes(PREFIX);
363 out.writeBytes(boundary);
364 out.writeBytes(PREFIX);
365 out.writeBytes(NEWLINE);
366 out.flush();
367 out.close();
368 }
369
370 /**
371 * Gets the multipart boundary string being used by this stream.
372 *
373 * @return the boundary
374 */
375 public String getBoundary() {
376 return this.boundary;
377 }
378
379 /**
380 * Creates a new <code>java.net.URLConnection</code> object from the
381 * specified <code>java.net.URL</code>. This is a convenience method
382 * which will set the <code>doInput</code>, <code>doOutput</code>,
383 * <code>useCaches</code> and <code>defaultUseCaches</code> fields to
384 * the appropriate settings in the correct order.
385 *
386 * @return a <code>java.net.URLConnection</code> object for the URL
387 * @throws java.io.IOException on input/output errors
388 */
389 public static URLConnection createConnection(URL url)
390 throws java.io.IOException {
391 URLConnection urlConn = url.openConnection();
392 if(urlConn instanceof HttpURLConnection) {
393 HttpURLConnection httpConn = (HttpURLConnection)urlConn;
394 httpConn.setRequestMethod("POST");
395 }
396 urlConn.setDoInput(true);
397 urlConn.setDoOutput(true);
398 urlConn.setUseCaches(false);
399 urlConn.setDefaultUseCaches(false);
400 return urlConn;
401 }
402
403 /**
404 * Creates a multipart boundary string by concatenating 20 hyphens (-)
405 * and the hexadecimal (base-16) representation of the current time in
406 * milliseconds.
407 *
408 * @return a multipart boundary string
409 * @see #getContentType(String)
410 */
411 public static String createBoundary() {
412 return "--------------------" +
413 Long.toString(System.currentTimeMillis(), 16);
414 }
415
416 /**
417 * Gets the content type string suitable for the
418 * <code>java.net.URLConnection</code> which includes the multipart
419 * boundary string. <br/>
420 * <br/>
421 * This method is static because, due to the nature of the
422 * <code>java.net.URLConnection</code> class, once the output stream
423 * for the connection is acquired, it's too late to set the content
424 * type (or any other request parameter). So one has to create a
425 * multipart boundary string first before using this class, such as
426 * with the <code>createBoundary()</code> method.
427 *
428 * @param boundary the boundary string
429 * @return the content type string
430 * @see #createBoundary()
431 */
432 public static String getContentType(String boundary) {
433 return "multipart/form-data; boundary=" + boundary;
434 }
435}
Note: See TracBrowser for help on using the repository browser.