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

Last change on this file since 2612 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

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