/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @author Herb Jellinek
* @author Dave Brown
*/
// whether this httpclient comes from the cache
protected boolean cachedHttpClient = false;
protected boolean inCache;
// Http requests we send
// Http data we send with the headers
// true if we are in streaming mode (fixed length or chunked)
boolean streaming;
// if we've had one io error
boolean failedOnce = false;
/** Response code for CONTINUE */
private boolean ignoreContinue = true;
/** Default port number for http daemons. REMIND: make these private */
/** return default port number (subclasses may override) */
return 80;
return 443;
return -1;
}
/* All proxying (generic as well as instance-specific) may be
* disabled through use of this flag
*/
protected boolean proxyDisabled;
// are we using proxy in this instance?
public boolean usingProxy = false;
// target host, port for the URL
protected int port;
/* where we cache currently open, persistent connections */
private static boolean keepAliveProp = true;
// retryPostProp is true by default so as to preserve behavior
// from previous releases.
private static boolean retryPostProp = true;
/**Idle timeout value, in milliseconds. Zero means infinity,
* iff keepingAlive=true.
* Unfortunately, we can't always believe this one. If I'm connected
* through a Netscape proxy to a server that sent me a keep-alive
* time of 15 sec, the proxy unilaterally terminates my connection
* after 5 sec. So we have to hard code our effective timeout to
* 4 sec for the case where we're using a proxy. *SIGH*
*/
/** whether the response is to be cached */
/** Url being fetched. */
/* 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
}
}
/**
* A NOP method kept for backwards binary compatibility
* @deprecated -- system properties are no longer cached.
*/
public static synchronized void resetProperties() {
}
int getKeepAliveTimeout() {
return keepAliveTimeout;
}
static {
} else {
keepAliveProp = true;
}
} else
retryPostProp = true;
}
/**
* @return true iff http keep alive is set (i.e. enabled). Defaults
* to true if the system property http.keepAlive isn't set.
*/
public boolean getHttpKeepAliveSet() {
return keepAliveProp;
}
protected HttpClient() {
}
throws IOException {
}
boolean proxyDisabled) throws IOException {
}
/* This package-only CTOR should only be used for FTP piggy-backed on HTTP
* HTTP URL's that use this won't take advantage of keep-alive.
* Additionally, this constructor may be used as a last resort when the
* first HttpClient gotten through New() failed (probably b/c of a
* Keep-Alive mismatch).
*
* XXX That documentation is wrong ... it's not package-private any more
*/
throws IOException {
}
if (port == -1) {
port = getDefaultPort();
}
openServer();
}
}
/*
* This constructor gives "ultimate" flexibility, including the ability
* to bypass implicit proxying. Sometimes we need to be using tunneling
* (transport or network level) instead of proxying (application level),
* for example when we don't want the application level data to become
* visible to third parties.
*
* @param url the URL to which we're connecting
* @param proxy proxy to use for this URL (e.g. forwarding)
* @param proxyPort proxy port to use for this URL
* @param proxyDisabled true to disable default proxying
*/
boolean proxyDisabled)
throws IOException {
}
boolean proxyDisabled, int to)
throws IOException {
}
/* This class has no public constructor for HTTP. This method is used to
* get an HttpClient to the specifed URL. If there's currently an
*/
throws IOException {
}
throws IOException {
}
{
if (p == null) {
}
/* see if one's already around */
if (useCache) {
ret.closeServer();
}
}
synchronized (ret) {
ret.cachedHttpClient = true;
}
} else {
// We cannot return this connection to the cache as it's
// 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.
synchronized(ret) {
ret.closeServer();
}
}
}
}
} else {
} else {
}
}
}
return ret;
}
{
}
boolean useCache)
throws IOException {
}
throws IOException {
}
/* return it to the cache as still usable, if:
* 1) It's keeping alive, AND
* 2) It still has some connections left, AND
* 3) It hasn't had a error (PrintStream.checkError())
* 4) It hasn't timed out
*
* If this client is not keepingAlive, it should have been
* removed from the cache in the parseHeaders() method.
*/
public void finished() {
if (reuse) /* will be reused */
return;
!(serverOutput.checkError())) {
/* This connection is keepingAlive && still valid.
* Return it to the cache.
*/
} else {
closeServer();
}
}
protected synchronized boolean available() {
boolean available = true;
int old = -1;
try {
try {
if (r == -1) {
logFinest("HttpClient.available(): " +
"read returned -1: not available");
available = false;
}
} catch (SocketTimeoutException e) {
logFinest("HttpClient.available(): " +
"SocketTimeout: its available");
} finally {
if (old != -1)
}
} catch (IOException e) {
logFinest("HttpClient.available(): " +
"SocketException: not available");
available = false;
}
return available;
}
protected synchronized void putInKeepAliveCache() {
if (inCache) {
assert false : "Duplicate put to keep alive cache";
return;
}
inCache = true;
}
protected synchronized boolean isInKeepAliveCache() {
return inCache;
}
/*
* Close an idle connection to this URL (if it exists in the
* cache).
*/
public void closeIdleConnection() {
http.closeServer();
}
}
/* We're very particular here about what our InputStream to the server
* looks like for reasons that are apparent if you can decipher the
* method parseHTTP(). That's why this method is overidden from the
* superclass.
*/
try {
}
serverOutput = new PrintStream(
new BufferedOutputStream(out),
false, encoding);
} catch (UnsupportedEncodingException e) {
}
serverSocket.setTcpNoDelay(true);
}
/*
* Returns true if the http request should be tunneled through proxy.
* An example where this is the case is Https.
*/
public boolean needsTunneling() {
return false;
}
/*
* Returns true if this httpclient is from cache
*/
public synchronized boolean isCachedConnection() {
return cachedHttpClient;
}
/*
* Finish any work left after the socket connection is
* established. In the normal http case, it's a NO-OP. Subclass
* may need to override this. An example is Https, where for
* direct connection to the origin server, ssl handshake needs to
* be done; for proxy tunneling, the socket needs to be converted
* into an SSL socket before ssl handshake can take place.
*/
// NO-OP. Needs to be overwritten by HttpsClient
}
/*
* call openServer in a privileged block
*/
throws IOException
{
try {
return null;
}
});
}
}
/*
* call super.openServer
*/
final int proxyPort)
throws IOException, UnknownHostException
{
}
/*
*/
}
if (keepingAlive) { // already opened
return;
}
usingProxy = true;
return;
} else {
// make direct connection
usingProxy = false;
return;
}
} else {
/* we're opening some other kind of url, most likely an
* ftp url.
*/
usingProxy = true;
return;
} else {
// make direct connection
usingProxy = false;
return;
}
}
}
fileName = "/";
/**
* proxyDisabled is set by subclass HttpsClient!
*/
if (usingProxy && !proxyDisabled) {
// Do not use URLStreamHandler.toExternalForm as the fragment
// should not be part of the RequestURI. It should be an
// absolute URI which does not have a fragment part.
}
}
}
}
return fileName;
else
}
/**
* @deprecated
*/
}
}
boolean streaming) throws IOException {
}
/** Parse the first line of the HTTP request. It usually looks
something like: "HTTP/1.0 <number> comment\r\n". */
throws IOException {
/* If "HTTP/*" is found in the beginning, return true. Let
* HttpURLConnection parse the mime header itself.
*
* If this isn't valid HTTP, then we don't try to parse a header
* out of the beginning of the response into the responses,
* and instead just queue up the output stream to it's very beginning.
* This seems most reasonable, and is what the NN browser does.
*/
try {
}
} catch (SocketTimeoutException stex) {
// We don't want to retry the request when the app. sets a timeout
// but don't close the server if timeout while waiting for 100-continue
if (ignoreContinue) {
closeServer();
}
throw stex;
} catch (IOException e) {
closeServer();
cachedHttpClient = false;
failedOnce = true;
(!retryPostProp || streaming))) {
// do not retry the request
} else {
// try once more
openServer();
if (needsTunneling()) {
}
afterConnect();
}
}
throw e;
}
}
private boolean parseHTTPHeader(MessageHeader responses, ProgressSource pi, HttpURLConnection httpuc)
throws IOException {
/* If "HTTP/*" is found in the beginning, return true. Let
* HttpURLConnection parse the mime header itself.
*
* If this isn't valid HTTP, then we don't try to parse a header
* out of the beginning of the response into the responses,
* and instead just queue up the output stream to it's very beginning.
* This seems most reasonable, and is what the NN browser does.
*/
keepAliveConnections = -1;
keepAliveTimeout = 0;
boolean ret = false;
byte[] b = new byte[8];
try {
int nread = 0;
while (nread < 8) {
if (r < 0) {
break;
}
nread += r;
}
&& b[2] == 'T' && b[3] == 'P' && b[4] == '/' &&
b[5] == '1' && b[6] == '.';
serverInput.reset();
if (ret) { // is valid HTTP - response started w/ "HTTP/1."
// we've finished parsing http headers
// check if there are any applicable cookies to set (in cache)
if (cookieHandler != null) {
// NOTE: That cast from Map shouldn't be necessary but
// a bug in javac is triggered under certain circumstances
// So we do put the cast in as a workaround until
// it is resolved.
}
/* decide if we're keeping alive:
* This is a bit tricky. There's a spec, but most current
* servers (10/1/96) that support this differ in dialects.
* protocol should fall back onto HTTP/1.0, no keep-alive.
*/
if (usingProxy) { // not likely a proxy will return this
}
}
/* some servers, notably Apache1.1, send something like:
* "Keep-Alive: timeout=15, max=1" which we should respect.
*/
HeaderParser p = new HeaderParser(
if (p != null) {
/* default should be larger in case of proxy */
}
} else if (b[7] != '0') {
/*
* We're talking 1.1 or later. Keep persistent until
* the server says to close.
*/
/*
* The only Connection token we understand is close.
* Paranoia: if there is any Connection header then
* treat as non-persistent.
*/
keepAliveConnections = 1;
} else {
keepAliveConnections = 5;
}
}
} else if (nread != 8) {
failedOnce = true;
(!retryPostProp || streaming))) {
// do not retry the request
} else {
closeServer();
cachedHttpClient = false;
openServer();
if (needsTunneling()) {
}
afterConnect();
}
}
throw new SocketException("Unexpected end of file from server");
} else {
// we can't vouche for what this is....
}
} catch (IOException e) {
throw e;
}
int code = -1;
try {
* expedite the typical case by assuming it has
* form "HTTP/1.x <WS> 2XX <mumble>"
*/
int ind;
ind++;
} catch (Exception e) {}
}
long cl = -1;
/*
* Set things up to parse the entity body of the reply.
* We should be smarter about avoid pointless work when
* the HTTP method and response code indicate there will be
* no entity body to parse.
*/
/*
* If keep alive not specified then close after the stream
* has completed.
*/
if (keepAliveConnections <= 1) {
keepAliveConnections = 1;
keepingAlive = false;
} else {
keepingAlive = true;
}
failedOnce = false;
} else {
/*
* If it's a keep alive connection then we will keep
* (alive if :-
* 1. content-length is specified, or
* 2. "Not-Modified" or "No-Content" responses - RFC 2616 states that
* 204 or 304 response must not include a message body.
*/
try {
} catch (NumberFormatException e) {
cl = -1;
}
}
if ((requestLine != null &&
cl = 0;
}
if (keepAliveConnections > 1 &&
(cl >= 0 ||
keepingAlive = true;
failedOnce = false;
} else if (keepingAlive) {
/* Previously we were keeping alive, and now we're not. Remove
* this from the cache (but only here, once) - otherwise we get
* multiple removes and the cache count gets messed up.
*/
keepingAlive=false;
}
}
/* wrap a KeepAliveStream/MeteredStream around it if appropriate */
if (cl > 0) {
// In this case, content length is well known, so it is okay
// to wrap the input stream with KeepAliveStream/MeteredStream.
// Progress monitor is enabled
}
if (isKeepingAlive()) {
// Wrap KeepAliveStream if keep alive is enabled.
failedOnce = false;
}
else {
}
}
else if (cl == -1) {
// In this case, content length is unknown - the input
// stream would simply be a regular InputStream or
// ChunkedInputStream.
// Progress monitoring is enabled.
// Wrap MeteredStream for tracking indeterministic
// progress, even if the input stream is ChunkedInputStream.
}
else {
// Progress monitoring is disabled, and there is no
// need to wrap an unknown length input stream.
// ** This is an no-op **
}
}
else {
pi.finishTracking();
}
return ret;
}
return serverInput;
}
return serverOutput;
}
}
public final boolean isKeepingAlive() {
return getHttpKeepAliveSet() && keepingAlive;
}
this.cacheRequest = cacheRequest;
}
return cacheRequest;
}
if (requestLine != null) {
}
}
return "";
}
// This should do nothing. The stream finalizer will
// close the fd.
}
// failedOnce is used to determine if a request should be retried.
failedOnce = value;
}
}
/* Use only on connections in error. */
public void closeServer() {
try {
keepingAlive = false;
} catch (Exception e) {}
}
/**
* @return the proxy host being used for this client, or null
* if we're not going through a proxy
*/
if (!usingProxy) {
return null;
} else {
}
}
/**
* @return the proxy port being used for this client. Meaningless
* if getProxyHostUsed() gives null.
*/
public int getProxyPortUsed() {
if (usingProxy)
return -1;
}
}