You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
14 KiB
Java
431 lines
14 KiB
Java
/*
|
|
* Copyright (C) 2009-2017 Alistair Neil <info@dazzleships.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
package lib;
|
|
|
|
import java.io.*;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.Proxy;
|
|
import java.net.Socket;
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.net.URL;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.HashMap;
|
|
import java.util.Locale;
|
|
import java.util.TimeZone;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import javax.swing.JProgressBar;
|
|
|
|
/**
|
|
*
|
|
* @author Alistair Neil, <info@dazzleships.net>
|
|
*/
|
|
public class NetFunctions {
|
|
|
|
public static final int CONNECTION_FAILED = 0;
|
|
public static final int FILE_LOCAL_ISNEWER = 1;
|
|
public static final int FILE_RETRIEVED = 2;
|
|
public static final int FILE_FAILED = 3;
|
|
public static final int EVENT_URLOK = 1;
|
|
public static final int EVENT_URLFAILED = 2;
|
|
public static final int EVENT_NETLATENCY = 3;
|
|
public static final long LATENCY_FAIL = 9999;
|
|
public static final long LATENCY_UNKNOWN = 0;
|
|
private int intSocketTimeout = 8000;
|
|
private JProgressBar jpb;
|
|
|
|
public NetFunctions() {
|
|
}
|
|
|
|
/**
|
|
* Set default socket timeout
|
|
*
|
|
* @param timeout
|
|
*/
|
|
public void setSocketTimeout(int timeout) {
|
|
intSocketTimeout = timeout;
|
|
}
|
|
|
|
public void setProgressBar(JProgressBar jpb) {
|
|
this.jpb = jpb;
|
|
}
|
|
|
|
/**
|
|
* Save the contents of a URL to a file
|
|
*
|
|
* @param destfile File destination path
|
|
* @param sourceurl URL
|
|
* @param socket
|
|
* @param force Forces update regardless of age
|
|
* @return int File retieval status code
|
|
*/
|
|
public int saveURLContentToFile(String destfile, String sourceurl, Socket socket, boolean force) {
|
|
// Get a handle to our local file
|
|
File f = new File(destfile);
|
|
InputStream is = openStreamToURL(sourceurl, socket);
|
|
HttpPage hp = new HttpPage(is);
|
|
int result = FILE_FAILED;
|
|
try {
|
|
socket.setSoTimeout(intSocketTimeout);
|
|
hp.retrieveHeader();
|
|
if (hp.isHeaderOK()) {
|
|
result = FILE_LOCAL_ISNEWER;
|
|
if (hp.getLastModified() > f.lastModified() || force) {
|
|
if (hp.saveBodyToFile(destfile, jpb)) {
|
|
result = FILE_RETRIEVED;
|
|
Logger.getGlobal().logp(Level.INFO, this.getClass().getName(), "saveURLContentToFile", "Http body content retrieved");
|
|
} else {
|
|
Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "saveURLContentToFile", "Failed to retrieve Http body content");
|
|
}
|
|
}
|
|
} else {
|
|
Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "saveURLContentToFile", "Failed to retrieve Http header");
|
|
}
|
|
} catch (IOException ex) {
|
|
Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "saveURLContentToFile", ex.getMessage());
|
|
} finally {
|
|
try {
|
|
is.close();
|
|
socket.close();
|
|
} catch (Exception ex) {
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Make sure ipaddress is valid number
|
|
*
|
|
* @param ipaddress
|
|
* @return true if a valid ip address
|
|
*/
|
|
public boolean isIPAddress(String ipaddress) {
|
|
ipaddress = ipaddress.replace(".", "");
|
|
try {
|
|
Long.parseLong(ipaddress);
|
|
return true;
|
|
} catch (NumberFormatException ex) {
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get latency non threaded version
|
|
*
|
|
* @param surl Testing url
|
|
* @param proxy Specify a proxy, null == no proxy
|
|
* @param timeout Specify a timeout before declaring failure
|
|
* @return long latency in milliseconds
|
|
*/
|
|
public long getLatency(String surl, Proxy proxy, int timeout) {
|
|
|
|
long lngStart;
|
|
long lngResult;
|
|
HttpURLConnection conn = null;
|
|
|
|
try {
|
|
URL url = new URL(surl);
|
|
if (proxy == null) {
|
|
conn = (HttpURLConnection) url.openConnection();
|
|
} else {
|
|
conn = (HttpURLConnection) url.openConnection(proxy);
|
|
}
|
|
conn.setDoInput(true);
|
|
conn.setDefaultUseCaches(false);
|
|
conn.setConnectTimeout(timeout);
|
|
lngStart = System.currentTimeMillis();
|
|
conn.connect();
|
|
lngResult = System.currentTimeMillis() - lngStart;
|
|
} catch (IOException ex) {
|
|
lngResult = LATENCY_FAIL;
|
|
Logger.getGlobal().log(Level.WARNING, "getLatency {0}", ex.getMessage());
|
|
}
|
|
if (conn != null) {
|
|
conn.disconnect();
|
|
}
|
|
return lngResult;
|
|
}
|
|
|
|
/**
|
|
* Check web for updates and return version string if an update is available
|
|
*
|
|
* @param sourceurl URL to check
|
|
* @param s Socket
|
|
* @return String new version number
|
|
*/
|
|
public String getURLContentAsString(String sourceurl, Socket s) {
|
|
|
|
String result = null;
|
|
try {
|
|
s.setSoTimeout(intSocketTimeout);
|
|
try (InputStream is = openStreamToURL(sourceurl, s)) {
|
|
HttpPage hp = new HttpPage(is);
|
|
hp.retrieveHeader();
|
|
if (hp.isHeaderOK()) {
|
|
result = hp.getBodyAsString();
|
|
}
|
|
is.close();
|
|
}
|
|
} catch (Exception ex) {
|
|
Logger.getGlobal().log(Level.WARNING, "getURLAsString", ex.getMessage());
|
|
result = null;
|
|
} finally {
|
|
try {
|
|
s.close();
|
|
} catch (Exception ex) {
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Open an inputstream to the given url on the given socket
|
|
*
|
|
* @param surl
|
|
* @param s
|
|
* @return inputstream
|
|
*/
|
|
public InputStream openStreamToURL(String surl, Socket s) {
|
|
URI uri;
|
|
try {
|
|
uri = new URI(surl);
|
|
String host = uri.getHost();
|
|
String path = uri.getRawPath();
|
|
if (path == null) {
|
|
return null;
|
|
}
|
|
|
|
PrintWriter request = new PrintWriter(s.getOutputStream());
|
|
request.print("GET " + path + " HTTP/1.1\r\n"
|
|
+ "Host: " + host + "\r\n"
|
|
+ "Connection: close\r\n\r\n"
|
|
);
|
|
|
|
request.flush();
|
|
InputStream inStream = s.getInputStream();
|
|
return inStream;
|
|
} catch (URISyntaxException | IOException ex) {
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Store an http formatted web page
|
|
*/
|
|
public static final class HttpPage {
|
|
|
|
public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
|
|
public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
|
|
public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
|
|
private final TimeZone GMT = TimeZone.getTimeZone("GMT");
|
|
private final SimpleDateFormat format = new SimpleDateFormat("", Locale.US);
|
|
private final HashMap<String, String> hm = new HashMap<>();
|
|
private final InputStream israw;
|
|
|
|
/**
|
|
* Store webpage from the given input stream
|
|
*
|
|
* @param is
|
|
*/
|
|
public HttpPage(InputStream is) {
|
|
format.setTimeZone(GMT);
|
|
israw = is;
|
|
}
|
|
|
|
private String readLine(InputStream is) {
|
|
byte data;
|
|
String line = "";
|
|
String term = "";
|
|
try {
|
|
while (!"\r\n".equals(term)) {
|
|
data = (byte) is.read();
|
|
if (data == -1) {
|
|
return null;
|
|
}
|
|
line += String.valueOf((char) data);
|
|
if (((char) data) == '\r' || ((char) data) == '\n') {
|
|
term += String.valueOf((char) data);
|
|
} else {
|
|
term = "";
|
|
}
|
|
}
|
|
line = line.trim();
|
|
} catch (Exception ex) {
|
|
line = null;
|
|
}
|
|
return line;
|
|
}
|
|
|
|
/**
|
|
* Retrieve http header info
|
|
*/
|
|
public final void retrieveHeader() {
|
|
int colonpos;
|
|
String key;
|
|
String value;
|
|
String line;
|
|
try {
|
|
line = readLine(israw);
|
|
hm.put("Header-Response", line);
|
|
while (true) {
|
|
line = readLine(israw);
|
|
if (line.isEmpty()) {
|
|
if (hm.get("Content-Length") == null) {
|
|
line = readLine(israw);
|
|
if (!line.isEmpty()) {
|
|
try {
|
|
long contentsize = Long.parseLong(line, 16);
|
|
hm.put("Content-Length", String.valueOf(contentsize));
|
|
} catch (Exception ex) {
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
colonpos = line.indexOf(':');
|
|
key = line.substring(0, colonpos);
|
|
value = line.substring(colonpos + 1);
|
|
hm.put(key, value.trim());
|
|
}
|
|
} catch (Exception ex) {
|
|
Logger.getGlobal().log(Level.WARNING, "retrieveHeader()", ex.getMessage());
|
|
hm.clear();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve http body as string should only be used with text content
|
|
*
|
|
* @return null if failed, otherwise returns the contents
|
|
*/
|
|
public final String getBodyAsString() {
|
|
String result = "";
|
|
try {
|
|
String temp = hm.get("Content-Length");
|
|
if (temp == null) {
|
|
return null;
|
|
}
|
|
long contentsize = Long.parseLong(temp);
|
|
while (contentsize-- != 0) {
|
|
result += (char) israw.read();
|
|
}
|
|
} catch (NumberFormatException | IOException ex) {
|
|
result = null;
|
|
Logger.getGlobal().log(Level.WARNING, "getBodyAsString()", ex.getMessage());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Save http body to a file, applies to all types of content
|
|
*
|
|
* @param dest File destination
|
|
* @param jpb Progress bar
|
|
* @return true if successful
|
|
*/
|
|
public final boolean saveBodyToFile(String dest, JProgressBar jpb) {
|
|
try {
|
|
String temp = hm.get("Content-Length");
|
|
if (temp == null) {
|
|
return false;
|
|
}
|
|
long contentsize = Long.parseLong(temp);
|
|
long bytereset = contentsize / 102;
|
|
long bytecount = bytereset;
|
|
int progress = 0;
|
|
File f = new File(dest);
|
|
try (FileOutputStream fos = new FileOutputStream(f)) {
|
|
if (jpb != null) {
|
|
jpb.setString(null);
|
|
}
|
|
while (contentsize-- != 0) {
|
|
fos.write(israw.read());
|
|
if (bytecount-- == 0) {
|
|
bytecount = bytereset;
|
|
if (jpb != null) {
|
|
jpb.setValue(progress++);
|
|
}
|
|
}
|
|
}
|
|
fos.close();
|
|
return true;
|
|
}
|
|
} catch (NumberFormatException | IOException ex) {
|
|
Logger.getGlobal().log(Level.WARNING, "saveBody()", ex.getMessage());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get various properties of the web page
|
|
*
|
|
* @param key
|
|
* @return property string
|
|
*/
|
|
public final String getProperty(String key) {
|
|
return hm.get(key);
|
|
}
|
|
|
|
private long getHttpDate(String adate) {
|
|
try {
|
|
format.applyPattern(PATTERN_RFC1123);
|
|
return format.parse(adate).getTime();
|
|
} catch (Exception ex) {
|
|
}
|
|
try {
|
|
format.applyPattern(PATTERN_RFC1036);
|
|
return format.parse(adate).getTime();
|
|
} catch (Exception ex) {
|
|
}
|
|
try {
|
|
format.applyPattern(PATTERN_ASCTIME);
|
|
return format.parse(adate).getTime();
|
|
} catch (Exception ex) {
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
public final long getLastModified() {
|
|
return getHttpDate(hm.get("Last-Modified"));
|
|
}
|
|
|
|
public final long getServerDate() {
|
|
return getHttpDate(hm.get("Date"));
|
|
}
|
|
|
|
public final long getExpires() {
|
|
return getHttpDate(hm.get("Expires"));
|
|
}
|
|
|
|
public final boolean isHeaderOK() {
|
|
String temp = hm.get("Content-Length");
|
|
if (temp == null) {
|
|
return false;
|
|
}
|
|
temp = hm.get("Header-Response");
|
|
if (temp == null) {
|
|
return false;
|
|
}
|
|
return temp.contains("200 OK");
|
|
}
|
|
|
|
}
|
|
|
|
}
|