synced up with the eepget from the syndie source tree (allowing better
control of timeouts and transparent redirection). the users of eepget in this source tree don't necessarily use the timeout controls, though they can be updated to do so
This commit is contained in:
@ -225,4 +225,5 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
|||||||
temp.delete();
|
temp.delete();
|
||||||
}
|
}
|
||||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||||
|
public void attempting(String url) {}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,7 @@ public class ReseedHandler {
|
|||||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
|
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
|
||||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
|
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
|
||||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||||
|
public void attempting(String url) {}
|
||||||
// End of EepGet status listeners
|
// End of EepGet status listeners
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,6 +169,7 @@ public class UpdateHandler {
|
|||||||
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
|
||||||
}
|
}
|
||||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||||
|
public void attempting(String url) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restart() {
|
private void restart() {
|
||||||
|
@ -37,7 +37,10 @@ public class EepGet {
|
|||||||
private long _maxSize; // applied both against whole responses and chunks
|
private long _maxSize; // applied both against whole responses and chunks
|
||||||
private String _outputFile;
|
private String _outputFile;
|
||||||
private OutputStream _outputStream;
|
private OutputStream _outputStream;
|
||||||
|
/** url we were asked to fetch */
|
||||||
private String _url;
|
private String _url;
|
||||||
|
/** the URL we actually fetch from (may differ from the _url in case of redirect) */
|
||||||
|
private String _actualURL;
|
||||||
private String _postData;
|
private String _postData;
|
||||||
private boolean _allowCaching;
|
private boolean _allowCaching;
|
||||||
private List _listeners;
|
private List _listeners;
|
||||||
@ -55,42 +58,42 @@ public class EepGet {
|
|||||||
private boolean _encodingChunked;
|
private boolean _encodingChunked;
|
||||||
private boolean _notModified;
|
private boolean _notModified;
|
||||||
private String _contentType;
|
private String _contentType;
|
||||||
|
private boolean _transferFailed;
|
||||||
|
private boolean _headersRead;
|
||||||
|
private boolean _aborted;
|
||||||
|
private long _fetchHeaderTimeout;
|
||||||
|
private long _fetchEndTime;
|
||||||
|
private long _fetchInactivityTimeout;
|
||||||
|
private int _redirects;
|
||||||
|
private String _redirectLocation;
|
||||||
|
|
||||||
// Constructor 7, calls 3 with: do proxy
|
|
||||||
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
||||||
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url);
|
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url);
|
||||||
}
|
}
|
||||||
// Constructor 6, calls 1 with: do proxy, no etag
|
|
||||||
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching) {
|
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching) {
|
||||||
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url, allowCaching, null);
|
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url, allowCaching, null);
|
||||||
}
|
}
|
||||||
// Constructor 5, calls 3 with: no proxy
|
|
||||||
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url) {
|
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url) {
|
||||||
this(ctx, false, null, -1, numRetries, outputFile, url);
|
this(ctx, false, null, -1, numRetries, outputFile, url);
|
||||||
}
|
}
|
||||||
// Constructor 4, calls 1 with: no proxy, no etag
|
|
||||||
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url, boolean allowCaching) {
|
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url, boolean allowCaching) {
|
||||||
this(ctx, false, null, -1, numRetries, outputFile, url, allowCaching, null);
|
this(ctx, false, null, -1, numRetries, outputFile, url, allowCaching, null);
|
||||||
}
|
}
|
||||||
// Constructor 3, calls 1 with: do caching, no etag
|
|
||||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
|
||||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, outputFile, url, true, null);
|
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, outputFile, url, true, null);
|
||||||
}
|
}
|
||||||
// Constructor 2, calls 0 with: no output buffer, do caching, no etag
|
|
||||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, String postData) {
|
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, String postData) {
|
||||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, true, null, postData);
|
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, true, null, postData);
|
||||||
}
|
}
|
||||||
// Constructor 1, calls 0 with: no output buffer, no postdata
|
|
||||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag) {
|
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag) {
|
||||||
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, allowCaching, etag, null);
|
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, allowCaching, etag, null);
|
||||||
}
|
}
|
||||||
// Constructor 0, real constructor
|
|
||||||
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize,
|
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize,
|
||||||
String outputFile, OutputStream outputStream, String url, boolean allowCaching,
|
String outputFile, OutputStream outputStream, String url, boolean allowCaching,
|
||||||
String etag, String postData) {
|
String etag, String postData) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(EepGet.class);
|
_log = ctx.logManager().getLog(EepGet.class);
|
||||||
_shouldProxy = shouldProxy;
|
_shouldProxy = (proxyHost != null) && (proxyHost.length() > 0) && (proxyPort > 0) && shouldProxy;
|
||||||
_proxyHost = proxyHost;
|
_proxyHost = proxyHost;
|
||||||
_proxyPort = proxyPort;
|
_proxyPort = proxyPort;
|
||||||
_numRetries = numRetries;
|
_numRetries = numRetries;
|
||||||
@ -99,11 +102,16 @@ public class EepGet {
|
|||||||
_outputFile = outputFile; // if outputFile is set, outputStream must be null
|
_outputFile = outputFile; // if outputFile is set, outputStream must be null
|
||||||
_outputStream = outputStream; // if both are set, outputStream overrides outputFile
|
_outputStream = outputStream; // if both are set, outputStream overrides outputFile
|
||||||
_url = url;
|
_url = url;
|
||||||
|
_actualURL = url;
|
||||||
_postData = postData;
|
_postData = postData;
|
||||||
_alreadyTransferred = 0;
|
_alreadyTransferred = 0;
|
||||||
_bytesTransferred = 0;
|
_bytesTransferred = 0;
|
||||||
_bytesRemaining = -1;
|
_bytesRemaining = -1;
|
||||||
_currentAttempt = 0;
|
_currentAttempt = 0;
|
||||||
|
_transferFailed = false;
|
||||||
|
_headersRead = false;
|
||||||
|
_aborted = false;
|
||||||
|
_fetchHeaderTimeout = 30*1000;
|
||||||
_listeners = new ArrayList(1);
|
_listeners = new ArrayList(1);
|
||||||
_etag = etag;
|
_etag = etag;
|
||||||
}
|
}
|
||||||
@ -203,6 +211,7 @@ public class EepGet {
|
|||||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause);
|
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause);
|
||||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt);
|
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt);
|
||||||
public void headerReceived(String url, int currentAttempt, String key, String val);
|
public void headerReceived(String url, int currentAttempt, String key, String val);
|
||||||
|
public void attempting(String url);
|
||||||
}
|
}
|
||||||
private class CLIStatusListener implements StatusListener {
|
private class CLIStatusListener implements StatusListener {
|
||||||
private int _markSize;
|
private int _markSize;
|
||||||
@ -317,6 +326,7 @@ public class EepGet {
|
|||||||
buf.append("KBps");
|
buf.append("KBps");
|
||||||
System.out.println(buf.toString());
|
System.out.println(buf.toString());
|
||||||
}
|
}
|
||||||
|
public void attempting(String url) {}
|
||||||
public void headerReceived(String url, int currentAttempt, String key, String val) {}
|
public void headerReceived(String url, int currentAttempt, String key, String val) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,17 +339,48 @@ public class EepGet {
|
|||||||
* Blocking fetch, returning true if the URL was retrieved, false if all retries failed
|
* Blocking fetch, returning true if the URL was retrieved, false if all retries failed
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public boolean fetch() {
|
public boolean fetch() { return fetch(_fetchHeaderTimeout); }
|
||||||
|
/**
|
||||||
|
* Blocking fetch, timing out individual attempts if the HTTP response headers
|
||||||
|
* don't come back in the time given. If the timeout is zero or less, this will
|
||||||
|
* wait indefinitely.
|
||||||
|
*/
|
||||||
|
public boolean fetch(long fetchHeaderTimeout) {
|
||||||
|
return fetch(fetchHeaderTimeout, -1, -1);
|
||||||
|
}
|
||||||
|
public boolean fetch(long fetchHeaderTimeout, long totalTimeout, long inactivityTimeout) {
|
||||||
|
_fetchHeaderTimeout = fetchHeaderTimeout;
|
||||||
|
_fetchEndTime = (totalTimeout > 0 ? System.currentTimeMillis() + totalTimeout : -1);
|
||||||
|
_fetchInactivityTimeout = inactivityTimeout;
|
||||||
_keepFetching = true;
|
_keepFetching = true;
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _url);
|
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _actualURL);
|
||||||
while (_keepFetching) {
|
while (_keepFetching) {
|
||||||
|
SocketTimeout timeout = null;
|
||||||
|
if (_fetchHeaderTimeout > 0)
|
||||||
|
timeout = new SocketTimeout(_fetchHeaderTimeout);
|
||||||
|
final SocketTimeout stimeout = timeout; // ugly
|
||||||
|
timeout.setTimeoutCommand(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("timeout reached on " + _url + ": " + stimeout);
|
||||||
|
_aborted = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
timeout.setTotalTimeoutPeriod(_fetchEndTime);
|
||||||
try {
|
try {
|
||||||
sendRequest();
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
doFetch();
|
((StatusListener)_listeners.get(i)).attempting(_url);
|
||||||
|
sendRequest(timeout);
|
||||||
|
timeout.resetTimer();
|
||||||
|
doFetch(timeout);
|
||||||
|
timeout.cancel();
|
||||||
|
if (!_transferFailed)
|
||||||
return true;
|
return true;
|
||||||
|
break;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
|
timeout.cancel();
|
||||||
for (int i = 0; i < _listeners.size(); i++)
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
((StatusListener)_listeners.get(i)).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
|
((StatusListener)_listeners.get(i)).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
|
||||||
} finally {
|
} finally {
|
||||||
@ -360,7 +401,10 @@ public class EepGet {
|
|||||||
_currentAttempt++;
|
_currentAttempt++;
|
||||||
if (_currentAttempt > _numRetries)
|
if (_currentAttempt > _numRetries)
|
||||||
break;
|
break;
|
||||||
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
|
try {
|
||||||
|
long delay = _context.random().nextInt(60*1000);
|
||||||
|
Thread.sleep(5*1000+delay);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < _listeners.size(); i++)
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
@ -368,9 +412,57 @@ public class EepGet {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** a single fetch attempt */
|
/** return true if the URL was completely retrieved */
|
||||||
private void doFetch() throws IOException {
|
private void doFetch(SocketTimeout timeout) throws IOException {
|
||||||
|
_headersRead = false;
|
||||||
|
_aborted = false;
|
||||||
|
try {
|
||||||
readHeaders();
|
readHeaders();
|
||||||
|
} finally {
|
||||||
|
_headersRead = true;
|
||||||
|
}
|
||||||
|
if (_aborted)
|
||||||
|
throw new IOException("Timed out reading the HTTP headers");
|
||||||
|
|
||||||
|
timeout.resetTimer();
|
||||||
|
if (_fetchInactivityTimeout > 0)
|
||||||
|
timeout.setInactivityTimeout(_fetchInactivityTimeout);
|
||||||
|
else
|
||||||
|
timeout.setInactivityTimeout(60*1000);
|
||||||
|
|
||||||
|
if (_redirectLocation != null) {
|
||||||
|
try {
|
||||||
|
URL oldURL = new URL(_actualURL);
|
||||||
|
String query = oldURL.getQuery();
|
||||||
|
if (query == null) query = "";
|
||||||
|
if (_redirectLocation.startsWith("http://")) {
|
||||||
|
if ( (_redirectLocation.indexOf('?') < 0) && (query.length() > 0) )
|
||||||
|
_actualURL = _redirectLocation + "?" + query;
|
||||||
|
else
|
||||||
|
_actualURL = _redirectLocation;
|
||||||
|
} else {
|
||||||
|
URL url = new URL(_actualURL);
|
||||||
|
if (_redirectLocation.startsWith("/"))
|
||||||
|
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation;
|
||||||
|
else
|
||||||
|
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation;
|
||||||
|
if ( (_actualURL.indexOf('?') < 0) && (query.length() > 0) )
|
||||||
|
_actualURL = _actualURL + "?" + query;
|
||||||
|
else
|
||||||
|
_actualURL = _actualURL;
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException mue) {
|
||||||
|
throw new IOException("Redirected from an invalid URL");
|
||||||
|
}
|
||||||
|
_redirects++;
|
||||||
|
if (_redirects > 5)
|
||||||
|
throw new IOException("Too many redirects: to " + _redirectLocation);
|
||||||
|
if (_log.shouldLog(Log.INFO)) _log.info("Redirecting to " + _redirectLocation);
|
||||||
|
sendRequest(timeout);
|
||||||
|
doFetch(timeout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Headers read completely, reading " + _bytesRemaining);
|
_log.debug("Headers read completely, reading " + _bytesRemaining);
|
||||||
|
|
||||||
@ -384,13 +476,14 @@ public class EepGet {
|
|||||||
|
|
||||||
int remaining = (int)_bytesRemaining;
|
int remaining = (int)_bytesRemaining;
|
||||||
byte buf[] = new byte[1024];
|
byte buf[] = new byte[1024];
|
||||||
while (_keepFetching && ( (remaining > 0) || !strictSize )) {
|
while (_keepFetching && ( (remaining > 0) || !strictSize ) && !_aborted) {
|
||||||
int toRead = buf.length;
|
int toRead = buf.length;
|
||||||
if (strictSize && toRead > remaining)
|
if (strictSize && toRead > remaining)
|
||||||
toRead = remaining;
|
toRead = remaining;
|
||||||
int read = _proxyIn.read(buf, 0, toRead);
|
int read = _proxyIn.read(buf, 0, toRead);
|
||||||
if (read == -1)
|
if (read == -1)
|
||||||
break;
|
break;
|
||||||
|
timeout.resetTimer();
|
||||||
_out.write(buf, 0, read);
|
_out.write(buf, 0, read);
|
||||||
_bytesTransferred += read;
|
_bytesTransferred += read;
|
||||||
// This seems necessary to properly resume a partial download into a stream,
|
// This seems necessary to properly resume a partial download into a stream,
|
||||||
@ -400,10 +493,26 @@ public class EepGet {
|
|||||||
_alreadyTransferred += read;
|
_alreadyTransferred += read;
|
||||||
remaining -= read;
|
remaining -= read;
|
||||||
if (remaining==0 && _encodingChunked) {
|
if (remaining==0 && _encodingChunked) {
|
||||||
if(_proxyIn.read()=='\r' && _proxyIn.read()=='\n') {
|
int char1 = _proxyIn.read();
|
||||||
|
if (char1 == '\r') {
|
||||||
|
int char2 = _proxyIn.read();
|
||||||
|
if (char2 == '\n') {
|
||||||
remaining = (int) readChunkLength();
|
remaining = (int) readChunkLength();
|
||||||
|
} else {
|
||||||
|
_out.write(char1);
|
||||||
|
_out.write(char2);
|
||||||
|
_bytesTransferred += 2;
|
||||||
|
remaining -= 2;
|
||||||
|
read += 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_out.write(char1);
|
||||||
|
_bytesTransferred++;
|
||||||
|
remaining--;
|
||||||
|
read++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
timeout.resetTimer();
|
||||||
if (read > 0)
|
if (read > 0)
|
||||||
for (int i = 0; i < _listeners.size(); i++)
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
((StatusListener)_listeners.get(i)).bytesTransferred(
|
((StatusListener)_listeners.get(i)).bytesTransferred(
|
||||||
@ -418,10 +527,19 @@ public class EepGet {
|
|||||||
_out.close();
|
_out.close();
|
||||||
_out = null;
|
_out = null;
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_aborted)
|
||||||
_log.debug("Done transferring " + _bytesTransferred);
|
throw new IOException("Timed out reading the HTTP data");
|
||||||
|
|
||||||
if ( (_bytesRemaining == -1) || (remaining == 0) ){
|
timeout.cancel();
|
||||||
|
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Done transferring " + _bytesTransferred + " (ok? " + !_transferFailed + ")");
|
||||||
|
|
||||||
|
if (_transferFailed) {
|
||||||
|
// 404, etc
|
||||||
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
|
((StatusListener)_listeners.get(i)).transferFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt);
|
||||||
|
} else if ( (_bytesRemaining == -1) || (remaining == 0) ) {
|
||||||
for (int i = 0; i < _listeners.size(); i++)
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
((StatusListener)_listeners.get(i)).transferComplete(
|
((StatusListener)_listeners.get(i)).transferComplete(
|
||||||
_alreadyTransferred,
|
_alreadyTransferred,
|
||||||
@ -442,31 +560,52 @@ public class EepGet {
|
|||||||
boolean read = DataHelper.readLine(_proxyIn, buf);
|
boolean read = DataHelper.readLine(_proxyIn, buf);
|
||||||
if (!read) throw new IOException("Unable to read the first line");
|
if (!read) throw new IOException("Unable to read the first line");
|
||||||
int responseCode = handleStatus(buf.toString());
|
int responseCode = handleStatus(buf.toString());
|
||||||
|
boolean redirect = false;
|
||||||
|
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("rc: " + responseCode + " for " + _actualURL);
|
||||||
|
|
||||||
boolean rcOk = false;
|
boolean rcOk = false;
|
||||||
switch (responseCode) {
|
switch (responseCode) {
|
||||||
case 200: // full
|
case 200: // full
|
||||||
if (_outputStream != null) _out = _outputStream;
|
if (_outputStream != null)
|
||||||
else _out = new FileOutputStream(_outputFile, false);
|
_out = _outputStream;
|
||||||
|
else
|
||||||
|
_out = new FileOutputStream(_outputFile, false);
|
||||||
_alreadyTransferred = 0;
|
_alreadyTransferred = 0;
|
||||||
rcOk = true;
|
rcOk = true;
|
||||||
break;
|
break;
|
||||||
case 206: // partial
|
case 206: // partial
|
||||||
if (_outputStream != null) _out = _outputStream;
|
if (_outputStream != null)
|
||||||
else _out = new FileOutputStream(_outputFile, true);
|
_out = _outputStream;
|
||||||
|
else
|
||||||
|
_out = new FileOutputStream(_outputFile, true);
|
||||||
rcOk = true;
|
rcOk = true;
|
||||||
break;
|
break;
|
||||||
|
case 301: // various redirections
|
||||||
|
case 302:
|
||||||
|
case 303:
|
||||||
|
case 307:
|
||||||
|
_alreadyTransferred = 0;
|
||||||
|
rcOk = true;
|
||||||
|
redirect = true;
|
||||||
|
break;
|
||||||
case 304: // not modified
|
case 304: // not modified
|
||||||
_bytesRemaining = 0;
|
_bytesRemaining = 0;
|
||||||
_keepFetching = false;
|
_keepFetching = false;
|
||||||
_notModified = true;
|
_notModified = true;
|
||||||
return;
|
return;
|
||||||
|
case 404: // not found
|
||||||
|
_keepFetching = false;
|
||||||
|
_transferFailed = true;
|
||||||
|
return;
|
||||||
case 416: // completed (or range out of reach)
|
case 416: // completed (or range out of reach)
|
||||||
_bytesRemaining = 0;
|
_bytesRemaining = 0;
|
||||||
_keepFetching = false;
|
_keepFetching = false;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
rcOk = false;
|
rcOk = false;
|
||||||
|
_transferFailed = true;
|
||||||
}
|
}
|
||||||
buf.setLength(0);
|
buf.setLength(0);
|
||||||
byte lookahead[] = new byte[3];
|
byte lookahead[] = new byte[3];
|
||||||
@ -500,6 +639,7 @@ public class EepGet {
|
|||||||
if (_encodingChunked) {
|
if (_encodingChunked) {
|
||||||
_bytesRemaining = readChunkLength();
|
_bytesRemaining = readChunkLength();
|
||||||
}
|
}
|
||||||
|
if (!redirect) _redirectLocation = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -594,6 +734,8 @@ public class EepGet {
|
|||||||
_encodingChunked = true;
|
_encodingChunked = true;
|
||||||
} else if (key.equalsIgnoreCase("Content-Type")) {
|
} else if (key.equalsIgnoreCase("Content-Type")) {
|
||||||
_contentType=val;
|
_contentType=val;
|
||||||
|
} else if (key.equalsIgnoreCase("Location")) {
|
||||||
|
_redirectLocation=val.trim();
|
||||||
} else {
|
} else {
|
||||||
// ignore the rest
|
// ignore the rest
|
||||||
}
|
}
|
||||||
@ -616,7 +758,7 @@ public class EepGet {
|
|||||||
private static final byte NL = '\n';
|
private static final byte NL = '\n';
|
||||||
private boolean isNL(byte b) { return (b == NL); }
|
private boolean isNL(byte b) { return (b == NL); }
|
||||||
|
|
||||||
private void sendRequest() throws IOException {
|
private void sendRequest(SocketTimeout timeout) throws IOException {
|
||||||
if (_outputStream != null) {
|
if (_outputStream != null) {
|
||||||
// We are reading into a stream supplied by a caller,
|
// We are reading into a stream supplied by a caller,
|
||||||
// for which we cannot easily determine how much we've written.
|
// for which we cannot easily determine how much we've written.
|
||||||
@ -630,16 +772,24 @@ public class EepGet {
|
|||||||
|
|
||||||
String req = getRequest();
|
String req = getRequest();
|
||||||
|
|
||||||
|
if (_proxyIn != null) try { _proxyIn.close(); } catch (IOException ioe) {}
|
||||||
|
if (_proxyOut != null) try { _proxyOut.close(); } catch (IOException ioe) {}
|
||||||
|
if (_proxy != null) try { _proxy.close(); } catch (IOException ioe) {}
|
||||||
|
|
||||||
if (_shouldProxy) {
|
if (_shouldProxy) {
|
||||||
_proxy = new Socket(_proxyHost, _proxyPort);
|
_proxy = new Socket(_proxyHost, _proxyPort);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(_url);
|
URL url = new URL(_actualURL);
|
||||||
|
if ("http".equals(url.getProtocol())) {
|
||||||
String host = url.getHost();
|
String host = url.getHost();
|
||||||
int port = url.getPort();
|
int port = url.getPort();
|
||||||
if (port == -1)
|
if (port == -1)
|
||||||
port = 80;
|
port = 80;
|
||||||
_proxy = new Socket(host, port);
|
_proxy = new Socket(host, port);
|
||||||
|
} else {
|
||||||
|
throw new IOException("URL is not supported:" + _actualURL);
|
||||||
|
}
|
||||||
} catch (MalformedURLException mue) {
|
} catch (MalformedURLException mue) {
|
||||||
throw new IOException("Request URL is invalid");
|
throw new IOException("Request URL is invalid");
|
||||||
}
|
}
|
||||||
@ -647,7 +797,9 @@ public class EepGet {
|
|||||||
_proxyIn = _proxy.getInputStream();
|
_proxyIn = _proxy.getInputStream();
|
||||||
_proxyOut = _proxy.getOutputStream();
|
_proxyOut = _proxy.getOutputStream();
|
||||||
|
|
||||||
_proxyOut.write(req.toString().getBytes());
|
timeout.setSocket(_proxy);
|
||||||
|
|
||||||
|
_proxyOut.write(DataHelper.getUTF8(req.toString()));
|
||||||
_proxyOut.flush();
|
_proxyOut.flush();
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
@ -659,12 +811,24 @@ public class EepGet {
|
|||||||
boolean post = false;
|
boolean post = false;
|
||||||
if ( (_postData != null) && (_postData.length() > 0) )
|
if ( (_postData != null) && (_postData.length() > 0) )
|
||||||
post = true;
|
post = true;
|
||||||
|
URL url = new URL(_actualURL);
|
||||||
|
String proto = url.getProtocol();
|
||||||
|
String host = url.getHost();
|
||||||
|
int port = url.getPort();
|
||||||
|
String path = url.getPath();
|
||||||
|
String query = url.getQuery();
|
||||||
|
if (query != null)
|
||||||
|
path = path + "?" + query;
|
||||||
|
if (!path.startsWith("/"))
|
||||||
|
path = "/" + path;
|
||||||
|
if ( (port == 80) || (port == 443) || (port <= 0) ) path = proto + "://" + host + path;
|
||||||
|
else path = proto + "://" + host + ":" + port + path;
|
||||||
|
if (_log.shouldLog(Log.DEBUG)) _log.debug("Requesting " + path);
|
||||||
if (post) {
|
if (post) {
|
||||||
buf.append("POST ").append(_url).append(" HTTP/1.1\r\n");
|
buf.append("POST ").append(_actualURL).append(" HTTP/1.1\r\n");
|
||||||
} else {
|
} else {
|
||||||
buf.append("GET ").append(_url).append(" HTTP/1.1\r\n");
|
buf.append("GET ").append(_actualURL).append(" HTTP/1.1\r\n");
|
||||||
}
|
}
|
||||||
URL url = new URL(_url);
|
|
||||||
buf.append("Host: ").append(url.getHost()).append("\r\n");
|
buf.append("Host: ").append(url.getHost()).append("\r\n");
|
||||||
if (_alreadyTransferred > 0) {
|
if (_alreadyTransferred > 0) {
|
||||||
buf.append("Range: bytes=");
|
buf.append("Range: bytes=");
|
||||||
|
@ -36,6 +36,7 @@ public class EepGetScheduler implements EepGet.StatusListener {
|
|||||||
public void fetch(boolean shouldBlock) {
|
public void fetch(boolean shouldBlock) {
|
||||||
//Checking for a valid index is done in fetchNext, so we don't have to worry about it.
|
//Checking for a valid index is done in fetchNext, so we don't have to worry about it.
|
||||||
if (shouldBlock) {
|
if (shouldBlock) {
|
||||||
|
while (_curURL < _urls.size())
|
||||||
fetchNext();
|
fetchNext();
|
||||||
} else {
|
} else {
|
||||||
fetch();
|
fetch();
|
||||||
@ -77,6 +78,7 @@ public class EepGetScheduler implements EepGet.StatusListener {
|
|||||||
_listener.transferFailed(url, bytesTransferred, bytesRemaining, currentAttempt);
|
_listener.transferFailed(url, bytesTransferred, bytesRemaining, currentAttempt);
|
||||||
fetchNext();
|
fetchNext();
|
||||||
}
|
}
|
||||||
|
public void attempting(String url) { _listener.attempting(url); }
|
||||||
|
|
||||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||||
}
|
}
|
||||||
|
71
core/java/src/net/i2p/util/SocketTimeout.java
Normal file
71
core/java/src/net/i2p/util/SocketTimeout.java
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package net.i2p.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class SocketTimeout implements SimpleTimer.TimedEvent {
|
||||||
|
private Socket _targetSocket;
|
||||||
|
private long _startTime;
|
||||||
|
private long _inactivityDelay;
|
||||||
|
private long _lastActivity;
|
||||||
|
private long _totalTimeoutTime;
|
||||||
|
private boolean _cancelled;
|
||||||
|
private Runnable _command;
|
||||||
|
public SocketTimeout(long delay) { this(null, delay); }
|
||||||
|
public SocketTimeout(Socket socket, long delay) {
|
||||||
|
_inactivityDelay = delay;
|
||||||
|
_targetSocket = socket;
|
||||||
|
_cancelled = false;
|
||||||
|
_lastActivity = _startTime = System.currentTimeMillis();
|
||||||
|
_totalTimeoutTime = -1;
|
||||||
|
SimpleTimer.getInstance().addEvent(SocketTimeout.this, delay);
|
||||||
|
}
|
||||||
|
public void timeReached() {
|
||||||
|
if (_cancelled) return;
|
||||||
|
|
||||||
|
if ( ( (_totalTimeoutTime > 0) && (_totalTimeoutTime <= System.currentTimeMillis()) ) ||
|
||||||
|
(_inactivityDelay + _lastActivity <= System.currentTimeMillis()) ) {
|
||||||
|
if (_targetSocket != null) {
|
||||||
|
try {
|
||||||
|
if (!_targetSocket.isClosed())
|
||||||
|
_targetSocket.close();
|
||||||
|
} catch (IOException ioe) {}
|
||||||
|
}
|
||||||
|
if (_command != null) _command.run();
|
||||||
|
} else {
|
||||||
|
SimpleTimer.getInstance().addEvent(SocketTimeout.this, _inactivityDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
_cancelled = true;
|
||||||
|
SimpleTimer.getInstance().removeEvent(SocketTimeout.this);
|
||||||
|
}
|
||||||
|
public void setSocket(Socket s) { _targetSocket = s; }
|
||||||
|
public void resetTimer() { _lastActivity = System.currentTimeMillis(); }
|
||||||
|
public void setInactivityTimeout(long timeout) { _inactivityDelay = timeout; }
|
||||||
|
public void setTotalTimeoutPeriod(long timeoutPeriod) {
|
||||||
|
if (timeoutPeriod > 0)
|
||||||
|
_totalTimeoutTime = _startTime + timeoutPeriod;
|
||||||
|
else
|
||||||
|
_totalTimeoutTime = -1;
|
||||||
|
}
|
||||||
|
public void setTimeoutCommand(Runnable job) { _command = job; }
|
||||||
|
|
||||||
|
private static final SimpleDateFormat _fmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS");
|
||||||
|
private static String ts(long when) { synchronized (_fmt) { return _fmt.format(new Date(when)); } }
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append("started on ");
|
||||||
|
buf.append(ts(_startTime));
|
||||||
|
buf.append("idle for ");
|
||||||
|
buf.append(System.currentTimeMillis() - _lastActivity);
|
||||||
|
buf.append("ms ");
|
||||||
|
if (_totalTimeoutTime > 0)
|
||||||
|
buf.append("total timeout at ").append(ts(_totalTimeoutTime));
|
||||||
|
buf.append("cancelled? ").append(_cancelled);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RouterVersion {
|
public class RouterVersion {
|
||||||
public final static String ID = "$Revision: 1.518 $ $Date: 2007-08-13 14:43:01 $";
|
public final static String ID = "$Revision: 1.519 $ $Date: 2007-08-23 19:33:33 $";
|
||||||
public final static String VERSION = "0.6.1.29";
|
public final static String VERSION = "0.6.1.29";
|
||||||
public final static long BUILD = 0;
|
public final static long BUILD = 1;
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||||
System.out.println("Router ID: " + RouterVersion.ID);
|
System.out.println("Router ID: " + RouterVersion.ID);
|
||||||
|
Reference in New Issue
Block a user