package org.myrobotlab.net;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.slf4j.Logger;
/**
* Client HTTP Request class This class helps to send POST HTTP requests with
* various form data, including files. Cookies can be added to be included in
* the request.
*
* @author Vlad Patryshev
* @version 1.0
*
* Modified by grog - added buffered output to increase performance in
* larger POSTs. In file operations buffered output is 10x faster.
* Currently, a POST of a large file takes ~6 seconds TODO - fill in
* details and result
*
* References:
* http://www.javabeat.net/tips/36-file-upload-and-download-
* using-java.html http://www.java2s.com/Code/Java/File-Input-Output/
* ComparingBufferedandUnbufferedWritingPerformance.htm
*
* The big beautiful kahuna from stack overflow
* http://stackoverflow.com
* /questions/2793150/how-to-use-java-net-urlconnection
* -to-fire-and-handle-http-requests Proxy info -
* http://edn.embarcadero.com/article/29783 Proxy info -
* http://docs.oracle
* .com/javase/6/docs/technotes/guides/net/proxies.html Proxy info -
* http
* ://stackoverflow.com/questions/120797/how-do-i-set-the-proxy-to-be
* -used-by-the-jvm
*
*/
public class HttpRequest {
public final static Logger log = LoggerFactory.getLogger(HttpRequest.class);
URLConnection connection;
OutputStream osstr = null;
BufferedOutputStream os = null;
Map<String, String> cookies = new HashMap<String, String>();
String boundary = "---------------------------";
String error = null;
public static void main(String[] args) throws Exception {
Logging logging = LoggingFactory.getInstance();
logging.configure();
LoggingFactory.getInstance().setLevel(Level.DEBUG);
// HTTPRequest http;
// http = new HTTPRequest("http://www.google.com");
// String s = http.getString();
HttpRequest.postFile("http://myrobotlab.org/myrobotlab_log/postLogFile.php", "GroG", "file", new File(LoggingFactory.getLogFileName()));
/*
*
* HTTPRequest http = new HTTPRequest(
* "http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/"
* ); String s = http.getString(); log.info(s);
*
* String language = "en"; String toSpeak = "hello"; URI uri = new
* URI("http", null, "translate.google.com", 80, "/translate_tts", "tl=" +
* language + "&q=" + toSpeak, null);
*
* URL url = uri.toURL();
*
* HttpURLConnection.setFollowRedirects(true); HttpURLConnection connection
* = (HttpURLConnection) url.openConnection(); System.out.println(
* "Response code = " + connection.getResponseCode()); String header =
* connection.getHeaderField("location"); if (header != null)
* System.out.println("Redirected to " + header);
*
* HTTPRequest request = new HTTPRequest(uri.toURL()); request.getBinary();
*/
}
/*
* Graciously lifted from - http://stackoverflow.com/questions/2793150/how-to
* -use-java-net-urlconnection-to-fire-and-handle-http-requests
*/
static public String postFile(String url, String userid, String fieldName, File textFile) throws Exception {
// String param = "value";
// File textFile = new File("/path/to/file.txt");
// File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just
// generate
// some
// unique
// random
// value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
String charset = "ISO-8859-1";
OutputStream output = connection.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(output, charset), true); // true
// =
// autoFlush,
// important!
// Send text file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF).flush();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
for (String line; (line = reader.readLine()) != null;) {
writer.append(line).append(CRLF);
}
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException logOrIgnore) {
}
}
// Send normal param.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"user\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF);
writer.append(userid).append(CRLF).flush();
writer.flush();
/*
* // Send binary file. writer.append("--" + boundary).append(CRLF);
* writer.append(
* "Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" +
* binaryFile.getName() + "\"").append(CRLF); writer.append(
* "Content-Type: " + URLConnection.guessContentTypeFromName
* (binaryFile.getName())).append(CRLF); writer.append(
* "Content-Transfer-Encoding: binary").append(CRLF);
* writer.append(CRLF).flush(); InputStream input = null; try { input =
* new FileInputStream(binaryFile); byte[] buffer = new byte[1024]; for
* (int length = 0; (length = input.read(buffer)) > 0;) {
* output.write(buffer, 0, length); } output.flush(); // Important! Output
* cannot be closed. Close of writer will close output as well. } finally
* { if (input != null) try { input.close(); } catch (IOException
* logOrIgnore) {} } writer.append(CRLF).flush(); // CRLF is important! It
* indicates end of binary boundary.
*/
// End of multipart/form-data.
writer.append("--" + boundary + "--").append(CRLF);
writer.append(CRLF).flush(); // CRLF is important! It indicates end
// of binary boundary.
byte[] data;
InputStream in = null;
in = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream bos = new ByteArrayOutputStream(16384);
try {
int BUFFER_SIZE = 16384;
byte[] tmp = new byte[BUFFER_SIZE];
int ret;
while ((ret = in.read(tmp)) > 0) {
bos.write(tmp, 0, ret);
}
} catch (IOException e) {
Logging.logError(e);
}
data = bos.toByteArray();
log.info(String.format("read %d bytes", data.length));
String s = new String(data);
log.info(s);
try {
in.close();
} catch (IOException e) {
// don't care
}
return s;
} finally {
if (writer != null)
writer.close();
}
}
/**
* Creates a new multipart POST HTTP request for a specified URL string
*
* @param urlString
* the string representation of the URL to send request to
* @throws IOException
*/
public HttpRequest(String urlString) throws IOException {
this(new URL(urlString));
}
/**
* Creates a new multipart POST HTTP request for a specified URL
*
* @param url
* the URL to send request to
* @throws IOException
*/
public HttpRequest(URL url) throws IOException {
this(url.openConnection());
}
/**
* Creates a new multipart POST HTTP request on a freshly opened URLConnection
*
* @param connection
* an already open URL connection
* @throws IOException
*/
public HttpRequest(URLConnection connection) throws IOException {
log.info("http request for " + connection.getURL());
this.connection = connection;
connection.setDoOutput(true);
}
private void boundary() throws IOException {
write("--");
write(boundary);
}
protected void connect() throws IOException {
if (os == null)
os = new BufferedOutputStream(connection.getOutputStream());
}
public byte[] getBinary() throws IOException {
// URL u = new URL("http://www.java2s.com/binary.dat");
// URLConnection uc = url.openConnection();
String contentType = null;
int contentLength = -1;
// a little weird - this will throw NoSuchElementException
// if nothing was recieved
contentType = connection.getContentType();
contentLength = connection.getContentLength();
log.info(String.format("contentType %s contentLength %d", contentType, contentLength));
InputStream raw;
byte[] data = null;
int initSize = (contentLength == -1) ? 65536 : contentLength;
ByteArrayOutputStream bos = new ByteArrayOutputStream(initSize);
InputStream in = null;
// try {
raw = connection.getInputStream();
in = new BufferedInputStream(raw);
byte[] tmp = new byte[initSize];
int ret;
while ((ret = in.read(tmp)) > 0) {
log.debug(String.format("read %d bytes", ret));
bos.write(tmp, 0, ret);
}
/*
* } catch (IOException e) { Logging.logException(e); }
*/
data = bos.toByteArray();
log.info(String.format("read %d bytes", data.length));
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
// don't care
}
/*
*
* try { // content size sent back data = new byte[contentLength]; int
* bytesRead = 0; int offset = 0; while (offset < contentLength) { bytesRead
* = in.read(data, offset, data.length - offset); if (bytesRead == -1)
* break; offset += bytesRead; } in.close();
*
* if (offset != contentLength) { throw new IOException("Only read " +
* offset + " bytes; Expected " + contentLength + " bytes"); } } catch
* (IOException e1) { Logging.logException(e1); error = e1.getMessage(); } }
*/
/*
* String filename = u.getFile().substring(filename.lastIndexOf('/') + 1);
*/
/*
* FileOutputStream out; try { out = new FileOutputStream("hello.mp3");
* out.write(data); out.flush(); out.close(); } catch (Exception e) { //
* TODO Auto-generated catch block e.printStackTrace(); }
*/
return data;
}
public String getError() {
return error;
}
public String getString() throws IOException {
byte[] b = getBinary();
if (b != null) {
return new String(b);
}
return null;
}
public boolean hasError() {
return error != null;
}
protected void newline() throws IOException {
connect();
write("\r\n");
}
private void pipe(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[500000];
int nread;
// int navailable;
// int total = 0;
synchronized (in) {
while ((nread = in.read(buf, 0, buf.length)) >= 0) {
out.write(buf, 0, nread);
// total += nread;
}
}
out.flush();
in.close();
buf = null;
}
/**
* posts the requests to the server, with all the cookies and parameters that
* were added
*
* @return input stream with the server response
* @throws IOException
*/
public InputStream post() {
try {
boundary();
writeln("--");
os.close();
return connection.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
}
return null;
}
/**
* 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
*
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setParameters
*/
public InputStream post(Map<String, String> parameters) throws IOException {
setParameters(parameters);
return post();
}
/**
* 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
*
* @param cookies
* request cookies
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setParameters
* @see setCookies
*/
public InputStream post(Map<String, String> cookies, Map<String, String> parameters) throws IOException {
setCookies(cookies);
setParameters(parameters);
return post();
}
/**
* 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
*
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setParameters
*/
public InputStream post(Object[] parameters) throws IOException {
setParameters(parameters);
return post();
}
/**
* post the POST request to the server, with the specified parameter
*
* @param name
* parameter name
* @param value
* parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(String name, Object value) throws IOException {
setParameter(name, value);
return post();
}
/**
* post the POST request to the server, with the specified parameters
*
* @param name1
* first parameter name
* @param value1
* first parameter value
* @param name2
* second parameter name
* @param value2
* second parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(String name1, Object value1, String name2, Object value2) throws IOException {
setParameter(name1, value1);
return post(name2, value2);
}
/**
* post the POST request to the server, with the specified parameters
*
* @param name1
* first parameter name
* @param value1
* first parameter value
* @param name2
* second parameter name
* @param value2
* second parameter value
* @param name3
* third parameter name
* @param value3
* third parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
setParameter(name1, value1);
return post(name2, value2, name3, value3);
}
/**
* post the POST request to the server, with the specified parameters
*
* @param name1
* first parameter name
* @param value1
* first parameter value
* @param name2
* second parameter name
* @param value2
* second parameter value
* @param name3
* third parameter name
* @param value3
* third parameter value
* @param name4
* fourth parameter name
* @param value4
* fourth parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
setParameter(name1, value1);
return post(name2, value2, name3, value3, name4, value4);
}
/**
* 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
*
* @param cookies
* request cookies
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setParameters
* @see setCookies
*/
public InputStream post(String[] cookies, Object[] parameters) throws IOException {
setCookies(cookies);
setParameters(parameters);
return post();
}
/**
* posts a new request to specified URL, with parameters that are passed in
* the argument
*
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setParameters
*/
public InputStream post(URL url, Map<String, String> parameters) throws IOException {
return new HttpRequest(url).post(parameters);
}
/**
* posts a new request to specified URL, with cookies and parameters that are
* passed in the argument
*
* @param cookies
* request cookies
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setCookies
* @see #setParameters
*/
public InputStream post(URL url, Map<String, String> cookies, Map<String, String> parameters) throws IOException {
return new HttpRequest(url).post(cookies, parameters);
}
/**
* posts a new request to specified URL, with parameters that are passed in
* the argument
*
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setParameters
*/
public InputStream post(URL url, Object[] parameters) throws IOException {
return new HttpRequest(url).post(parameters);
}
/**
* post the POST request specified URL, with the specified parameter
*
* @param path
* parameter name
* @param value
* parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(URL url, String name1, Object value1) throws IOException {
return new HttpRequest(url).post(name1, value1);
}
/**
* post the POST request to specified URL, with the specified parameters
*
* @param name1
* first parameter name
* @param value1
* first parameter value
* @param name2
* second parameter name
* @param value2
* second parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(URL url, String name1, Object value1, String name2, Object value2) throws IOException {
return new HttpRequest(url).post(name1, value1, name2, value2);
}
/**
* post the POST request to specified URL, with the specified parameters
*
* @param name1
* first parameter name
* @param value1
* first parameter value
* @param name2
* second parameter name
* @param value2
* second parameter value
* @param name3
* third parameter name
* @param value3
* third parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
return new HttpRequest(url).post(name1, value1, name2, value2, name3, value3);
}
/**
* post the POST request to specified URL, with the specified parameters
*
* @param name1
* first parameter name
* @param value1
* first parameter value
* @param name2
* second parameter name
* @param value2
* second parameter value
* @param name3
* third parameter name
* @param value3
* third parameter value
* @param name4
* fourth parameter name
* @param value4
* fourth parameter value
* @return input stream with the server response
* @throws IOException
* @see #setParameter
*/
public InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
return new HttpRequest(url).post(name1, value1, name2, value2, name3, value3, name4, value4);
}
/**
* posts a new request to specified URL, with cookies and parameters that are
* passed in the argument
*
* @param cookies
* request cookies
* @param parameters
* request parameters
* @return input stream with the server response
* @throws IOException
* @see #setCookies
* @see #setParameters
*/
public InputStream post(URL url, String[] cookies, Object[] parameters) throws IOException {
return new HttpRequest(url).post(cookies, parameters);
}
public void postCookies() {
StringBuffer cookieList = new StringBuffer();
for (Iterator<Entry<String, String>> i = cookies.entrySet().iterator(); i.hasNext();) {
Entry<String, String> entry = (i.next());
cookieList.append(entry.getKey().toString() + "=" + entry.getValue());
if (i.hasNext()) {
cookieList.append("; ");
}
}
if (cookieList.length() > 0) {
connection.setRequestProperty("Cookie", cookieList.toString());
}
}
/**
* adds a cookie to the requst
*
* @param name
* cookie name
* @param value
* cookie value
* @throws IOException
*/
public void setCookie(String name, String value) throws IOException {
cookies.put(name, value);
}
/**
* adds cookies to the request
*
* @param cookies
* the cookie "name-to-value" map
* @throws IOException
*/
public void setCookies(Map<String, String> cookies) throws IOException {
if (cookies == null)
return;
this.cookies.putAll(cookies);
}
/**
* adds cookies to the request
*
* @param cookies
* array of cookie names and values (cookies[2*i] is a name,
* cookies[2*i + 1] is a value)
* @throws IOException
*/
public void setCookies(String[] cookies) throws IOException {
if (cookies == null)
return;
for (int i = 0; i < cookies.length - 1; i += 2) {
setCookie(cookies[i], cookies[i + 1]);
}
}
/**
* adds a file parameter to the request
*
* @param name
* parameter name
* @param file
* the file to upload
* @throws IOException
*/
public void setParameter(String name, File file) throws IOException {
Logging.logTime("pre set file");
setParameter(name, file.getPath(), new FileInputStream(file));
Logging.logTime("post set file");
}
/**
* 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
*
* @param name
* parameter name
* @param object
* parameter value, a File or anything else that can be stringified
* @throws IOException
*/
public void setParameter(String name, Object object) throws IOException {
if (object instanceof File) {
setParameter(name, (File) object);
} else {
setParameter(name, object.toString());
}
}
/**
* adds a string parameter to the request
*
* @param name
* parameter name
* @param value
* parameter value
* @throws IOException
*/
public void setParameter(String name, String value) throws IOException {
boundary();
writeName(name);
newline();
newline();
writeln(value);
}
/**
* adds a file parameter to the request
*
* @param name
* parameter name
* @param filename
* the name of the file
* @param is
* input stream to read the contents of the file from
* @throws IOException
*/
public void setParameter(String name, String filename, InputStream is) throws IOException {
Logging.logTime("setParameter begin (after new fileinput)");
boundary();
writeName(name);
write("; filename=\"");
write(filename);
write('"');
newline();
write("Content-Type: ");
Logging.logTime("pre guessContentTypeFromName");
String type = URLConnection.guessContentTypeFromName(filename);
if (type == null)
type = "application/octet-stream";
writeln(type);
Logging.logTime("post guessContentTypeFromName");
newline();
pipe(is, os);
newline();
}
/**
* adds parameters to the request
*
* @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
* @throws IOException
*/
public void setParameters(Map<String, String> parameters) throws IOException {
if (parameters == null)
return;
for (Iterator i = parameters.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
setParameter(entry.getKey().toString(), entry.getValue());
}
}
/**
* adds parameters to the request
*
* @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
* @throws IOException
*/
public void setParameters(Object[] parameters) throws IOException {
if (parameters == null)
return;
for (int i = 0; i < parameters.length - 1; i += 2) {
setParameter(parameters[i].toString(), parameters[i + 1]);
}
}
public void setRequestProperty(String key, String value) {
if (connection != null) {
connection.setRequestProperty(key, value);
}
}
protected void write(char c) throws IOException {
connect();
os.write(c);
}
protected void write(String s) throws IOException {
Logging.logTime("write-connect");
connect();
Logging.logTime("write-post connect");
os.write(s.getBytes());
Logging.logTime("post write s.getBytes");
}
protected void writeln(String s) throws IOException {
connect();
write(s);
newline();
}
private void writeName(String name) throws IOException {
newline();
write("Content-Disposition: form-data; name=\"");
write(name);
write('"');
}
}