package javaforce;
/** HTTP Client
*
* @author pquiring
*/
import java.net.*;
import java.io.*;
import java.util.*;
public class HTTP {
protected Socket s;
protected OutputStream os;
protected InputStream is;
protected String host;
protected int port;
private Parameters request_headers = new Parameters();
private Parameters reply_headers = new Parameters();
private int code = -1;
public static boolean debug = false;
private Progress progress;
private static int timeout = 30000;
public static final String formType = "application/x-www-form-urlencoded";
private final static int bufsiz = 1024;
public static class Parameters {
private HashMap params = new HashMap<>();
public String get(String name) {
return params.get(name);
}
public void put(String name, String value) {
params.put(name, value);
}
public String[] keys() {
return params.keySet().toArray(JF.StringArrayType);
}
public void clear() {
params.clear();
}
public HashMap getHashMap() {
return params;
}
public static Parameters decode(String[] headers, int offset) {
Parameters p = new Parameters();
for(int i=offset;i 0) {
System.arraycopy(buf, pos, newbuf, 0, count);
}
buf = newbuf;
pos = 0;
}
public void condense() {
if (pos == 0) return;
if (count == 0) {
pos = 0;
return;
}
System.arraycopy(buf, pos, buf, 0, count);
pos = 0;
}
public void consume(int length) {
if (length > count) {
JFLog.log("HTTP:Error:Buffer.consume(length > count)");
}
pos += length;
count -= length;
if (count == 0) {
pos = 0;
}
}
public void consumeAll() {
pos = 0;
count = 0;
}
public void setLength(int length) {
if (buf.length == length) return;
byte[] newbuf = new byte[length];
if (buf.length > length) {
//copy part
System.arraycopy(buf, pos, newbuf, 0, length);
} else {
//copy all
System.arraycopy(buf, pos, newbuf, 0, count);
}
buf = newbuf;
pos = 0;
}
public void append(Buffer other) {
if (other.count == 0) return;
while (buf.length < count + other.count) {
expand();
}
if (pos > 0) condense();
System.arraycopy(other.buf, other.pos, buf, pos + count, other.count);
count += other.count;
other.consumeAll();
}
public void append(Buffer other, int maxCopy) {
if (other.count == 0) return;
if (maxCopy == 0) return;
int toCopy = maxCopy;
if (other.count < maxCopy) toCopy = other.count;
while (buf.length < count + toCopy) {
expand();
}
if (pos > 0) condense();
System.arraycopy(other.buf, other.pos, buf, pos + count, toCopy);
count += toCopy;
other.consume(toCopy);
}
public byte[] toArray() {
if (count != buf.length) {
return Arrays.copyOfRange(buf, pos, pos + count);
}
return buf;
}
}
/** Removes user info from HTTP URL. */
public static String cleanURL(String url) {
return JF.cleanURL(url);
}
public static String getUserInfo(String urlstr) {
try {
return new URI(urlstr).toURL().getUserInfo();
} catch (Exception e) {
return null;
}
}
public static String getHost(String urlstr) {
try {
return new URI(urlstr).toURL().getHost();
} catch (Exception e) {
return null;
}
}
public static int getPort(String urlstr) {
try {
return new URI(urlstr).toURL().getPort();
} catch (Exception e) {
return 80;
}
}
/** Set connect/read timeout in ms (default = 30000) */
public static void setTimeout(int timeout) {
HTTP.timeout = timeout;
}
public boolean open(String host) {
return open(host, 80);
}
public boolean open(String host, int port) {
this.host = host;
this.port = port;
try {
if (debug) JFLog.log("HTTP.connect:" + host + ":" + port);
s = new Socket();
s.connect(new InetSocketAddress(host, port), timeout);
s.setSoTimeout(timeout);
os = s.getOutputStream();
is = s.getInputStream();
} catch (Exception e) {
JFLog.log(e);
if (s != null) {
try {s.close();} catch (Exception e2) {}
s = null;
}
s = null;
return false;
}
return true;
}
/** Close connection. */
public void close() {
if (s != null) {
try {
s.close();
} catch (Exception e) {
JFLog.log(e);
}
s = null;
}
}
/** Returns connection status. */
public boolean isConnected() {
return s != null;
}
/** Registers a download progress listener. */
public void setProgressListener(Progress progress) {
this.progress = progress;
}
/** Set a request header. */
public void setHeader(String key, String value) {
request_headers.put(key, value);
}
/** Clears all request headers. */
public void clearHeaders() {
request_headers.clear();
}
/** Returns reply header. */
public String getHeader(String key) {
return reply_headers.get(key);
}
/** Returns reply headers. */
public HashMap getHeaders() {
return reply_headers.getHashMap();
}
/** Returns last status code. */
public int getCode() {
return code;
}
private int read(Buffer buf, int length) throws Exception {
if (buf.count >= length) return length;
int maxlength = buf.buf.length - buf.pos - buf.count;
if (length > maxlength) {
if (buf.pos > 0) {
buf.condense();
maxlength = buf.buf.length - buf.count;
}
}
if (length > maxlength) {
length = maxlength;
if (length == 0) {
JFLog.log("HTTP:Error:buffer full:" + buf.buf.length + "," + buf.pos + "," + buf.count);
return 0;
}
}
int read = is.read(buf.buf, buf.pos + buf.count, length);
if (read > 0) {
buf.count += read;
}
return read;
}
private void write(byte[] data) throws Exception {
os.write(data);
}
private void sendRequest(String req) throws Exception {
write(req.getBytes("UTF-8"));
}
private void sendData(byte[] data) throws Exception {
write(data);
}
private boolean endOfHeaders(Buffer buf) {
if (buf.count < 4) return false;
int length = buf.count;
return ((buf.buf[length-4] == '\r') && (buf.buf[length-3] == '\n') && (buf.buf[length-2] == '\r') && (buf.buf[length-1] == '\n'));
}
private boolean haveChunkLength(Buffer buf) {
if (buf.count < 2) return false;
int length = buf.count;
int start = buf.pos;
int end = buf.pos + length - 1;
for(int pos=start;pos= '0') && (digit <= '9')) {
value += (digit - '0');
} else if ((digit >= 'A' && digit <= 'F')) {
value += (digit - 'A' + 10);
} else if ((digit >= 'a' && digit <= 'f')) {
value += (digit - 'a' + 10);
} else {
JFLog.log("HTTP:Error:Invalid chunk length");
return -1;
}
buf.consume(1);
}
buf.consume(2); //consume \r\n
return value;
}
private boolean getReply(OutputStream os) throws Exception {
Buffer buf = new Buffer();
Buffer req = new Buffer();
//read headers
reply_headers.clear();
do {
int read = read(buf, bufsiz);
buf.pos = 0;
buf.count = read;
while (buf.count > 0) {
if (req.count == req.buf.length) {
req.expand();
}
req.buf[req.count++] = buf.buf[buf.pos++];
buf.count--;
read--;
if (endOfHeaders(req)) break;
}
} while (!endOfHeaders(req));
//parse headers
long length = -1;
boolean chunked = false;
String[] lns = new String(req.toArray()).split("\r\n");
for(int i=1;i 0) {
int toCopy = buf.count;
if (toCopy > chunkLength) toCopy = chunkLength;
os.write(buf.buf, buf.pos, toCopy);
chunkLength -= toCopy;
buf.consume(toCopy);
copied += toCopy;
}
while (chunkLength > 0) {
int toread = chunkLength;
if (toread > bufsiz) toread = bufsiz;
int read = read(buf, toread);
if (read > 0) {
copied += read;
if (progress != null) {
progress.progress(copied, -1);
}
os.write(buf.buf, buf.pos, read);
chunkLength -= read;
buf.consume(read);
}
}
//read \r\n
while (buf.count < 2) {
read(buf, 2 - buf.count);
}
buf.consume(2);
if (endOfChunks) {
if (disconn) close();
return true;
}
} else {
read(buf, bufsiz);
}
}
} else if (length != -1) {
if (debug) System.out.println("HTTP:Reading Length:" + length);
//read length data
if (buf.count > 0) {
copied += buf.count;
os.write(buf.toArray());
buf.consumeAll();
}
while (copied < length) {
int toread = bufsiz;
if (toread > length) {
toread = (int)length;
}
int read = read(buf, toread);
if (read > 0) {
copied += read;
if (progress != null) {
progress.progress(copied, length);
}
os.write(buf.toArray());
buf.consume(read);
}
}
if (disconn) close();
return true;
} else {
if (debug) System.out.println("HTTP:Reading till carrier dropped");
//read till carrier is dropped
do {
if (buf.count > 0) {
copied += buf.count;
if (progress != null) {
progress.progress(copied, -1);
}
os.write(buf.toArray());
buf.consumeAll();
}
} while (read(buf, bufsiz) >= 0);
if (disconn) close();
return true;
}
}
/** Append user headers. */
private void appendHeaders(StringBuilder req) {
String[] keys = request_headers.keys();
for(String key : keys) {
String value = request_headers.get(key);
req.append(key + ": " + value + "\r\n");
}
}
/** HTTP GET using url.
* Writes content to OutputStream.
*/
public boolean get(String url, OutputStream os) {
if (debug) {
JFLog.log("HTTP.get():" + url);
}
code = -1;
if (s == null) return false;
StringBuilder req = new StringBuilder();
req.append("GET " + url + " HTTP/1.1\r\n");
req.append("Host: " + host + (port != 80 ? (":" + port) : "") + "\r\n");
req.append("Content-Length: 0\r\n");
req.append("Accept: */*\r\n");
req.append("Accept-Encoding: chunked\r\n");
appendHeaders(req);
req.append("\r\n");
if (debug) {
JFLog.log("request=" + req.toString());
}
try {
sendRequest(req.toString());
return getReply(os);
} catch (Exception e) {
JFLog.log(e);
return false;
}
}
/** HTTP GET using url.
* Returns as a byte[]
*/
public byte[] get(String url) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (!get(url, baos)) return null;
return baos.toByteArray();
}
/** HTTP GET using url.
* Returns as a String.
*/
public String getString(String url) {
return new String(get(url));
}
/** HTTP POST using url with post data encoding with mimeType.
* Writes content to OutputStream.
*/
public boolean post(String url, byte[] data, String mimeType, OutputStream os) {
code = -1;
if (s == null) return false;
StringBuilder req = new StringBuilder();
req.append("POST " + url + " HTTP/1.1\r\n");
req.append("Host: " + host + (port != 80 ? (":" + port) : "") + "\r\n");
req.append("Content-Length: " + data.length + "\r\n");
req.append("Content-Type: " + mimeType + "\r\n");
req.append("Accept: */*\r\n");
req.append("Accept-Encoding: chunked\r\n");
appendHeaders(req);
req.append("\r\n");
try {
sendRequest(req.toString());
sendData(data);
return getReply(os);
} catch (Exception e) {
JFLog.log(e);
return false;
}
}
/** HTTP POST using url with post data encoding with mimeType.
* Returns content as byte[]
*/
public byte[] post(String url, byte[] data, String mimeType) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (!post(url, data, mimeType, baos)) return null;
return baos.toByteArray();
}
/** HTTP POST using url with post data encoding with mimeType.
* Returns content as String.
*/
public String postString(String url, byte[] data, String mimeType) {
return new String(post(url, data, mimeType));
}
/** Test HTTP */
public static void main(String[] args) {
HTTP http = new HTTP();
String html;
boolean print = false;
if (args.length > 0 && args[0].equals("print")) print = true;
debug = true;
http.open("google.com");
html = http.getString("/");
http.close();
if (html == null || html.length() == 0) {
System.out.println("Error:HTTP.get() failed");
return;
}
if (print) System.out.println(html);
http.open("www.google.com");
html = http.getString("/");
http.close();
if (html == null || html.length() == 0) {
System.out.println("Error:HTTP.get() failed");
return;
}
if (print) System.out.println(html);
}
/**
* Returns HTTP style parameter from list of parameters.
*
* @param params = HTTP list of parameters
* @param name = name of parameter to return
* @return parameter
*/
public static String getParameter(String[] params, String name) {
for(int a=0;a lst = new ArrayList<>();
for(int a=0;a content = new ArrayList();
for (int a = 0; a < msg.length; a++) {
//look for double \r\n (which appears as an empty line) that marks end of headers
if (msg[a].length() == 0) {
for (int b = a + 1; b < msg.length; b++) {
content.add(msg[b]);
}
break;
}
}
return content.toArray(JF.StringArrayType);
}
}