diff --git a/core/java/src/net/i2p/util/EepGet.java b/core/java/src/net/i2p/util/EepGet.java index 1a6e23a011fe84a73823de2263cc44ef6e3a3056..2f59baeac7ce8cced513b80ae111dc1fdd102e14 100644 --- a/core/java/src/net/i2p/util/EepGet.java +++ b/core/java/src/net/i2p/util/EepGet.java @@ -92,7 +92,7 @@ public class EepGet { // following for proxy digest auth // only created via addAuthorization() - private AuthState _authState; + protected AuthState _authState; /** this will be replaced by the HTTP Proxy if we are using it */ protected static final String USER_AGENT = "Wget/1.11.4"; @@ -175,7 +175,6 @@ public class EepGet { long inactivityTimeout = INACTIVITY_TIMEOUT; String etag = null; String saveAs = null; - String url = null; List<String> extra = null; String username = null; String password = null; @@ -233,13 +232,18 @@ public class EepGet { break; case 'h': - if (extra == null) - extra = new ArrayList<String>(2); String a = g.getOptarg(); - String key = a.substring(0, a.indexOf('=')); - String val = a.substring(a.indexOf('=')+1); - extra.add(key); - extra.add(val); + int eq = a.indexOf('='); + if (eq > 0) { + if (extra == null) + extra = new ArrayList<String>(2); + String key = a.substring(0, eq); + String val = a.substring(eq + 1); + extra.add(key); + extra.add(val); + } else { + error = true; + } break; case 'u': @@ -262,12 +266,11 @@ public class EepGet { error = true; } - int remaining = args.length - g.getOptind(); - if (error || remaining != 1) { + if (error || args.length - g.getOptind() != 1) { usage(); System.exit(1); } - url = args[g.getOptind()]; + String url = args[g.getOptind()]; if (saveAs == null) saveAs = suggestName(url); @@ -349,7 +352,7 @@ public class EepGet { } private static void usage() { - System.err.println("eepget [-p 127.0.0.1:4444] [-c] [-o outputFile]\n" + + System.err.println("eepget [-p 127.0.0.1[:4444]] [-c] [-o outputFile]\n" + " [-n #retries] (default 5)\n" + " [-m markSize] (default 1024)\n" + " [-l lineLen] (default 40)\n" + @@ -697,8 +700,6 @@ public class EepGet { throw new IOException("Proxy requires authentication"); if (as.authSent) throw new IOException("Proxy authentication failed"); // ignore stale - if (as.authChallenge == null) - throw new IOException("Bad proxy auth response"); if (_log.shouldLog(Log.INFO)) _log.info("Adding auth"); // actually happens in getRequest() } else { @@ -1379,7 +1380,6 @@ public class EepGet { * Add basic authorization header for the proxy. * Only added if the request is going through a proxy. * Must be called before fetch(). - * Not supported by EepHead. * * @since 0.8.9 */ @@ -1469,7 +1469,7 @@ public class EepGet { /** * @since 0.9.12 */ - private enum AUTH_MODE {NONE, BASIC, DIGEST, UNKNOWN} + protected enum AUTH_MODE {NONE, BASIC, DIGEST, UNKNOWN} /** * Manage the authentication parameters @@ -1479,7 +1479,7 @@ public class EepGet { * * @since 0.9.12 */ - private class AuthState { + protected class AuthState { private final String username; private final String password; // as recvd in 407 @@ -1517,7 +1517,7 @@ public class EepGet { // better than NONE only if (authMode == AUTH_MODE.NONE) { authMode = AUTH_MODE.UNKNOWN; - authChallenge = ""; + authChallenge = null; } } nonceCount = 0; @@ -1533,6 +1533,8 @@ public class EepGet { Base64.encode(DataHelper.getUTF8(username + ':' + password), true); case DIGEST: + if (authChallenge == null) + throw new IOException("Bad proxy auth response"); if (args == null) args = parseAuthArgs(authChallenge); Map<String, String> outArgs = generateAuthArgs(method, uri); diff --git a/core/java/src/net/i2p/util/EepHead.java b/core/java/src/net/i2p/util/EepHead.java index 53650408835e147c9896be070e732fbba7dafbcc..c1ddb62828001a4661c0e877ae10030b84a6328d 100644 --- a/core/java/src/net/i2p/util/EepHead.java +++ b/core/java/src/net/i2p/util/EepHead.java @@ -1,10 +1,15 @@ package net.i2p.util; +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; +import gnu.getopt.Getopt; + import net.i2p.I2PAppContext; /** @@ -51,39 +56,86 @@ public class EepHead extends EepGet { int proxyPort = 4444; int numRetries = 0; int inactivityTimeout = 60*1000; - String url = null; + String username = null; + String password = null; + boolean error = false; + Getopt g = new Getopt("eephead", args, "p:cn:t:u:x:"); try { - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-p")) { - proxyHost = args[i+1].substring(0, args[i+1].indexOf(':')); - String port = args[i+1].substring(args[i+1].indexOf(':')+1); - proxyPort = Integer.parseInt(port); - i++; - } else if (args[i].equals("-n")) { - numRetries = Integer.parseInt(args[i+1]); - i++; - } else if (args[i].equals("-t")) { - inactivityTimeout = 1000 * Integer.parseInt(args[i+1]); - i++; - } else if (args[i].startsWith("-")) { - usage(); - return; - } else { - url = args[i]; - } - } + int c; + while ((c = g.getopt()) != -1) { + switch (c) { + case 'p': + String s = g.getOptarg(); + int colon = s.indexOf(':'); + if (colon >= 0) { + // Todo IPv6 [a:b:c]:4444 + proxyHost = s.substring(0, colon); + String port = s.substring(colon + 1); + proxyPort = Integer.parseInt(port); + } else { + proxyHost = s; + // proxyPort remains default + } + break; + + case 'c': + // no proxy, same as -p :0 + proxyHost = ""; + proxyPort = 0; + break; + + case 'n': + numRetries = Integer.parseInt(g.getOptarg()); + break; + + case 't': + inactivityTimeout = 1000 * Integer.parseInt(g.getOptarg()); + break; + + case 'u': + username = g.getOptarg(); + break; + + case 'x': + password = g.getOptarg(); + break; + + case '?': + case ':': + default: + error = true; + break; + } // switch + } // while } catch (Exception e) { e.printStackTrace(); - usage(); - return; + error = true; } - - if (url == null) { + + if (error || args.length - g.getOptind() != 1) { usage(); - return; + System.exit(1); } - + String url = args[g.getOptind()]; + EepHead get = new EepHead(I2PAppContext.getGlobalContext(), proxyHost, proxyPort, numRetries, url); + if (username != null) { + if (password == null) { + try { + BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); + do { + System.err.print("Proxy password: "); + password = r.readLine(); + if (password == null) + throw new IOException(); + password = password.trim(); + } while (password.length() <= 0); + } catch (IOException ioe) { + System.exit(1); + } + } + get.addAuthorization(username, password); + } if (get.fetch(45*1000, -1, inactivityTimeout)) { System.err.println("Content-Type: " + get.getContentType()); System.err.println("Content-Length: " + get.getContentLength()); @@ -96,7 +148,11 @@ public class EepHead extends EepGet { } private static void usage() { - System.err.println("EepHead [-p 127.0.0.1:4444] [-n #retries] [-t timeout] url"); + System.err.println("EepHead [-p 127.0.0.1[:4444]] [-c]\n" + + " [-n #retries] (default 0)\n" + + " [-t timeout] (default 60 sec)\n" + + " [-u username] [-x password] url\n" + + " (use -c or -p :0 for no proxy)"); } /** return true if the URL was completely retrieved */ @@ -138,10 +194,24 @@ public class EepHead extends EepGet { //} 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); + AuthState as = _authState; + if (_responseCode == 407) { + if (!_shouldProxy) + throw new IOException("Proxy auth response from non-proxy"); + if (as == null) + throw new IOException("Proxy requires authentication"); + if (as.authSent) + throw new IOException("Proxy authentication failed"); // ignore stale + if (_log.shouldLog(Log.INFO)) _log.info("Adding auth"); + // actually happens in getRequest() + } else { + _redirects++; + if (_redirects > 5) + throw new IOException("Too many redirects: to " + _redirectLocation); + if (_log.shouldLog(Log.INFO)) _log.info("Redirecting to " + _redirectLocation); + if (as != null) + as.authSent = false; + } // reset some important variables, we don't want to save the values from the redirect _bytesRemaining = -1; @@ -212,6 +282,11 @@ public class EepHead extends EepGet { buf.append("Accept-Encoding: \r\n"); // This will be replaced if we are going through I2PTunnelHTTPClient buf.append("User-Agent: " + USER_AGENT + "\r\n"); + if (_authState != null && _shouldProxy && _authState.authMode != AUTH_MODE.NONE) { + buf.append("Proxy-Authorization: "); + buf.append(_authState.getAuthHeader("HEAD", urlToSend)); + buf.append("\r\n"); + } buf.append("Connection: close\r\n\r\n"); if (_log.shouldLog(Log.DEBUG)) _log.debug("Request: [" + buf.toString() + "]"); diff --git a/core/java/src/net/i2p/util/PartialEepGet.java b/core/java/src/net/i2p/util/PartialEepGet.java index 4f3cf95519676799bbfdfe177ac337352fc3482a..baab6e0397d2b557e6a76df453d7a9904e070a93 100644 --- a/core/java/src/net/i2p/util/PartialEepGet.java +++ b/core/java/src/net/i2p/util/PartialEepGet.java @@ -1,12 +1,16 @@ package net.i2p.util; +import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; +import gnu.getopt.Getopt; + import net.i2p.I2PAppContext; /** @@ -50,46 +54,99 @@ public class PartialEepGet extends EepGet { int proxyPort = 4444; // 40 sig + 16 version for .suds long size = 56; - String url = null; + String saveAs = null; + String username = null; + String password = null; + boolean error = false; + Getopt g = new Getopt("partialeepget", args, "p:cl:o:u:x:"); try { - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-p")) { - proxyHost = args[i+1].substring(0, args[i+1].indexOf(':')); - String port = args[i+1].substring(args[i+1].indexOf(':')+1); - proxyPort = Integer.parseInt(port); - i++; - } else if (args[i].equals("-l")) { - size = Long.parseLong(args[i+1]); - i++; - } else if (args[i].startsWith("-")) { - usage(); - return; - } else { - url = args[i]; - } - } + int c; + while ((c = g.getopt()) != -1) { + switch (c) { + case 'p': + String s = g.getOptarg(); + int colon = s.indexOf(':'); + if (colon >= 0) { + // Todo IPv6 [a:b:c]:4444 + proxyHost = s.substring(0, colon); + String port = s.substring(colon + 1); + proxyPort = Integer.parseInt(port); + } else { + proxyHost = s; + // proxyPort remains default + } + break; + + case 'c': + // no proxy, same as -p :0 + proxyHost = ""; + proxyPort = 0; + break; + + case 'l': + size = Long.parseLong(g.getOptarg()); + break; + + case 'o': + saveAs = g.getOptarg(); + break; + + case 'u': + username = g.getOptarg(); + break; + + case 'x': + password = g.getOptarg(); + break; + + case '?': + case ':': + default: + error = true; + break; + } // switch + } // while } catch (Exception e) { e.printStackTrace(); - usage(); - return; + error = true; } - - if (url == null) { + + if (error || args.length - g.getOptind() != 1) { usage(); - return; + System.exit(1); } + String url = args[g.getOptind()]; - String saveAs = suggestName(url); + if (saveAs == null) + saveAs = suggestName(url); OutputStream out; try { // resume from a previous eepget won't work right doing it this way out = new FileOutputStream(saveAs); } catch (IOException ioe) { System.err.println("Failed to create output file " + saveAs); - return; + out = null; // dummy for compiler + System.exit(1); } EepGet get = new PartialEepGet(I2PAppContext.getGlobalContext(), proxyHost, proxyPort, out, url, size); + if (username != null) { + if (password == null) { + try { + BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); + do { + System.err.print("Proxy password: "); + password = r.readLine(); + if (password == null) + throw new IOException(); + password = password.trim(); + } while (password.length() <= 0); + } catch (IOException ioe) { + System.exit(1); + } + } + get.addAuthorization(username, password); + } get.addStatusListener(get.new CLIStatusListener(1024, 40)); if (get.fetch(45*1000, -1, 60*1000)) { System.err.println("Last-Modified: " + get.getLastModified()); @@ -101,8 +158,10 @@ public class PartialEepGet extends EepGet { } private static void usage() { - System.err.println("PartialEepGet [-p 127.0.0.1:4444] [-l #bytes] url\n" + - " (use -p :0 for no proxy)"); + System.err.println("PartialEepGet [-p 127.0.0.1[:4444]] [-c] [-o outputFile]\n" + + " [-l #bytes] (default 56)\n" + + " [-u username] [-x password] url\n" + + " (use -c or -p :0 for no proxy)"); } @Override @@ -158,6 +217,11 @@ public class PartialEepGet extends EepGet { // This will be replaced if we are going through I2PTunnelHTTPClient if(!uaOverridden) buf.append("User-Agent: " + USER_AGENT + "\r\n"); + if (_authState != null && _shouldProxy && _authState.authMode != AUTH_MODE.NONE) { + buf.append("Proxy-Authorization: "); + buf.append(_authState.getAuthHeader("GET", urlToSend)); + buf.append("\r\n"); + } buf.append("\r\n"); if (_log.shouldLog(Log.DEBUG)) diff --git a/core/java/src/net/i2p/util/SSLEepGet.java b/core/java/src/net/i2p/util/SSLEepGet.java index 81b728b57262706d97260314c6c33cc3c20d6fbf..9236d6cae989428912b69b01593940b786e4f6ed 100644 --- a/core/java/src/net/i2p/util/SSLEepGet.java +++ b/core/java/src/net/i2p/util/SSLEepGet.java @@ -58,6 +58,8 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; +import gnu.getopt.Getopt; + import net.i2p.I2PAppContext; import net.i2p.crypto.CertUtil; import net.i2p.crypto.KeyStoreUtil; @@ -147,29 +149,34 @@ public class SSLEepGet extends EepGet { * SSLEepGet -s https://foo/bar */ public static void main(String args[]) { - String url = null; boolean saveCerts = false; + boolean error = false; + Getopt g = new Getopt("ssleepget", args, "s"); try { - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-s")) { + int c; + while ((c = g.getopt()) != -1) { + switch (c) { + case 's': saveCerts = true; - } else if (args[i].startsWith("-")) { - usage(); - return; - } else { - url = args[i]; - } - } + break; + + case '?': + case ':': + default: + error = true; + break; + } // switch + } // while } catch (Exception e) { e.printStackTrace(); - usage(); - return; + error = true; } - - if (url == null) { + + if (error || args.length - g.getOptind() != 1) { usage(); - return; + System.exit(1); } + String url = args[g.getOptind()]; String saveAs = suggestName(url); OutputStream out; @@ -191,8 +198,8 @@ public class SSLEepGet extends EepGet { } private static void usage() { - System.err.println("Usage: SSLEepGet https://url"); - System.err.println("To save unknown certs, use: SSLEepGet -s https://url"); + System.err.println("Usage: SSLEepGet https://url\n" + + "To save unknown certs, use: SSLEepGet -s https://url"); } /**