chiark / gitweb /
show pctb server's html if things don't go well
[jarrg-ian.git] / src / com / myjavatools / web / ClientHttpRequest.java
1 package com.myjavatools.web;
2
3 import java.net.URLConnection;
4 import java.net.URL;
5 import java.io.IOException;
6 import java.util.HashMap;
7 import java.util.Map;
8 import java.io.File;
9 import java.io.InputStream;
10 import java.util.Random;
11 import java.io.OutputStream;
12 import java.io.FileInputStream;
13 import java.util.Iterator;
14
15 /**
16  * <p>Title: Client HTTP Request class</p>
17  * <p>Description: this class helps to send POST HTTP requests with various form data,
18  * including files. Cookies can be added to be included in the request.</p>
19  * <p>Modified by Ted Pearson(ted@tedpearson.com) 5/4/09</p>
20  *
21  * @author Vlad Patryshev
22  * @version 1.0
23  */
24 public class ClientHttpRequest {
25   URLConnection connection;
26   OutputStream os = null;
27   Map cookies = new HashMap();
28
29   protected void connect() throws IOException {
30     if (os == null) os = connection.getOutputStream();
31   }
32
33   protected void write(char c) throws IOException {
34     connect();
35     os.write(c);
36   }
37
38   protected void write(String s) throws IOException {
39     connect();
40     os.write(s.getBytes());
41   }
42
43   protected void newline() throws IOException {
44     connect();
45     write("\r\n");
46   }
47
48   protected void writeln(String s) throws IOException {
49     connect();
50     write(s);
51     newline();
52   }
53
54   private static Random random = new Random();
55
56   protected static String randomString() {
57     return Long.toString(random.nextLong(), 36);
58   }
59
60   String boundary = "---------------------------" + randomString() + randomString() + randomString();
61
62   private void boundary() throws IOException {
63     write("--");
64     write(boundary);
65   }
66
67   /**
68    * Creates a new multipart POST HTTP request on a freshly opened URLConnection
69    *
70    * @param connection an already open URL connection
71    * @throws IOException
72    */
73   public ClientHttpRequest(URLConnection connection) throws IOException {
74     this.connection = connection;
75     connection.setDoOutput(true);
76     connection.setRequestProperty("Content-Type",
77                                   "multipart/form-data; boundary=" + boundary);
78   }
79
80   /**
81    * Creates a new multipart POST HTTP request for a specified URL
82    *
83    * @param url the URL to send request to
84    * @throws IOException
85    */
86   public ClientHttpRequest(URL url) throws IOException {
87     this(url.openConnection());
88   }
89
90   /**
91    * Creates a new multipart POST HTTP request for a specified URL string
92    *
93    * @param urlString the string representation of the URL to send request to
94    * @throws IOException
95    */
96   public ClientHttpRequest(String urlString) throws IOException {
97     this(new URL(urlString));
98   }
99
100
101   private void postCookies() {
102     StringBuffer cookieList = new StringBuffer();
103
104     for (Iterator i = cookies.entrySet().iterator(); i.hasNext();) {
105       Map.Entry entry = (Map.Entry)(i.next());
106       cookieList.append(entry.getKey().toString() + "=" + entry.getValue());
107
108       if (i.hasNext()) {
109         cookieList.append("; ");
110       }
111     }
112     if (cookieList.length() > 0) {
113       connection.setRequestProperty("Cookie", cookieList.toString());
114     }
115   }
116
117   /**
118    * adds a cookie to the requst
119    * @param name cookie name
120    * @param value cookie value
121    * @throws IOException
122    */
123   public void setCookie(String name, String value) throws IOException {
124     cookies.put(name, value);
125   }
126
127   /**
128    * adds cookies to the request
129    * @param cookies the cookie "name-to-value" map
130    * @throws IOException
131    */
132   public void setCookies(Map cookies) throws IOException {
133     if (cookies == null) return;
134     this.cookies.putAll(cookies);
135   }
136
137   /**
138    * adds cookies to the request
139    * @param cookies array of cookie names and values (cookies[2*i] is a name, cookies[2*i + 1] is a value)
140    * @throws IOException
141    */
142   public void setCookies(String[] cookies) throws IOException {
143     if (cookies == null) return;
144     for (int i = 0; i < cookies.length - 1; i+=2) {
145       setCookie(cookies[i], cookies[i+1]);
146     }
147   }
148
149   private void writeName(String name) throws IOException {
150     newline();
151     write("Content-Disposition: form-data; name=\"");
152     write(name);
153     write('"');
154   }
155
156   /**
157    * adds a string parameter to the request
158    * @param name parameter name
159    * @param value parameter value
160    * @throws IOException
161    */
162   public void setParameter(String name, String value) throws IOException {
163     boundary();
164     writeName(name);
165     newline(); newline();
166     writeln(value);
167   }
168
169   private static void pipe(InputStream in, OutputStream out) throws IOException {
170     byte[] buf = new byte[500000];
171     int nread;
172     int navailable;
173     int total = 0;
174     synchronized (in) {
175       while((nread = in.read(buf, 0, buf.length)) >= 0) {
176         out.write(buf, 0, nread);
177         total += nread;
178       }
179     }
180     out.flush();
181     buf = null;
182   }
183
184   /**
185    * adds a file parameter to the request
186    * @param name parameter name
187    * @param filename the name of the file
188    * @param is input stream to read the contents of the file from
189    * @throws IOException
190    */
191   public void setParameter(String name, String filename, InputStream is) throws IOException {
192     String type = connection.guessContentTypeFromName(filename);
193     if (type == null) type = "application/octet-stream";
194     setParameter(name, filename, is, type);
195   }
196   
197   /**
198    * adds a file parameter to the request
199    * @param name parameter name
200    * @param filename the name of the file
201    * @param is input stream to read the contents of the file from
202    * @param type Content-Type of the file
203    * @throws IOException
204    */
205   public void setParameter(String name, String filename, InputStream is, String type) throws IOException {
206     boundary();
207     writeName(name);
208     write("; filename=\"");
209     write(filename);
210     write('"');
211     newline();
212     write("Content-Type: ");
213     writeln(type);
214     newline();
215     pipe(is, os);
216     newline();
217   }
218
219   /**
220    * adds a file parameter to the request
221    * @param name parameter name
222    * @param file the file to upload
223    * @throws IOException
224    */
225   public void setParameter(String name, File file) throws IOException {
226     setParameter(name, file.getPath(), new FileInputStream(file));
227   }
228
229   /**
230    * adds a parameter to the request; if the parameter is a File, the file is uploaded, otherwise the string value of the parameter is passed in the request
231    * @param name parameter name
232    * @param object parameter value, a File or anything else that can be stringified
233    * @throws IOException
234    */
235   public void setParameter(String name, Object object) throws IOException {
236     if (object instanceof File) {
237       setParameter(name, (File) object);
238     } else {
239       setParameter(name, object.toString());
240     }
241   }
242
243   /**
244    * adds parameters to the request
245    * @param parameters "name-to-value" map of parameters; if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
246    * @throws IOException
247    */
248   public void setParameters(Map parameters) throws IOException {
249     if (parameters == null) return;
250     for (Iterator i = parameters.entrySet().iterator(); i.hasNext();) {
251       Map.Entry entry = (Map.Entry)i.next();
252       setParameter(entry.getKey().toString(), entry.getValue());
253     }
254   }
255
256   /**
257    * adds parameters to the request
258    * @param parameters array of parameter names and values (parameters[2*i] is a name, parameters[2*i + 1] is a value); if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
259    * @throws IOException
260    */
261   public void setParameters(Object[] parameters) throws IOException {
262     if (parameters == null) return;
263     for (int i = 0; i < parameters.length - 1; i+=2) {
264       setParameter(parameters[i].toString(), parameters[i+1]);
265     }
266   }
267
268   /**
269    * posts the requests to the server, with all the cookies and parameters that were added
270    * @return input stream with the server response
271    * @throws IOException
272    */
273   public InputStream post() throws IOException {
274     boundary();
275     writeln("--");
276     os.close();
277     InputStream tis;
278     try {
279         tis = connection.getInputStream();
280     } catch (IOException e) {
281         tis = ((java.net.HttpURLConnection) connection).getErrorStream();
282     }
283     return tis;
284   }
285
286   /**
287    * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
288    * @param parameters request parameters
289    * @return input stream with the server response
290    * @throws IOException
291    * @see setParameters
292    */
293   public InputStream post(Map parameters) throws IOException {
294     setParameters(parameters);
295     return post();
296   }
297
298   /**
299    * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
300    * @param parameters request parameters
301    * @return input stream with the server response
302    * @throws IOException
303    * @see setParameters
304    */
305   public InputStream post(Object[] parameters) throws IOException {
306     setParameters(parameters);
307     return post();
308   }
309
310   /**
311    * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
312    * @param cookies request cookies
313    * @param parameters request parameters
314    * @return input stream with the server response
315    * @throws IOException
316    * @see setParameters
317    * @see setCookies
318    */
319   public InputStream post(Map cookies, Map parameters) throws IOException {
320     setCookies(cookies);
321     setParameters(parameters);
322     return post();
323   }
324
325   /**
326    * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
327    * @param cookies request cookies
328    * @param parameters request parameters
329    * @return input stream with the server response
330    * @throws IOException
331    * @see setParameters
332    * @see setCookies
333    */
334   public InputStream post(String[] cookies, Object[] parameters) throws IOException {
335     setCookies(cookies);
336     setParameters(parameters);
337     return post();
338   }
339
340   /**
341    * post the POST request to the server, with the specified parameter
342    * @param name parameter name
343    * @param value parameter value
344    * @return input stream with the server response
345    * @throws IOException
346    * @see setParameter
347    */
348   public InputStream post(String name, Object value) throws IOException {
349     setParameter(name, value);
350     return post();
351   }
352
353   /**
354    * post the POST request to the server, with the specified parameters
355    * @param name1 first parameter name
356    * @param value1 first parameter value
357    * @param name2 second parameter name
358    * @param value2 second parameter value
359    * @return input stream with the server response
360    * @throws IOException
361    * @see setParameter
362    */
363   public InputStream post(String name1, Object value1, String name2, Object value2) throws IOException {
364     setParameter(name1, value1);
365     return post(name2, value2);
366   }
367
368   /**
369    * post the POST request to the server, with the specified parameters
370    * @param name1 first parameter name
371    * @param value1 first parameter value
372    * @param name2 second parameter name
373    * @param value2 second parameter value
374    * @param name3 third parameter name
375    * @param value3 third parameter value
376    * @return input stream with the server response
377    * @throws IOException
378    * @see setParameter
379    */
380   public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
381     setParameter(name1, value1);
382     return post(name2, value2, name3, value3);
383   }
384
385   /**
386    * post the POST request to the server, with the specified parameters
387    * @param name1 first parameter name
388    * @param value1 first parameter value
389    * @param name2 second parameter name
390    * @param value2 second parameter value
391    * @param name3 third parameter name
392    * @param value3 third parameter value
393    * @param name4 fourth parameter name
394    * @param value4 fourth parameter value
395    * @return input stream with the server response
396    * @throws IOException
397    * @see setParameter
398    */
399   public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
400     setParameter(name1, value1);
401     return post(name2, value2, name3, value3, name4, value4);
402   }
403
404   /**
405    * posts a new request to specified URL, with parameters that are passed in the argument
406    * @param parameters request parameters
407    * @return input stream with the server response
408    * @throws IOException
409    * @see setParameters
410    */
411   public static InputStream post(URL url, Map parameters) throws IOException {
412     return new ClientHttpRequest(url).post(parameters);
413   }
414
415   /**
416    * posts a new request to specified URL, with parameters that are passed in the argument
417    * @param parameters request parameters
418    * @return input stream with the server response
419    * @throws IOException
420    * @see setParameters
421    */
422   public static InputStream post(URL url, Object[] parameters) throws IOException {
423     return new ClientHttpRequest(url).post(parameters);
424   }
425
426   /**
427    * posts a new request to specified URL, with cookies and parameters that are passed in the argument
428    * @param cookies request cookies
429    * @param parameters request parameters
430    * @return input stream with the server response
431    * @throws IOException
432    * @see setCookies
433    * @see setParameters
434    */
435   public static InputStream post(URL url, Map cookies, Map parameters) throws IOException {
436     return new ClientHttpRequest(url).post(cookies, parameters);
437   }
438
439   /**
440    * posts a new request to specified URL, with cookies and parameters that are passed in the argument
441    * @param cookies request cookies
442    * @param parameters request parameters
443    * @return input stream with the server response
444    * @throws IOException
445    * @see setCookies
446    * @see setParameters
447    */
448   public static InputStream post(URL url, String[] cookies, Object[] parameters) throws IOException {
449     return new ClientHttpRequest(url).post(cookies, parameters);
450   }
451
452   /**
453    * post the POST request specified URL, with the specified parameter
454    * @param name parameter name
455    * @param value parameter value
456    * @return input stream with the server response
457    * @throws IOException
458    * @see setParameter
459    */
460   public static InputStream post(URL url, String name1, Object value1) throws IOException {
461     return new ClientHttpRequest(url).post(name1, value1);
462   }
463
464   /**
465    * post the POST request to specified URL, with the specified parameters
466    * @param name1 first parameter name
467    * @param value1 first parameter value
468    * @param name2 second parameter name
469    * @param value2 second parameter value
470    * @return input stream with the server response
471    * @throws IOException
472    * @see setParameter
473    */
474   public static InputStream post(URL url, String name1, Object value1, String name2, Object value2) throws IOException {
475     return new ClientHttpRequest(url).post(name1, value1, name2, value2);
476   }
477
478   /**
479    * post the POST request to specified URL, with the specified parameters
480    * @param name1 first parameter name
481    * @param value1 first parameter value
482    * @param name2 second parameter name
483    * @param value2 second parameter value
484    * @param name3 third parameter name
485    * @param value3 third parameter value
486    * @return input stream with the server response
487    * @throws IOException
488    * @see setParameter
489    */
490   public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
491     return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3);
492   }
493
494   /**
495    * post the POST request to specified URL, with the specified parameters
496    * @param name1 first parameter name
497    * @param value1 first parameter value
498    * @param name2 second parameter name
499    * @param value2 second parameter value
500    * @param name3 third parameter name
501    * @param value3 third parameter value
502    * @param name4 fourth parameter name
503    * @param value4 fourth parameter value
504    * @return input stream with the server response
505    * @throws IOException
506    * @see setParameter
507    */
508   public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
509     return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3, name4, value4);
510   }
511 }