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

/*
* 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");
}
}
}