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