6811297: Add more logging to HTTP protocol handler
Summary: Added extra logging to HttpURLConnection and HttpClient. Added a capture tool.
Reviewed-by: chegar
--- a/jdk/make/sun/net/FILES_java.gmk Tue Jun 23 22:07:58 2009 -0700
+++ b/jdk/make/sun/net/FILES_java.gmk Thu Jun 25 18:56:30 2009 +0200
@@ -66,6 +66,9 @@
sun/net/www/protocol/file/Handler.java \
sun/net/www/protocol/file/FileURLConnection.java \
sun/net/www/http/HttpClient.java \
+ sun/net/www/http/HttpCapture.java \
+ sun/net/www/http/HttpCaptureInputStream.java \
+ sun/net/www/http/HttpCaptureOutputStream.java \
sun/net/www/http/PosterOutputStream.java \
sun/net/www/http/ChunkedInputStream.java \
sun/net/www/http/ChunkedOutputStream.java \
@@ -75,6 +78,7 @@
sun/net/www/http/Hurryable.java \
sun/net/www/protocol/http/Handler.java \
sun/net/www/protocol/http/HttpURLConnection.java \
+ sun/net/www/protocol/http/HttpLogFormatter.java \
sun/net/www/protocol/http/HttpAuthenticator.java \
sun/net/www/protocol/http/AuthenticationHeader.java \
sun/net/www/protocol/http/AuthenticationInfo.java \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/http/HttpCapture.java Thu Jun 25 18:56:30 2009 +0200
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.http;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import sun.net.NetProperties;
+import java.util.regex.*;
+
+/**
+ * Main class of the HTTP traffic capture tool.
+ * Captures are triggered by the sun.net.http.captureRules system property.
+ * If set, it should point to a file containing the capture rules.
+ * Format for the file is simple:
+ * - 1 rule per line
+ * - Lines starting with a # are considered comments and ignored
+ * - a rule is a pair of a regular expression and file pattern, separated by a comma
+ * - The regular expression is applied to URLs, if it matches, the traffic for
+ * that URL will be captured in the associated file.
+ * - if the file name contains a '%d', then that sequence will be replaced by a
+ * unique random number for each URL. This allow for multi-threaded captures
+ * of URLs matching the same pattern.
+ * - Rules are checked in sequence, in the same order as in the file, until a
+ * match is found or the end of the list is reached.
+ *
+ * Examples of rules:
+ * www\.sun\.com , sun%d.log
+ * yahoo\.com\/.*asf , yahoo.log
+ *
+ * @author jccollet
+ */
+public class HttpCapture {
+ private File file = null;
+ private boolean incoming = true;
+ private BufferedWriter out = null;
+ private static boolean initialized = false;
+ private static volatile ArrayList<Pattern> patterns = null;
+ private static volatile ArrayList<String> capFiles = null;
+
+ private static synchronized void init() {
+ initialized = true;
+ String rulesFile = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<String>() {
+ public String run() {
+ return NetProperties.get("sun.net.http.captureRules");
+ }
+ });
+ if (rulesFile != null && !rulesFile.isEmpty()) {
+ BufferedReader in;
+ try {
+ in = new BufferedReader(new FileReader(rulesFile));
+ } catch (FileNotFoundException ex) {
+ return;
+ }
+ try {
+ String line = in.readLine();
+ while (line != null) {
+ line = line.trim();
+ if (!line.startsWith("#")) {
+ // skip line if it's a comment
+ String[] s = line.split(",");
+ if (s.length == 2) {
+ if (patterns == null) {
+ patterns = new ArrayList<Pattern>();
+ capFiles = new ArrayList<String>();
+ }
+ patterns.add(Pattern.compile(s[0].trim()));
+ capFiles.add(s[1].trim());
+ }
+ }
+ line = in.readLine();
+ }
+ } catch (IOException ioe) {
+
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ex) {
+ }
+ }
+ }
+ }
+
+ private static synchronized boolean isInitialized() {
+ return initialized;
+ }
+
+ private HttpCapture(File f, java.net.URL url) {
+ file = f;
+ try {
+ out = new BufferedWriter(new FileWriter(file, true));
+ out.write("URL: " + url + "\n");
+ } catch (IOException ex) {
+ Logger.getLogger(HttpCapture.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+
+ public synchronized void sent(int c) throws IOException {
+ if (incoming) {
+ out.write("\n------>\n");
+ incoming = false;
+ out.flush();
+ }
+ out.write(c);
+ }
+
+ public synchronized void received(int c) throws IOException {
+ if (!incoming) {
+ out.write("\n<------\n");
+ incoming = true;
+ out.flush();
+ }
+ out.write(c);
+ }
+
+ public synchronized void flush() throws IOException {
+ out.flush();
+ }
+
+ public static HttpCapture getCapture(java.net.URL url) {
+ if (!isInitialized()) {
+ init();
+ }
+ if (patterns == null || patterns.isEmpty()) {
+ return null;
+ }
+ String s = url.toString();
+ for (int i = 0; i < patterns.size(); i++) {
+ Pattern p = patterns.get(i);
+ if (p.matcher(s).find()) {
+ String f = capFiles.get(i);
+ File fi;
+ if (f.indexOf("%d") >= 0) {
+ java.util.Random rand = new java.util.Random();
+ do {
+ String f2 = f.replace("%d", Integer.toString(rand.nextInt()));
+ fi = new File(f2);
+ } while (fi.exists());
+ } else {
+ fi = new File(f);
+ }
+ return new HttpCapture(fi, url);
+ }
+ }
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/http/HttpCaptureInputStream.java Thu Jun 25 18:56:30 2009 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.http;
+import java.io.*;
+
+/**
+ * A Simple FilterInputStream subclass to capture HTTP traffic.
+ * Every byte read is also passed to the HttpCapture class.
+ *
+ * @author jccollet
+ */
+public class HttpCaptureInputStream extends FilterInputStream {
+ private HttpCapture capture = null;
+
+ public HttpCaptureInputStream(InputStream in, HttpCapture cap) {
+ super(in);
+ capture = cap;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int i = super.read();
+ capture.received(i);
+ return i;
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ capture.flush();
+ } catch (IOException iOException) {
+ }
+ super.close();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int ret = super.read(b);
+ for (int i = 0; i < ret; i++) {
+ capture.received(b[i]);
+ }
+ return ret;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int ret = super.read(b, off, len);
+ for (int i = 0; i < ret; i++) {
+ capture.received(b[off+i]);
+ }
+ return ret;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/http/HttpCaptureOutputStream.java Thu Jun 25 18:56:30 2009 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.http;
+import java.io.*;
+
+/**
+ * A Simple FilterOutputStream subclass to capture HTTP traffic.
+ * Every byte written is also passed to the HttpCapture class.
+ *
+ * @author jccollet
+ */
+public class HttpCaptureOutputStream extends FilterOutputStream {
+ private HttpCapture capture = null;
+
+ public HttpCaptureOutputStream(OutputStream out, HttpCapture cap) {
+ super(out);
+ capture = cap;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ capture.sent(b);
+ out.write(b);
+ }
+
+ @Override
+ public void write(byte[] ba) throws IOException {
+ for (byte b : ba) {
+ capture.sent(b);
+ }
+ out.write(ba);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ for (int i = off; i < len; i++) {
+ capture.sent(b[i]);
+ }
+ out.write(b, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ capture.flush();
+ } catch (IOException iOException) {
+ }
+ super.flush();
+ }
+}
--- a/jdk/src/share/classes/sun/net/www/http/HttpClient.java Tue Jun 23 22:07:58 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/http/HttpClient.java Thu Jun 25 18:56:30 2009 +0200
@@ -27,6 +27,9 @@
import java.io.*;
import java.net.*;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import sun.net.NetworkClient;
import sun.net.ProgressSource;
import sun.net.www.MessageHeader;
@@ -34,7 +37,6 @@
import sun.net.www.MeteredStream;
import sun.net.www.ParseUtil;
import sun.net.www.protocol.http.HttpURLConnection;
-import sun.misc.RegexpPool;
/**
* @author Herb Jellinek
@@ -64,6 +66,10 @@
/** Default port number for http daemons. REMIND: make these private */
static final int httpPortNumber = 80;
+ // Use same logger as HttpURLConnection since we want to combine both event
+ // streams into one single HTTP log
+ private static Logger logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
+
/** return default port number (subclasses may override) */
protected int getDefaultPort () { return httpPortNumber; }
@@ -75,30 +81,6 @@
return -1;
}
- /* The following three data members are left in for binary */
- /* backwards-compatibility. Unfortunately, HotJava sets them directly */
- /* when it wants to change the settings. The new design has us not */
- /* cache these, so this is unnecessary, but eliminating the data members */
- /* would break HJB 1.1 under JDK 1.2. */
- /* */
- /* These data members are not used, and their values are meaningless. */
- /* REMIND: Take them out for JDK 2.0! */
- /**
- * @deprecated
- */
- // public static String proxyHost = null;
- /**
- * @deprecated
- */
- // public static int proxyPort = 80;
-
- /* instance-specific proxy fields override the static fields if set.
- * Used by FTP. These are set to the true proxy host/port if
- * usingProxy is true.
- */
- // private String instProxy = null;
- // private int instProxyPort = -1;
-
/* All proxying (generic as well as instance-specific) may be
* disabled through use of this flag
*/
@@ -141,6 +123,9 @@
/* if set, the client will be reused and must not be put in cache */
public boolean reuse = false;
+ // Traffic capture tool, if configured. See HttpCapture class for info
+ private HttpCapture capture = null;
+
/**
* A NOP method kept for backwards binary compatibility
* @deprecated -- system properties are no longer cached.
@@ -226,6 +211,7 @@
}
});
+ capture = HttpCapture.getCapture(url);
openServer();
}
@@ -300,8 +286,10 @@
// KeepAliveTimeout will get reset. We simply close the connection.
// This should be fine as it is very rare that a connection
// to the same host will not use the same proxy.
- ret.inCache = false;
- ret.closeServer();
+ synchronized(ret) {
+ ret.inCache = false;
+ ret.closeServer();
+ }
ret = null;
}
}
@@ -369,7 +357,7 @@
kac.put(url, null, this);
}
- protected boolean isInKeepAliveCache() {
+ protected synchronized boolean isInKeepAliveCache() {
return inCache;
}
@@ -389,11 +377,16 @@
* method parseHTTP(). That's why this method is overidden from the
* superclass.
*/
+ @Override
public void openServer(String server, int port) throws IOException {
serverSocket = doConnect(server, port);
try {
+ OutputStream out = serverSocket.getOutputStream();
+ if (capture != null) {
+ out = new HttpCaptureOutputStream(out, capture);
+ }
serverOutput = new PrintStream(
- new BufferedOutputStream(serverSocket.getOutputStream()),
+ new BufferedOutputStream(out),
false, encoding);
} catch (UnsupportedEncodingException e) {
throw new InternalError(encoding+" encoding not found");
@@ -412,7 +405,7 @@
/*
* Returns true if this httpclient is from cache
*/
- public boolean isCachedConnection() {
+ public synchronized boolean isCachedConnection() {
return cachedHttpClient;
}
@@ -458,26 +451,6 @@
}
/*
- * call super.openServer in a privileged block
- */
- private synchronized void privilegedSuperOpenServer(final String proxyHost,
- final int proxyPort)
- throws IOException
- {
- try {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedExceptionAction<Void>() {
- public Void run() throws IOException {
- superOpenServer(proxyHost, proxyPort);
- return null;
- }
- });
- } catch (java.security.PrivilegedActionException pae) {
- throw (IOException) pae.getException();
- }
- }
-
- /*
*/
protected synchronized void openServer() throws IOException {
@@ -490,8 +463,6 @@
return;
}
- String urlHost = url.getHost().toLowerCase();
-
if (url.getProtocol().equals("http") ||
url.getProtocol().equals("https") ) {
@@ -595,6 +566,9 @@
try {
serverInput = serverSocket.getInputStream();
+ if (capture != null) {
+ serverInput = new HttpCaptureInputStream(serverInput, capture);
+ }
serverInput = new BufferedInputStream(serverInput);
return (parseHTTPHeader(responses, pi, httpuc));
} catch (SocketTimeoutException stex) {
@@ -686,7 +660,7 @@
if (keep == null) {
keep = responses.findValue("Connection");
}
- if (keep != null && keep.toLowerCase().equals("keep-alive")) {
+ if (keep != null && keep.toLowerCase(Locale.US).equals("keep-alive")) {
/* some servers, notably Apache1.1, send something like:
* "Keep-Alive: timeout=15, max=1" which we should respect.
*/
@@ -767,10 +741,7 @@
* the HTTP method and response code indicate there will be
* no entity body to parse.
*/
- String te = null;
- try {
- te = responses.findValue("Transfer-Encoding");
- } catch (Exception e) {}
+ String te = responses.findValue("Transfer-Encoding");
if (te != null && te.equalsIgnoreCase("chunked")) {
serverInput = new ChunkedInputStream(serverInput, this, responses);
@@ -794,10 +765,14 @@
* 2. "Not-Modified" or "No-Content" responses - RFC 2616 states that
* 204 or 304 response must not include a message body.
*/
- try {
- cl = Long.parseLong(responses.findValue("content-length"));
- } catch (Exception e) {}
-
+ String cls = responses.findValue("content-length");
+ if (cls != null) {
+ try {
+ cl = Long.parseLong(cls);
+ } catch (NumberFormatException e) {
+ cl = -1;
+ }
+ }
String requestLine = requests.getKey(0);
if ((requestLine != null &&
@@ -835,6 +810,9 @@
if (isKeepingAlive()) {
// Wrap KeepAliveStream if keep alive is enabled.
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.finest("KeepAlive stream used: " + url);
+ }
serverInput = new KeepAliveStream(serverInput, pi, cl, this);
failedOnce = false;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpLogFormatter.java Thu Jun 25 18:56:30 2009 +0200
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http;
+
+import java.util.logging.LogRecord;
+import java.util.regex.*;
+
+/**
+ * A Formatter to make the HTTP logs a bit more palatable to the developer
+ * looking at them. The idea is to present the HTTP events in such a way that
+ * commands and headers are easily spotted (i.e. on separate lines).
+ * @author jccollet
+ */
+public class HttpLogFormatter extends java.util.logging.SimpleFormatter {
+ // Pattern for MessageHeader data. Mostly pairs within curly brackets
+ private static volatile Pattern pattern = null;
+ // Pattern for Cookies
+ private static volatile Pattern cpattern = null;
+
+ public HttpLogFormatter() {
+ if (pattern == null) {
+ pattern = Pattern.compile("\\{[^\\}]*\\}");
+ cpattern = Pattern.compile("[^,\\] ]{2,}");
+ }
+ }
+
+ @Override
+ public String format(LogRecord record) {
+ if (!"sun.net.www.protocol.http.HttpURLConnection".equalsIgnoreCase(record.getSourceClassName())
+ && !"sun.net.www.http.HttpClient".equalsIgnoreCase(record.getSourceClassName())) {
+ // Don't change format for stuff that doesn't concern us
+ return super.format(record);
+ }
+ String src = record.getMessage();
+ StringBuilder buf = new StringBuilder("HTTP: ");
+ if (src.startsWith("sun.net.www.MessageHeader@")) {
+ // MessageHeader logs are composed of pairs within curly brackets
+ // Let's extract them to make it more readable. That way we get one
+ // header pair (name, value) per line. A lot easier to read.
+ Matcher match = pattern.matcher(src);
+ while (match.find()) {
+ int i = match.start();
+ int j = match.end();
+ String s = src.substring(i + 1, j - 1);
+ if (s.startsWith("null: ")) {
+ s = s.substring(6);
+ }
+ if (s.endsWith(": null")) {
+ s = s.substring(0, s.length() - 6);
+ }
+ buf.append("\t").append(s).append("\n");
+ }
+ } else if (src.startsWith("Cookies retrieved: {")) {
+ // This comes from the Cookie handler, let's clean up the format a bit
+ String s = src.substring(20);
+ buf.append("Cookies from handler:\n");
+ while (s.length() >= 7) {
+ if (s.startsWith("Cookie=[")) {
+ String s2 = s.substring(8);
+ int c = s2.indexOf("Cookie2=[");
+ if (c > 0) {
+ s2 = s2.substring(0, c-1);
+ s = s2.substring(c);
+ } else {
+ s = "";
+ }
+ if (s2.length() < 4) {
+ continue;
+ }
+ Matcher m = cpattern.matcher(s2);
+ while (m.find()) {
+ int i = m.start();
+ int j = m.end();
+ if (i >= 0) {
+ String cookie = s2.substring(i + 1, j > 0 ? j - 1 : s2.length() - 1);
+ buf.append("\t").append(cookie).append("\n");
+ }
+ }
+ }
+ if (s.startsWith("Cookie2=[")) {
+ String s2 = s.substring(9);
+ int c = s2.indexOf("Cookie=[");
+ if (c > 0) {
+ s2 = s2.substring(0, c-1);
+ s = s2.substring(c);
+ } else {
+ s = "";
+ }
+ Matcher m = cpattern.matcher(s2);
+ while (m.find()) {
+ int i = m.start();
+ int j = m.end();
+ if (i >= 0) {
+ String cookie = s2.substring(i+1, j > 0 ? j-1 : s2.length() - 1);
+ buf.append("\t").append(cookie).append("\n");
+ }
+ }
+ }
+ }
+ } else {
+ // Anything else we let as is.
+ buf.append(src).append("\n");
+ }
+ return buf.toString();
+ }
+
+}
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Tue Jun 23 22:07:58 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Thu Jun 25 18:56:30 2009 +0200
@@ -237,7 +237,6 @@
/* try auth without calling Authenticator */
private boolean tryTransparentNTLMServer = NTLMAuthentication.supportsTransparentAuth();
private boolean tryTransparentNTLMProxy = NTLMAuthentication.supportsTransparentAuth();
- Object authObj;
/* Set if the user is manually setting the Authorization or Proxy-Authorization headers */
boolean isUserServerAuth;
@@ -303,9 +302,16 @@
return java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<PasswordAuthentication>() {
public PasswordAuthentication run() {
- return Authenticator.requestPasswordAuthentication(
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.finest("Requesting Authentication: host =" + host + " url = " + url);
+ }
+ PasswordAuthentication pass = Authenticator.requestPasswordAuthentication(
host, addr, port, protocol,
prompt, scheme, url, authType);
+ if (pass != null && logger.isLoggable(Level.FINEST)) {
+ logger.finest("Authentication returned: " + pass.toString());
+ }
+ return pass;
}
});
}
@@ -458,7 +464,7 @@
setRequests=true;
}
- if(logger.isLoggable(Level.FINEST)) {
+ if (logger.isLoggable(Level.FINE)) {
logger.fine(requests.toString());
}
http.writeRequests(requests, poster);
@@ -602,7 +608,7 @@
{
boolean redir;
int redirects = 0;
- InputStream in = null;
+ InputStream in;
do {
if (c instanceof HttpURLConnection) {
@@ -715,6 +721,12 @@
&& !(cachedResponse instanceof SecureCacheResponse)) {
cachedResponse = null;
}
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.finest("Cache Request for " + uri + " / " + getRequestMethod());
+ if (cachedResponse != null) {
+ logger.finest("From cache: "+cachedResponse.toString());
+ }
+ }
if (cachedResponse != null) {
cachedHeaders = mapToMessageHeader(cachedResponse.getHeaders());
cachedInputStream = cachedResponse.getBody();
@@ -750,10 +762,13 @@
return ProxySelector.getDefault();
}
});
- Proxy p = null;
if (sel != null) {
URI uri = sun.net.www.ParseUtil.toURI(url);
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.finest("ProxySelector Request for " + uri);
+ }
Iterator<Proxy> it = sel.select(uri).iterator();
+ Proxy p;
while (it.hasNext()) {
p = it.next();
try {
@@ -766,6 +781,11 @@
http = getNewHttpClient(url, p, connectTimeout, false);
http.setReadTimeout(readTimeout);
}
+ if (logger.isLoggable(Level.FINEST)) {
+ if (p != null) {
+ logger.finest("Proxy used: " + p.toString());
+ }
+ }
break;
} catch (IOException ioex) {
if (p != Proxy.NO_PROXY) {
@@ -993,10 +1013,16 @@
URI uri = ParseUtil.toURI(url);
if (uri != null) {
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.finest("CookieHandler request for " + uri);
+ }
Map<String, List<String>> cookies
= cookieHandler.get(
uri, requests.getHeaders(EXCLUDE_HEADERS));
if (!cookies.isEmpty()) {
+ if (logger.isLoggable(Level.FINEST)) {
+ logger.finest("Cookies retrieved: " + cookies.toString());
+ }
for (Map.Entry<String, List<String>> entry :
cookies.entrySet()) {
String key = entry.getKey();
@@ -1126,7 +1152,7 @@
writeRequests();
}
http.parseHTTP(responses, pi, this);
- if(logger.isLoggable(Level.FINEST)) {
+ if (logger.isLoggable(Level.FINE)) {
logger.fine(responses.toString());
}
inputStream = http.getInputStream();
@@ -1193,7 +1219,6 @@
disconnectInternal ();
throw new IOException ("Authentication failure");
}
- authObj = null;
doingNTLMp2ndStage = false;
continue;
}
@@ -1270,7 +1295,6 @@
throw new IOException ("Authentication failure");
}
doingNTLM2ndStage = false;
- authObj = null;
setCookieHeader();
continue;
}
@@ -1571,7 +1595,9 @@
http.parseHTTP(responses, null, this);
/* Log the response to the CONNECT */
- logger.fine(responses.toString());
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine(responses.toString());
+ }
statusLine = responses.getValue(0);
StringTokenizer st = new StringTokenizer(statusLine);
@@ -1617,12 +1643,9 @@
reset ();
if (!proxyAuthentication.setHeaders(this,
authhdr.headerParser(), raw)) {
- proxyHost = http.getProxyHostUsed();
- proxyPort = http.getProxyPortUsed();
disconnectInternal();
throw new IOException ("Authentication failure");
}
- authObj = null;
doingNTLMp2ndStage = false;
continue;
}
@@ -1699,7 +1722,9 @@
setPreemptiveProxyAuthentication(requests);
/* Log the CONNECT request */
- logger.fine(requests.toString());
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine(requests.toString());
+ }
http.writeRequests(requests, null);
// remove CONNECT header
@@ -1842,6 +1867,9 @@
}
}
}
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Proxy Authentication for " + authhdr.toString() +" returned " + ret.toString());
+ }
return ret;
}
@@ -1896,21 +1924,9 @@
}
if (ret == null) {
if (schemeID == NegotiateAuthentication.KERBEROS_AUTH) {
- URL url1;
- try {
- url1 = new URL (url, "/"); /* truncate the path */
- } catch (Exception e) {
- url1 = url;
- }
ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
}
if (schemeID == NegotiateAuthentication.NEGOTIATE_AUTH) {
- URL url1;
- try {
- url1 = new URL (url, "/"); /* truncate the path */
- } catch (Exception e) {
- url1 = url;
- }
ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
}
if (schemeID == BasicAuthentication.BASIC_AUTH) {
@@ -1981,6 +1997,9 @@
}
}
}
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Server Authentication for " + authhdr.toString() +" returned " + ret.toString());
+ }
return ret;
}
@@ -2054,6 +2073,9 @@
if (streaming()) {
throw new HttpRetryException (RETRY_MSG3, stat, loc);
}
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Redirected from " + url + " to " + locUrl);
+ }
// clear out old response headers!!!!
responses = new MessageHeader();
@@ -2158,11 +2180,17 @@
/* raw stream, which will block on read, so only read
* the expected number of bytes, probably 0
*/
- int cl = 0, n=0;
- try {
- cl = Integer.parseInt (responses.findValue ("Content-Length"));
- } catch (Exception e) {}
- for (int i=0; i<cl; ) {
+ long cl = 0;
+ int n = 0;
+ String cls = responses.findValue ("Content-Length");
+ if (cls != null) {
+ try {
+ cl = Long.parseLong (cls);
+ } catch (NumberFormatException e) {
+ cl = 0;
+ }
+ }
+ for (long i=0; i<cl; ) {
if ((n = is.read (cdata)) == -1) {
break;
} else {
@@ -2509,12 +2537,6 @@
return readTimeout < 0 ? 0 : readTimeout;
}
- @Override
- protected void finalize() {
- // this should do nothing. The stream finalizer will close
- // the fd
- }
-
String getMethod() {
return method;
}