diff options
Diffstat (limited to 'core/java/android/net')
49 files changed, 0 insertions, 13708 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java deleted file mode 100644 index 1429bc1..0000000 --- a/core/java/android/net/ConnectivityManager.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.os.RemoteException; - -/** - * Class that answers queries about the state of network connectivity. It also - * notifies applications when network connectivity changes. Get an instance - * of this class by calling - * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.CONNECTIVITY_SERVICE)}. - * <p> - * The primary responsibilities of this class are to: - * <ol> - * <li>Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)</li> - * <li>Send broadcast intents when network connectivity changes</li> - * <li>Attempt to "fail over" to another network when connectivity to a network - * is lost</li> - * <li>Provide an API that allows applications to query the coarse-grained or fine-grained - * state of the available networks</li> - * </ol> - */ -public class ConnectivityManager -{ - /** - * A change in network connectivity has occurred. A connection has either - * been established or lost. The NetworkInfo for the affected network is - * sent as an extra; it should be consulted to see what kind of - * connectivity event occurred. - * <p/> - * If this is a connection that was the result of failing over from a - * disconnected network, then the FAILOVER_CONNECTION boolean extra is - * set to true. - * <p/> - * For a loss of connectivity, if the connectivity manager is attempting - * to connect (or has already connected) to another network, the - * NetworkInfo for the new network is also passed as an extra. This lets - * any receivers of the broadcast know that they should not necessarily - * tell the user that no data traffic will be possible. Instead, the - * reciever should expect another broadcast soon, indicating either that - * the failover attempt succeeded (and so there is still overall data - * connectivity), or that the failover attempt failed, meaning that all - * connectivity has been lost. - * <p/> - * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY - * is set to {@code true} if there are no connected networks at all. - */ - public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; - /** - * The lookup key for a {@link NetworkInfo} object. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. - */ - public static final String EXTRA_NETWORK_INFO = "networkInfo"; - /** - * The lookup key for a boolean that indicates whether a connect event - * is for a network to which the connectivity manager was failing over - * following a disconnect on another network. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - */ - public static final String EXTRA_IS_FAILOVER = "isFailover"; - /** - * The lookup key for a {@link NetworkInfo} object. This is supplied when - * there is another network that it may be possible to connect to. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. - */ - public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; - /** - * The lookup key for a boolean that indicates whether there is a - * complete lack of connectivity, i.e., no network is available. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - */ - public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity"; - /** - * The lookup key for a string that indicates why an attempt to connect - * to a network failed. The string has no particular structure. It is - * intended to be used in notifications presented to users. Retrieve - * it with {@link android.content.Intent#getStringExtra(String)}. - */ - public static final String EXTRA_REASON = "reason"; - /** - * The lookup key for a string that provides optionally supplied - * extra information about the network state. The information - * may be passed up from the lower networking layers, and its - * meaning may be specific to a particular network type. Retrieve - * it with {@link android.content.Intent#getStringExtra(String)}. - */ - public static final String EXTRA_EXTRA_INFO = "extraInfo"; - - /** - * Broadcast Action: The setting for background data usage has changed - * values. Use {@link #getBackgroundDataSetting()} to get the current value. - * <p> - * If an application uses the network in the background, it should listen - * for this broadcast and stop using the background data if the value is - * false. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = - "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; - - public static final int TYPE_MOBILE = 0; - public static final int TYPE_WIFI = 1; - - public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; - - private IConnectivityManager mService; - - static public boolean isNetworkTypeValid(int networkType) { - return networkType == TYPE_WIFI || networkType == TYPE_MOBILE; - } - - public void setNetworkPreference(int preference) { - try { - mService.setNetworkPreference(preference); - } catch (RemoteException e) { - } - } - - public int getNetworkPreference() { - try { - return mService.getNetworkPreference(); - } catch (RemoteException e) { - return -1; - } - } - - public NetworkInfo getActiveNetworkInfo() { - try { - return mService.getActiveNetworkInfo(); - } catch (RemoteException e) { - return null; - } - } - - public NetworkInfo getNetworkInfo(int networkType) { - try { - return mService.getNetworkInfo(networkType); - } catch (RemoteException e) { - return null; - } - } - - public NetworkInfo[] getAllNetworkInfo() { - try { - return mService.getAllNetworkInfo(); - } catch (RemoteException e) { - return null; - } - } - - /** {@hide} */ - public boolean setRadios(boolean turnOn) { - try { - return mService.setRadios(turnOn); - } catch (RemoteException e) { - return false; - } - } - - /** {@hide} */ - public boolean setRadio(int networkType, boolean turnOn) { - try { - return mService.setRadio(networkType, turnOn); - } catch (RemoteException e) { - return false; - } - } - - /** - * Tells the underlying networking system that the caller wants to - * begin using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - * @param networkType specifies which network the request pertains to - * @param feature the name of the feature to be used - * @return an integer value representing the outcome of the request. - * The interpretation of this value is specific to each networking - * implementation+feature combination, except that the value {@code -1} - * always indicates failure. - */ - public int startUsingNetworkFeature(int networkType, String feature) { - try { - return mService.startUsingNetworkFeature(networkType, feature); - } catch (RemoteException e) { - return -1; - } - } - - /** - * Tells the underlying networking system that the caller is finished - * using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - * @param networkType specifies which network the request pertains to - * @param feature the name of the feature that is no longer needed - * @return an integer value representing the outcome of the request. - * The interpretation of this value is specific to each networking - * implementation+feature combination, except that the value {@code -1} - * always indicates failure. - */ - public int stopUsingNetworkFeature(int networkType, String feature) { - try { - return mService.stopUsingNetworkFeature(networkType, feature); - } catch (RemoteException e) { - return -1; - } - } - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the specified network interface. An attempt to add a route that - * already exists is ignored, but treated as successful. - * @param networkType the type of the network over which traffic to the specified - * host is to be routed - * @param hostAddress the IP address of the host to which the route is desired - * @return {@code true} on success, {@code false} on failure - */ - public boolean requestRouteToHost(int networkType, int hostAddress) { - try { - return mService.requestRouteToHost(networkType, hostAddress); - } catch (RemoteException e) { - return false; - } - } - - /** - * Returns the value of the setting for background data usage. If false, - * applications should not use the network if the application is not in the - * foreground. Developers should respect this setting, and check the value - * of this before performing any background data operations. - * <p> - * All applications that have background services that use the network - * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}. - * - * @return Whether background data usage is allowed. - */ - public boolean getBackgroundDataSetting() { - try { - return mService.getBackgroundDataSetting(); - } catch (RemoteException e) { - // Err on the side of safety - return false; - } - } - - /** - * Sets the value of the setting for background data usage. - * - * @param allowBackgroundData Whether an application should use data while - * it is in the background. - * - * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING - * @see #getBackgroundDataSetting() - * @hide - */ - public void setBackgroundDataSetting(boolean allowBackgroundData) { - try { - mService.setBackgroundDataSetting(allowBackgroundData); - } catch (RemoteException e) { - } - } - - /** - * Don't allow use of default constructor. - */ - @SuppressWarnings({"UnusedDeclaration"}) - private ConnectivityManager() { - } - - /** - * {@hide} - */ - public ConnectivityManager(IConnectivityManager service) { - if (service == null) { - throw new IllegalArgumentException( - "ConnectivityManager() cannot be constructed with null service"); - } - mService = service; - } -} diff --git a/core/java/android/net/Credentials.java b/core/java/android/net/Credentials.java deleted file mode 100644 index 7f6cf9d..0000000 --- a/core/java/android/net/Credentials.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * A class for representing UNIX credentials passed via ancillary data - * on UNIX domain sockets. See "man 7 unix" on a desktop linux distro. - */ -public class Credentials { - /** pid of process. root peers may lie. */ - private final int pid; - /** uid of process. root peers may lie. */ - private final int uid; - /** gid of process. root peers may lie. */ - private final int gid; - - public Credentials (int pid, int uid, int gid) { - this.pid = pid; - this.uid = uid; - this.gid = gid; - } - - public int getPid() { - return pid; - } - - public int getUid() { - return uid; - } - - public int getGid() { - return gid; - } -} diff --git a/core/java/android/net/DhcpInfo.aidl b/core/java/android/net/DhcpInfo.aidl deleted file mode 100644 index 29cd21f..0000000 --- a/core/java/android/net/DhcpInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable DhcpInfo; diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java deleted file mode 100644 index 1178bec..0000000 --- a/core/java/android/net/DhcpInfo.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcelable; -import android.os.Parcel; - -/** - * A simple object for retrieving the results of a DHCP request. - */ -public class DhcpInfo implements Parcelable { - public int ipAddress; - public int gateway; - public int netmask; - - public int dns1; - public int dns2; - - public int serverAddress; - public int leaseDuration; - - public DhcpInfo() { - super(); - } - - public String toString() { - StringBuffer str = new StringBuffer(); - - str.append("ipaddr "); putAddress(str, ipAddress); - str.append(" gateway "); putAddress(str, gateway); - str.append(" netmask "); putAddress(str, netmask); - str.append(" dns1 "); putAddress(str, dns1); - str.append(" dns2 "); putAddress(str, dns2); - str.append(" DHCP server "); putAddress(str, serverAddress); - str.append(" lease ").append(leaseDuration).append(" seconds"); - - return str.toString(); - } - - private static void putAddress(StringBuffer buf, int addr) { - buf.append(addr & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff).append('.'). - append((addr >>>= 8) & 0xff); - } - - /** Implement the Parcelable interface {@hide} */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface {@hide} */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(ipAddress); - dest.writeInt(gateway); - dest.writeInt(netmask); - dest.writeInt(dns1); - dest.writeInt(dns2); - dest.writeInt(serverAddress); - dest.writeInt(leaseDuration); - } - - /** Implement the Parcelable interface {@hide} */ - public static final Creator<DhcpInfo> CREATOR = - new Creator<DhcpInfo>() { - public DhcpInfo createFromParcel(Parcel in) { - DhcpInfo info = new DhcpInfo(); - info.ipAddress = in.readInt(); - info.gateway = in.readInt(); - info.netmask = in.readInt(); - info.dns1 = in.readInt(); - info.dns2 = in.readInt(); - info.serverAddress = in.readInt(); - info.leaseDuration = in.readInt(); - return info; - } - - public DhcpInfo[] newArray(int size) { - return new DhcpInfo[size]; - } - }; -} diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl deleted file mode 100644 index de68598..0000000 --- a/core/java/android/net/IConnectivityManager.aidl +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.net.NetworkInfo; - -/** - * Interface that answers queries about, and allows changing, the - * state of network connectivity. - */ -/** {@hide} */ -interface IConnectivityManager -{ - void setNetworkPreference(int pref); - - int getNetworkPreference(); - - NetworkInfo getActiveNetworkInfo(); - - NetworkInfo getNetworkInfo(int networkType); - - NetworkInfo[] getAllNetworkInfo(); - - boolean setRadios(boolean onOff); - - boolean setRadio(int networkType, boolean turnOn); - - int startUsingNetworkFeature(int networkType, in String feature); - - int stopUsingNetworkFeature(int networkType, in String feature); - - boolean requestRouteToHost(int networkType, int hostAddress); - - boolean getBackgroundDataSetting(); - - void setBackgroundDataSetting(boolean allowBackgroundData); -} diff --git a/core/java/android/net/LocalServerSocket.java b/core/java/android/net/LocalServerSocket.java deleted file mode 100644 index 2b93fc2..0000000 --- a/core/java/android/net/LocalServerSocket.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.io.IOException; -import java.io.FileDescriptor; - -/** - * non-standard class for creating inbound UNIX-domain socket - * on the Android platform, this is created in the Linux non-filesystem - * namespace. - * - * On simulator platforms, this may be created in a temporary directory on - * the filesystem - */ -public class LocalServerSocket { - private final LocalSocketImpl impl; - private final LocalSocketAddress localAddress; - - /** 50 seems a bit much, but it's what was here */ - private static final int LISTEN_BACKLOG = 50; - - /** - * Crewates a new server socket listening at specified name. - * On the Android platform, the name is created in the Linux - * abstract namespace (instead of on the filesystem). - * - * @param name address for socket - * @throws IOException - */ - public LocalServerSocket(String name) throws IOException - { - impl = new LocalSocketImpl(); - - impl.create(true); - - localAddress = new LocalSocketAddress(name); - impl.bind(localAddress); - - impl.listen(LISTEN_BACKLOG); - } - - /** - * Create a LocalServerSocket from a file descriptor that's already - * been created and bound. listen() will be called immediately on it. - * Used for cases where file descriptors are passed in via environment - * variables - * - * @param fd bound file descriptor - * @throws IOException - */ - public LocalServerSocket(FileDescriptor fd) throws IOException - { - impl = new LocalSocketImpl(fd); - impl.listen(LISTEN_BACKLOG); - localAddress = impl.getSockAddress(); - } - - /** - * Obtains the socket's local address - * - * @return local address - */ - public LocalSocketAddress getLocalSocketAddress() - { - return localAddress; - } - - /** - * Accepts a new connection to the socket. Blocks until a new - * connection arrives. - * - * @return a socket representing the new connection. - * @throws IOException - */ - public LocalSocket accept() throws IOException - { - LocalSocketImpl acceptedImpl = new LocalSocketImpl(); - - impl.accept (acceptedImpl); - - return new LocalSocket(acceptedImpl); - } - - /** - * Returns file descriptor or null if not yet open/already closed - * - * @return fd or null - */ - public FileDescriptor getFileDescriptor() { - return impl.getFileDescriptor(); - } - - /** - * Closes server socket. - * - * @throws IOException - */ - public void close() throws IOException - { - impl.close(); - } -} diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java deleted file mode 100644 index 4039a69..0000000 --- a/core/java/android/net/LocalSocket.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.SocketOptions; - -/** - * Creates a (non-server) socket in the UNIX-domain namespace. The interface - * here is not entirely unlike that of java.net.Socket - */ -public class LocalSocket { - - private LocalSocketImpl impl; - private volatile boolean implCreated; - private LocalSocketAddress localAddress; - private boolean isBound; - private boolean isConnected; - - /** - * Creates a AF_LOCAL/UNIX domain stream socket. - */ - public LocalSocket() { - this(new LocalSocketImpl()); - isBound = false; - isConnected = false; - } - - /** - * for use with AndroidServerSocket - * @param impl a SocketImpl - */ - /*package*/ LocalSocket(LocalSocketImpl impl) { - this.impl = impl; - this.isConnected = false; - this.isBound = false; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return super.toString() + " impl:" + impl; - } - - /** - * It's difficult to discern from the spec when impl.create() should be - * called, but it seems like a reasonable rule is "as soon as possible, - * but not in a context where IOException cannot be thrown" - * - * @throws IOException from SocketImpl.create() - */ - private void implCreateIfNeeded() throws IOException { - if (!implCreated) { - synchronized (this) { - if (!implCreated) { - implCreated = true; - impl.create(true); - } - } - } - } - - /** - * Connects this socket to an endpoint. May only be called on an instance - * that has not yet been connected. - * - * @param endpoint endpoint address - * @throws IOException if socket is in invalid state or the address does - * not exist. - */ - public void connect(LocalSocketAddress endpoint) throws IOException { - synchronized (this) { - if (isConnected) { - throw new IOException("already connected"); - } - - implCreateIfNeeded(); - impl.connect(endpoint, 0); - isConnected = true; - isBound = true; - } - } - - /** - * Binds this socket to an endpoint name. May only be called on an instance - * that has not yet been bound. - * - * @param bindpoint endpoint address - * @throws IOException - */ - public void bind(LocalSocketAddress bindpoint) throws IOException { - implCreateIfNeeded(); - - synchronized (this) { - if (isBound) { - throw new IOException("already bound"); - } - - localAddress = bindpoint; - impl.bind(localAddress); - isBound = true; - } - } - - /** - * Retrieves the name that this socket is bound to, if any. - * - * @return Local address or null if anonymous - */ - public LocalSocketAddress getLocalSocketAddress() { - return localAddress; - } - - /** - * Retrieves the input stream for this instance. - * - * @return input stream - * @throws IOException if socket has been closed or cannot be created. - */ - public InputStream getInputStream() throws IOException { - implCreateIfNeeded(); - return impl.getInputStream(); - } - - /** - * Retrieves the output stream for this instance. - * - * @return output stream - * @throws IOException if socket has been closed or cannot be created. - */ - public OutputStream getOutputStream() throws IOException { - implCreateIfNeeded(); - return impl.getOutputStream(); - } - - /** - * Closes the socket. - * - * @throws IOException - */ - public void close() throws IOException { - implCreateIfNeeded(); - impl.close(); - } - - /** - * Shuts down the input side of the socket. - * - * @throws IOException - */ - public void shutdownInput() throws IOException { - implCreateIfNeeded(); - impl.shutdownInput(); - } - - /** - * Shuts down the output side of the socket. - * - * @throws IOException - */ - public void shutdownOutput() throws IOException { - implCreateIfNeeded(); - impl.shutdownOutput(); - } - - public void setReceiveBufferSize(int size) throws IOException { - impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); - } - - public int getReceiveBufferSize() throws IOException { - return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue(); - } - - public void setSoTimeout(int n) throws IOException { - impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(n)); - } - - public int getSoTimeout() throws IOException { - return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue(); - } - - public void setSendBufferSize(int n) throws IOException { - impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(n)); - } - - public int getSendBufferSize() throws IOException { - return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue(); - } - - //???SEC - public LocalSocketAddress getRemoteSocketAddress() { - throw new UnsupportedOperationException(); - } - - //???SEC - public synchronized boolean isConnected() { - return isConnected; - } - - //???SEC - public boolean isClosed() { - throw new UnsupportedOperationException(); - } - - //???SEC - public synchronized boolean isBound() { - return isBound; - } - - //???SEC - public boolean isOutputShutdown() { - throw new UnsupportedOperationException(); - } - - //???SEC - public boolean isInputShutdown() { - throw new UnsupportedOperationException(); - } - - //???SEC - public void connect(LocalSocketAddress endpoint, int timeout) - throws IOException { - throw new UnsupportedOperationException(); - } - - /** - * Enqueues a set of file descriptors to send to the peer. The queue - * is one deep. The file descriptors will be sent with the next write - * of normal data, and will be delivered in a single ancillary message. - * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. - * - * @param fds non-null; file descriptors to send. - */ - public void setFileDescriptorsForSend(FileDescriptor[] fds) { - impl.setFileDescriptorsForSend(fds); - } - - /** - * Retrieves a set of file descriptors that a peer has sent through - * an ancillary message. This method retrieves the most recent set sent, - * and then returns null until a new set arrives. - * File descriptors may only be passed along with regular data, so this - * method can only return a non-null after a read operation. - * - * @return null or file descriptor array - * @throws IOException - */ - public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { - return impl.getAncillaryFileDescriptors(); - } - - /** - * Retrieves the credentials of this socket's peer. Only valid on - * connected sockets. - * - * @return non-null; peer credentials - * @throws IOException - */ - public Credentials getPeerCredentials() throws IOException { - return impl.getPeerCredentials(); - } - - /** - * Returns file descriptor or null if not yet open/already closed - * - * @return fd or null - */ - public FileDescriptor getFileDescriptor() { - return impl.getFileDescriptor(); - } -} diff --git a/core/java/android/net/LocalSocketAddress.java b/core/java/android/net/LocalSocketAddress.java deleted file mode 100644 index 8265b85..0000000 --- a/core/java/android/net/LocalSocketAddress.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * A UNIX-domain (AF_LOCAL) socket address. For use with - * android.net.LocalSocket and android.net.LocalServerSocket. - * - * On the Android system, these names refer to names in the Linux - * abstract (non-filesystem) UNIX domain namespace. - */ -public class LocalSocketAddress -{ - /** - * The namespace that this address exists in. See also - * include/cutils/sockets.h ANDROID_SOCKET_NAMESPACE_* - */ - public enum Namespace { - /** A socket in the Linux abstract namespace */ - ABSTRACT(0), - /** - * A socket in the Android reserved namespace in /dev/socket. - * Only the init process may create a socket here. - */ - RESERVED(1), - /** - * A socket named with a normal filesystem path. - */ - FILESYSTEM(2); - - /** The id matches with a #define in include/cutils/sockets.h */ - private int id; - Namespace (int id) { - this.id = id; - } - - /** - * @return int constant shared with native code - */ - /*package*/ int getId() { - return id; - } - } - - private final String name; - private final Namespace namespace; - - /** - * Creates an instance with a given name. - * - * @param name non-null name - * @param namespace namespace the name should be created in. - */ - public LocalSocketAddress(String name, Namespace namespace) { - this.name = name; - this.namespace = namespace; - } - - /** - * Creates an instance with a given name in the {@link Namespace#ABSTRACT} - * namespace - * - * @param name non-null name - */ - public LocalSocketAddress(String name) { - this(name,Namespace.ABSTRACT); - } - - /** - * Retrieves the string name of this address - * @return string name - */ - public String getName() - { - return name; - } - - /** - * Returns the namespace used by this address. - * - * @return non-null a namespace - */ - public Namespace getNamespace() { - return namespace; - } -} diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java deleted file mode 100644 index 6c36a7d..0000000 --- a/core/java/android/net/LocalSocketImpl.java +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.InputStream; -import java.io.FileDescriptor; -import java.net.SocketOptions; - -/** - * Socket implementation used for android.net.LocalSocket and - * android.net.LocalServerSocket. Supports only AF_LOCAL sockets. - */ -class LocalSocketImpl -{ - private SocketInputStream fis; - private SocketOutputStream fos; - private Object readMonitor = new Object(); - private Object writeMonitor = new Object(); - - /** null if closed or not yet created */ - private FileDescriptor fd; - - // These fields are accessed by native code; - /** file descriptor array received during a previous read */ - FileDescriptor[] inboundFileDescriptors; - /** file descriptor array that should be written during next write */ - FileDescriptor[] outboundFileDescriptors; - - /** - * An input stream for local sockets. Needed because we may - * need to read ancillary data. - */ - class SocketInputStream extends InputStream { - /** {@inheritDoc} */ - @Override - public int available() throws IOException { - return available_native(fd); - } - - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - LocalSocketImpl.this.close(); - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException { - int ret; - synchronized (readMonitor) { - FileDescriptor myFd = fd; - if (myFd == null) throw new IOException("socket closed"); - - ret = read_native(myFd); - return ret; - } - } - - /** {@inheritDoc} */ - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - /** {@inheritDoc} */ - @Override - public int read(byte[] b, int off, int len) throws IOException { - synchronized (readMonitor) { - FileDescriptor myFd = fd; - if (myFd == null) throw new IOException("socket closed"); - - if (off < 0 || len < 0 || (off + len) > b.length ) { - throw new ArrayIndexOutOfBoundsException(); - } - - int ret = readba_native(b, off, len, myFd); - - return ret; - } - } - } - - /** - * An output stream for local sockets. Needed because we may - * need to read ancillary data. - */ - class SocketOutputStream extends OutputStream { - /** {@inheritDoc} */ - @Override - public void close() throws IOException { - LocalSocketImpl.this.close(); - } - - /** {@inheritDoc} */ - @Override - public void write (byte[] b) throws IOException { - write(b, 0, b.length); - } - - /** {@inheritDoc} */ - @Override - public void write (byte[] b, int off, int len) throws IOException { - synchronized (writeMonitor) { - FileDescriptor myFd = fd; - if (myFd == null) throw new IOException("socket closed"); - - if (off < 0 || len < 0 || (off + len) > b.length ) { - throw new ArrayIndexOutOfBoundsException(); - } - writeba_native(b, off, len, myFd); - } - } - - /** {@inheritDoc} */ - @Override - public void write (int b) throws IOException { - synchronized (writeMonitor) { - FileDescriptor myFd = fd; - if (myFd == null) throw new IOException("socket closed"); - write_native(b, myFd); - } - } - } - - private native int available_native(FileDescriptor fd) throws IOException; - private native void close_native(FileDescriptor fd) throws IOException; - private native int read_native(FileDescriptor fd) throws IOException; - private native int readba_native(byte[] b, int off, int len, - FileDescriptor fd) throws IOException; - private native void writeba_native(byte[] b, int off, int len, - FileDescriptor fd) throws IOException; - private native void write_native(int b, FileDescriptor fd) - throws IOException; - private native void connectLocal(FileDescriptor fd, String name, - int namespace) throws IOException; - private native void bindLocal(FileDescriptor fd, String name, int namespace) - throws IOException; - private native FileDescriptor create_native(boolean stream) - throws IOException; - private native void listen_native(FileDescriptor fd, int backlog) - throws IOException; - private native void shutdown(FileDescriptor fd, boolean shutdownInput); - private native Credentials getPeerCredentials_native( - FileDescriptor fd) throws IOException; - private native int getOption_native(FileDescriptor fd, int optID) - throws IOException; - private native void setOption_native(FileDescriptor fd, int optID, - int b, int value) throws IOException; - -// private native LocalSocketAddress getSockName_native -// (FileDescriptor fd) throws IOException; - - /** - * Accepts a connection on a server socket. - * - * @param fd file descriptor of server socket - * @param s socket implementation that will become the new socket - * @return file descriptor of new socket - */ - private native FileDescriptor accept - (FileDescriptor fd, LocalSocketImpl s) throws IOException; - - /** - * Create a new instance. - */ - /*package*/ LocalSocketImpl() - { - } - - /** - * Create a new instance from a file descriptor representing - * a bound socket. The state of the file descriptor is not checked here - * but the caller can verify socket state by calling listen(). - * - * @param fd non-null; bound file descriptor - */ - /*package*/ LocalSocketImpl(FileDescriptor fd) throws IOException - { - this.fd = fd; - } - - public String toString() { - return super.toString() + " fd:" + fd; - } - - /** - * Creates a socket in the underlying OS. - * - * @param stream true if this should be a stream socket, false for - * datagram. - * @throws IOException - */ - public void create (boolean stream) throws IOException { - // no error if socket already created - // need this for LocalServerSocket.accept() - if (fd == null) { - fd = create_native(stream); - } - } - - /** - * Closes the socket. - * - * @throws IOException - */ - public void close() throws IOException { - synchronized (LocalSocketImpl.this) { - if (fd == null) return; - close_native(fd); - fd = null; - } - } - - /** note timeout presently ignored */ - protected void connect(LocalSocketAddress address, int timeout) - throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - connectLocal(fd, address.getName(), address.getNamespace().getId()); - } - - /** - * Binds this socket to an endpoint name. May only be called on an instance - * that has not yet been bound. - * - * @param endpoint endpoint address - * @throws IOException - */ - public void bind(LocalSocketAddress endpoint) throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - bindLocal(fd, endpoint.getName(), endpoint.getNamespace().getId()); - } - - protected void listen(int backlog) throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - listen_native(fd, backlog); - } - - /** - * Accepts a new connection to the socket. Blocks until a new - * connection arrives. - * - * @param s a socket that will be used to represent the new connection. - * @throws IOException - */ - protected void accept(LocalSocketImpl s) throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - s.fd = accept(fd, s); - } - - /** - * Retrieves the input stream for this instance. - * - * @return input stream - * @throws IOException if socket has been closed or cannot be created. - */ - protected InputStream getInputStream() throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - synchronized (this) { - if (fis == null) { - fis = new SocketInputStream(); - } - - return fis; - } - } - - /** - * Retrieves the output stream for this instance. - * - * @return output stream - * @throws IOException if socket has been closed or cannot be created. - */ - protected OutputStream getOutputStream() throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - synchronized (this) { - if (fos == null) { - fos = new SocketOutputStream(); - } - - return fos; - } - } - - /** - * Returns the number of bytes available for reading without blocking. - * - * @return >= 0 count bytes available - * @throws IOException - */ - protected int available() throws IOException - { - return getInputStream().available(); - } - - /** - * Shuts down the input side of the socket. - * - * @throws IOException - */ - protected void shutdownInput() throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - shutdown(fd, true); - } - - /** - * Shuts down the output side of the socket. - * - * @throws IOException - */ - protected void shutdownOutput() throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - shutdown(fd, false); - } - - protected FileDescriptor getFileDescriptor() - { - return fd; - } - - protected boolean supportsUrgentData() - { - return false; - } - - protected void sendUrgentData(int data) throws IOException - { - throw new RuntimeException ("not impled"); - } - - public Object getOption(int optID) throws IOException - { - if (fd == null) { - throw new IOException("socket not created"); - } - - if (optID == SocketOptions.SO_TIMEOUT) { - return 0; - } - - int value = getOption_native(fd, optID); - switch (optID) - { - case SocketOptions.SO_RCVBUF: - case SocketOptions.SO_SNDBUF: - return value; - case SocketOptions.SO_REUSEADDR: - default: - return value; - } - } - - public void setOption(int optID, Object value) - throws IOException { - /* - * Boolean.FALSE is used to disable some options, so it - * is important to distinguish between FALSE and unset. - * We define it here that -1 is unset, 0 is FALSE, and 1 - * is TRUE. - */ - int boolValue = -1; - int intValue = 0; - - if (fd == null) { - throw new IOException("socket not created"); - } - - if (value instanceof Integer) { - intValue = (Integer)value; - } else if (value instanceof Boolean) { - boolValue = ((Boolean) value)? 1 : 0; - } else { - throw new IOException("bad value: " + value); - } - - setOption_native(fd, optID, boolValue, intValue); - } - - /** - * Enqueues a set of file descriptors to send to the peer. The queue - * is one deep. The file descriptors will be sent with the next write - * of normal data, and will be delivered in a single ancillary message. - * See "man 7 unix" SCM_RIGHTS on a desktop Linux machine. - * - * @param fds non-null; file descriptors to send. - * @throws IOException - */ - public void setFileDescriptorsForSend(FileDescriptor[] fds) { - synchronized(writeMonitor) { - outboundFileDescriptors = fds; - } - } - - /** - * Retrieves a set of file descriptors that a peer has sent through - * an ancillary message. This method retrieves the most recent set sent, - * and then returns null until a new set arrives. - * File descriptors may only be passed along with regular data, so this - * method can only return a non-null after a read operation. - * - * @return null or file descriptor array - * @throws IOException - */ - public FileDescriptor[] getAncillaryFileDescriptors() throws IOException { - synchronized(readMonitor) { - FileDescriptor[] result = inboundFileDescriptors; - - inboundFileDescriptors = null; - return result; - } - } - - /** - * Retrieves the credentials of this socket's peer. Only valid on - * connected sockets. - * - * @return non-null; peer credentials - * @throws IOException - */ - public Credentials getPeerCredentials() throws IOException - { - return getPeerCredentials_native(fd); - } - - /** - * Retrieves the socket name from the OS. - * - * @return non-null; socket name - * @throws IOException on failure - */ - public LocalSocketAddress getSockAddress() throws IOException - { - return null; - //TODO implement this - //return getSockName_native(fd); - } - - @Override - protected void finalize() throws IOException { - close(); - } -} - diff --git a/core/java/android/net/MailTo.java b/core/java/android/net/MailTo.java deleted file mode 100644 index ca28f86..0000000 --- a/core/java/android/net/MailTo.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * - * MailTo URL parser - * - * This class parses a mailto scheme URL and then can be queried for - * the parsed parameters. This implements RFC 2368. - * - */ -public class MailTo { - - static public final String MAILTO_SCHEME = "mailto:"; - - // All the parsed content is added to the headers. - private HashMap<String, String> mHeaders; - - // Well known headers - static private final String TO = "to"; - static private final String BODY = "body"; - static private final String CC = "cc"; - static private final String SUBJECT = "subject"; - - - /** - * Test to see if the given string is a mailto URL - * @param url string to be tested - * @return true if the string is a mailto URL - */ - public static boolean isMailTo(String url) { - if (url != null && url.startsWith(MAILTO_SCHEME)) { - return true; - } - return false; - } - - /** - * Parse and decode a mailto scheme string. This parser implements - * RFC 2368. The returned object can be queried for the parsed parameters. - * @param url String containing a mailto URL - * @return MailTo object - * @exception ParseException if the scheme is not a mailto URL - */ - public static MailTo parse(String url) throws ParseException { - if (url == null) { - throw new NullPointerException(); - } - if (!isMailTo(url)) { - throw new ParseException("Not a mailto scheme"); - } - // Strip the scheme as the Uri parser can't cope with it. - String noScheme = url.substring(MAILTO_SCHEME.length()); - Uri email = Uri.parse(noScheme); - MailTo m = new MailTo(); - - // Parse out the query parameters - String query = email.getQuery(); - if (query != null ) { - String[] queries = query.split("&"); - for (String q : queries) { - String[] nameval = q.split("="); - if (nameval.length == 0) { - continue; - } - // insert the headers with the name in lowercase so that - // we can easily find common headers - m.mHeaders.put(Uri.decode(nameval[0]).toLowerCase(), - nameval.length > 1 ? Uri.decode(nameval[1]) : null); - } - } - - // Address can be specified in both the headers and just after the - // mailto line. Join the two together. - String address = email.getPath(); - if (address != null) { - String addr = m.getTo(); - if (addr != null) { - address += ", " + addr; - } - m.mHeaders.put(TO, address); - } - - return m; - } - - /** - * Retrieve the To address line from the parsed mailto URL. This could be - * several email address that are comma-space delimited. - * If no To line was specified, then null is return - * @return comma delimited email addresses or null - */ - public String getTo() { - return mHeaders.get(TO); - } - - /** - * Retrieve the CC address line from the parsed mailto URL. This could be - * several email address that are comma-space delimited. - * If no CC line was specified, then null is return - * @return comma delimited email addresses or null - */ - public String getCc() { - return mHeaders.get(CC); - } - - /** - * Retrieve the subject line from the parsed mailto URL. - * If no subject line was specified, then null is return - * @return subject or null - */ - public String getSubject() { - return mHeaders.get(SUBJECT); - } - - /** - * Retrieve the body line from the parsed mailto URL. - * If no body line was specified, then null is return - * @return body or null - */ - public String getBody() { - return mHeaders.get(BODY); - } - - /** - * Retrieve all the parsed email headers from the mailto URL - * @return map containing all parsed values - */ - public Map<String, String> getHeaders() { - return mHeaders; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(MAILTO_SCHEME); - sb.append('?'); - for (Map.Entry<String,String> header : mHeaders.entrySet()) { - sb.append(Uri.encode(header.getKey())); - sb.append('='); - sb.append(Uri.encode(header.getValue())); - sb.append('&'); - } - return sb.toString(); - } - - /** - * Private constructor. The only way to build a Mailto object is through - * the parse() method. - */ - private MailTo() { - mHeaders = new HashMap<String, String>(); - } -} diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java deleted file mode 100644 index 1d939e1..0000000 --- a/core/java/android/net/MobileDataStateTracker.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.RemoteException; -import android.os.Handler; -import android.os.ServiceManager; -import android.os.SystemProperties; -import com.android.internal.telephony.ITelephony; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.TelephonyIntents; -import android.net.NetworkInfo.DetailedState; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.text.TextUtils; - -import java.util.List; -import java.util.ArrayList; - -/** - * Track the state of mobile data connectivity. This is done by - * receiving broadcast intents from the Phone process whenever - * the state of data connectivity changes. - * - * {@hide} - */ -public class MobileDataStateTracker extends NetworkStateTracker { - - private static final String TAG = "MobileDataStateTracker"; - private static final boolean DBG = false; - - private Phone.DataState mMobileDataState; - private ITelephony mPhoneService; - private static final String[] sDnsPropNames = { - "net.rmnet0.dns1", - "net.rmnet0.dns2", - "net.eth0.dns1", - "net.eth0.dns2", - "net.eth0.dns3", - "net.eth0.dns4", - "net.gprs.dns1", - "net.gprs.dns2" - }; - private List<String> mDnsServers; - private String mInterfaceName; - private int mDefaultGatewayAddr; - private int mLastCallingPid = -1; - - /** - * Create a new MobileDataStateTracker - * @param context the application context of the caller - * @param target a message handler for getting callbacks about state changes - */ - public MobileDataStateTracker(Context context, Handler target) { - super(context, target, ConnectivityManager.TYPE_MOBILE, - TelephonyManager.getDefault().getNetworkType(), "MOBILE", - TelephonyManager.getDefault().getNetworkTypeName()); - mPhoneService = null; - mDnsServers = new ArrayList<String>(); - } - - /** - * Begin monitoring mobile data connectivity. - */ - public void startMonitoring() { - IntentFilter filter = - new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); - - Intent intent = mContext.registerReceiver(new MobileDataStateReceiver(), filter); - if (intent != null) - mMobileDataState = getMobileDataState(intent); - else - mMobileDataState = Phone.DataState.DISCONNECTED; - } - - private static Phone.DataState getMobileDataState(Intent intent) { - String str = intent.getStringExtra(Phone.STATE_KEY); - if (str != null) - return Enum.valueOf(Phone.DataState.class, str); - else - return Phone.DataState.DISCONNECTED; - } - - private class MobileDataStateReceiver extends BroadcastReceiver { - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { - Phone.DataState state = getMobileDataState(intent); - String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); - String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); - boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, false); - if (DBG) Log.d(TAG, "Received " + intent.getAction() + - " broadcast - state = " + state - + ", unavailable = " + unavailable - + ", reason = " + (reason == null ? "(unspecified)" : reason)); - mNetworkInfo.setIsAvailable(!unavailable); - if (mMobileDataState != state) { - mMobileDataState = state; - - switch (state) { - case DISCONNECTED: - setDetailedState(DetailedState.DISCONNECTED, reason, apnName); - if (mInterfaceName != null) { - NetworkUtils.resetConnections(mInterfaceName); - } - mInterfaceName = null; - mDefaultGatewayAddr = 0; - break; - case CONNECTING: - setDetailedState(DetailedState.CONNECTING, reason, apnName); - break; - case SUSPENDED: - setDetailedState(DetailedState.SUSPENDED, reason, apnName); - break; - case CONNECTED: - mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); - if (mInterfaceName == null) { - Log.d(TAG, "CONNECTED event did not supply interface name."); - } - setupDnsProperties(); - setDetailedState(DetailedState.CONNECTED, reason, apnName); - break; - } - } - } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { - String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY); - String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); - if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" + - reason == null ? "" : "(" + reason + ")"); - setDetailedState(DetailedState.FAILED, reason, apnName); - } - TelephonyManager tm = TelephonyManager.getDefault(); - setRoamingStatus(tm.isNetworkRoaming()); - setSubtype(tm.getNetworkType(), tm.getNetworkTypeName()); - } - } - - /** - * Make sure that route(s) exist to the carrier DNS server(s). - */ - public void addPrivateRoutes() { - if (mInterfaceName != null) { - for (String addrString : mDnsServers) { - int addr = NetworkUtils.lookupHost(addrString); - if (addr != -1) { - NetworkUtils.addHostRoute(mInterfaceName, addr); - } - } - } - } - - public void removePrivateRoutes() { - if(mInterfaceName != null) { - NetworkUtils.removeHostRoutes(mInterfaceName); - } - } - - public void removeDefaultRoute() { - if(mInterfaceName != null) { - mDefaultGatewayAddr = NetworkUtils.getDefaultRoute(mInterfaceName); - NetworkUtils.removeDefaultRoute(mInterfaceName); - } - } - - public void restoreDefaultRoute() { - // 0 is not a valid address for a gateway - if (mInterfaceName != null && mDefaultGatewayAddr != 0) { - NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr); - } - } - - private void getPhoneService(boolean forceRefresh) { - if ((mPhoneService == null) || forceRefresh) { - mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); - } - } - - /** - * Report whether data connectivity is possible. - */ - public boolean isAvailable() { - getPhoneService(false); - - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) break; - - try { - return mPhoneService.isDataConnectivityPossible(); - } catch (RemoteException e) { - // First-time failed, get the phone service again - if (retry == 0) getPhoneService(true); - } - } - - return false; - } - - /** - * Return the IP addresses of the DNS servers available for the mobile data - * network interface. - * @return a list of DNS addresses, with no holes. - */ - public String[] getNameServers() { - return getNameServerList(sDnsPropNames); - } - - /** - * {@inheritDoc} - * The mobile data network subtype indicates what generation network technology is in effect, - * e.g., GPRS, EDGE, UMTS, etc. - */ - public int getNetworkSubtype() { - return TelephonyManager.getDefault().getNetworkType(); - } - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName() { - String networkTypeStr = "unknown"; - TelephonyManager tm = new TelephonyManager(mContext); - switch(tm.getNetworkType()) { - case TelephonyManager.NETWORK_TYPE_GPRS: - networkTypeStr = "gprs"; - break; - case TelephonyManager.NETWORK_TYPE_EDGE: - networkTypeStr = "edge"; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - networkTypeStr = "umts"; - break; - } - return "net.tcp.buffersize." + networkTypeStr; - } - - /** - * Tear down mobile data connectivity, i.e., disable the ability to create - * mobile data connections. - */ - @Override - public boolean teardown() { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile data teardown request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.disableDataConnectivity(); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Failed to tear down mobile data connectivity"); - return false; - } - - /** - * Re-enable mobile data connectivity after a {@link #teardown()}. - */ - public boolean reconnect() { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile data connect request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.enableDataConnectivity(); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Failed to set up mobile data connectivity"); - return false; - } - - /** - * Turn on or off the mobile radio. No connectivity will be possible while the - * radio is off. The operation is a no-op if the radio is already in the desired state. - * @param turnOn {@code true} if the radio should be turned on, {@code false} if - */ - public boolean setRadio(boolean turnOn) { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile radio request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.setRadio(turnOn); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Could not set radio power to " + (turnOn ? "on" : "off")); - return false; - } - - /** - * Tells the phone sub-system that the caller wants to - * begin using the named feature. The only supported feature at - * this time is {@code Phone.FEATURE_ENABLE_MMS}, which allows an application - * to specify that it wants to send and/or receive MMS data. - * @param feature the name of the feature to be used - * @param callingPid the process ID of the process that is issuing this request - * @param callingUid the user ID of the process that is issuing this request - * @return an integer value representing the outcome of the request. - * The interpretation of this value is feature-specific. - * specific, except that the value {@code -1} - * always indicates failure. For {@code Phone.FEATURE_ENABLE_MMS}, - * the other possible return values are - * <ul> - * <li>{@code Phone.APN_ALREADY_ACTIVE}</li> - * <li>{@code Phone.APN_REQUEST_STARTED}</li> - * <li>{@code Phone.APN_TYPE_NOT_AVAILABLE}</li> - * <li>{@code Phone.APN_REQUEST_FAILED}</li> - * </ul> - */ - public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - mLastCallingPid = callingPid; - return setEnableApn(Phone.APN_TYPE_MMS, true); - } else { - return -1; - } - } - - /** - * Tells the phone sub-system that the caller is finished - * using the named feature. The only supported feature at - * this time is {@code Phone.FEATURE_ENABLE_MMS}, which allows an application - * to specify that it wants to send and/or receive MMS data. - * @param feature the name of the feature that is no longer needed - * @param callingPid the process ID of the process that is issuing this request - * @param callingUid the user ID of the process that is issuing this request - * @return an integer value representing the outcome of the request. - * The interpretation of this value is feature-specific, except that - * the value {@code -1} always indicates failure. - */ - public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - return setEnableApn(Phone.APN_TYPE_MMS, false); - } else { - return -1; - } - } - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the mobile data network. - * @param hostAddress the IP address of the host to which the route is desired, - * in network byte order. - * @return {@code true} on success, {@code false} on failure - */ - @Override - public boolean requestRouteToHost(int hostAddress) { - if (mInterfaceName != null && hostAddress != -1) { - if (DBG) { - Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress)); - } - return NetworkUtils.addHostRoute(mInterfaceName, hostAddress) == 0; - } else { - return false; - } - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer("Mobile data state: "); - - sb.append(mMobileDataState); - return sb.toString(); - } - - private void setupDnsProperties() { - mDnsServers.clear(); - // Set up per-process DNS server list on behalf of the MMS process - int i = 1; - if (mInterfaceName != null) { - for (String propName : sDnsPropNames) { - if (propName.indexOf(mInterfaceName) != -1) { - String propVal = SystemProperties.get(propName); - if (propVal != null && propVal.length() != 0 && !propVal.equals("0.0.0.0")) { - mDnsServers.add(propVal); - if (mLastCallingPid != -1) { - SystemProperties.set("net.dns" + i + "." + mLastCallingPid, propVal); - } - ++i; - } - } - } - } - if (i == 1) { - Log.d(TAG, "DNS server addresses are not known."); - } else if (mLastCallingPid != -1) { - /* - * Bump the property that tells the name resolver library - * to reread the DNS server list from the properties. - */ - String propVal = SystemProperties.get("net.dnschange"); - if (propVal.length() != 0) { - try { - int n = Integer.parseInt(propVal); - SystemProperties.set("net.dnschange", "" + (n+1)); - } catch (NumberFormatException e) { - } - } - } - mLastCallingPid = -1; - } - - /** - * Internal method supporting the ENABLE_MMS feature. - * @param apnType the type of APN to be enabled or disabled (e.g., mms) - * @param enable {@code true} to enable the specified APN type, - * {@code false} to disable it. - * @return an integer value representing the outcome of the request. - */ - private int setEnableApn(String apnType, boolean enable) { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring feature request because could not acquire PhoneService"); - break; - } - - try { - if (enable) { - return mPhoneService.enableApnType(apnType); - } else { - return mPhoneService.disableApnType(apnType); - } - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Could not " + (enable ? "enable" : "disable") - + " APN type \"" + apnType + "\""); - return Phone.APN_REQUEST_FAILED; - } -} diff --git a/core/java/android/net/NetworkConnectivityListener.java b/core/java/android/net/NetworkConnectivityListener.java deleted file mode 100644 index 858fc77..0000000 --- a/core/java/android/net/NetworkConnectivityListener.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.os.Message; -import android.util.Log; - -import java.util.HashMap; -import java.util.Iterator; - -/** - * A wrapper for a broadcast receiver that provides network connectivity - * state information, independent of network type (mobile, Wi-Fi, etc.). - * {@hide} - */ -public class NetworkConnectivityListener { - private static final String TAG = "NetworkConnectivityListener"; - private static final boolean DBG = false; - - private Context mContext; - private HashMap<Handler, Integer> mHandlers = new HashMap<Handler, Integer>(); - private State mState; - private boolean mListening; - private String mReason; - private boolean mIsFailover; - - /** Network connectivity information */ - private NetworkInfo mNetworkInfo; - - /** - * In case of a Disconnect, the connectivity manager may have - * already established, or may be attempting to establish, connectivity - * with another network. If so, {@code mOtherNetworkInfo} will be non-null. - */ - private NetworkInfo mOtherNetworkInfo; - - private ConnectivityBroadcastReceiver mReceiver; - - private class ConnectivityBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || - mListening == false) { - Log.w(TAG, "onReceived() called with " + mState.toString() + " and " + intent); - return; - } - - boolean noConnectivity = - intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - - if (noConnectivity) { - mState = State.NOT_CONNECTED; - } else { - mState = State.CONNECTED; - } - - mNetworkInfo = (NetworkInfo) - intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); - mOtherNetworkInfo = (NetworkInfo) - intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO); - - mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON); - mIsFailover = - intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false); - - if (DBG) { - Log.d(TAG, "onReceive(): mNetworkInfo=" + mNetworkInfo + " mOtherNetworkInfo = " - + (mOtherNetworkInfo == null ? "[none]" : mOtherNetworkInfo + - " noConn=" + noConnectivity) + " mState=" + mState.toString()); - } - - // Notifiy any handlers. - Iterator<Handler> it = mHandlers.keySet().iterator(); - while (it.hasNext()) { - Handler target = it.next(); - Message message = Message.obtain(target, mHandlers.get(target)); - target.sendMessage(message); - } - } - }; - - public enum State { - UNKNOWN, - - /** This state is returned if there is connectivity to any network **/ - CONNECTED, - /** - * This state is returned if there is no connectivity to any network. This is set - * to true under two circumstances: - * <ul> - * <li>When connectivity is lost to one network, and there is no other available - * network to attempt to switch to.</li> - * <li>When connectivity is lost to one network, and the attempt to switch to - * another network fails.</li> - */ - NOT_CONNECTED - } - - /** - * Create a new NetworkConnectivityListener. - */ - public NetworkConnectivityListener() { - mState = State.UNKNOWN; - mReceiver = new ConnectivityBroadcastReceiver(); - } - - /** - * This method starts listening for network connectivity state changes. - * @param context - */ - public synchronized void startListening(Context context) { - if (!mListening) { - mContext = context; - - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - context.registerReceiver(mReceiver, filter); - mListening = true; - } - } - - /** - * This method stops this class from listening for network changes. - */ - public synchronized void stopListening() { - if (mListening) { - mContext.unregisterReceiver(mReceiver); - mContext = null; - mNetworkInfo = null; - mOtherNetworkInfo = null; - mIsFailover = false; - mReason = null; - mListening = false; - } - } - - /** - * This methods registers a Handler to be called back onto with the specified what code when - * the network connectivity state changes. - * - * @param target The target handler. - * @param what The what code to be used when posting a message to the handler. - */ - public void registerHandler(Handler target, int what) { - mHandlers.put(target, what); - } - - /** - * This methods unregisters the specified Handler. - * @param target - */ - public void unregisterHandler(Handler target) { - mHandlers.remove(target); - } - - public State getState() { - return mState; - } - - /** - * Return the NetworkInfo associated with the most recent connectivity event. - * @return {@code NetworkInfo} for the network that had the most recent connectivity event. - */ - public NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - - /** - * If the most recent connectivity event was a DISCONNECT, return - * any information supplied in the broadcast about an alternate - * network that might be available. If this returns a non-null - * value, then another broadcast should follow shortly indicating - * whether connection to the other network succeeded. - * - * @return NetworkInfo - */ - public NetworkInfo getOtherNetworkInfo() { - return mOtherNetworkInfo; - } - - /** - * Returns true if the most recent event was for an attempt to switch over to - * a new network following loss of connectivity on another network. - * @return {@code true} if this was a failover attempt, {@code false} otherwise. - */ - public boolean isFailover() { - return mIsFailover; - } - - /** - * An optional reason for the connectivity state change may have been supplied. - * This returns it. - * @return the reason for the state change, if available, or {@code null} - * otherwise. - */ - public String getReason() { - return mReason; - } -} diff --git a/core/java/android/net/NetworkInfo.aidl b/core/java/android/net/NetworkInfo.aidl deleted file mode 100644 index f501873..0000000 --- a/core/java/android/net/NetworkInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable NetworkInfo; diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java deleted file mode 100644 index 8c82212..0000000 --- a/core/java/android/net/NetworkInfo.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcelable; -import android.os.Parcel; - -import java.util.EnumMap; - -/** - * Describes the status of a network interface of a given type - * (currently either Mobile or Wifi). - */ -public class NetworkInfo implements Parcelable { - - /** - * Coarse-grained network state. This is probably what most applications should - * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}. - * The mapping between the two is as follows: - * <br/><br/> - * <table> - * <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr> - * <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr> - * <tr><td><code>SCANNING</code></td><td><code>CONNECTING</code></td></tr> - * <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr> - * <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr> - * <tr><td><code>CONNECTED</code></td><td<code>CONNECTED</code></td></tr> - * <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr> - * <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr> - * <tr><td><code>UNAVAILABLE</code></td><td><code>DISCONNECTED</code></td></tr> - * <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr> - * </table> - */ - public enum State { - CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN - } - - /** - * The fine-grained state of a network connection. This level of detail - * is probably of interest to few applications. Most should use - * {@link android.net.NetworkInfo.State State} instead. - */ - public enum DetailedState { - /** Ready to start data connection setup. */ - IDLE, - /** Searching for an available access point. */ - SCANNING, - /** Currently setting up data connection. */ - CONNECTING, - /** Network link established, performing authentication. */ - AUTHENTICATING, - /** Awaiting response from DHCP server in order to assign IP address information. */ - OBTAINING_IPADDR, - /** IP traffic should be available. */ - CONNECTED, - /** IP traffic is suspended */ - SUSPENDED, - /** Currently tearing down data connection. */ - DISCONNECTING, - /** IP traffic not available. */ - DISCONNECTED, - /** Attempt to connect failed. */ - FAILED - } - - /** - * This is the map described in the Javadoc comment above. The positions - * of the elements of the array must correspond to the ordinal values - * of <code>DetailedState</code>. - */ - private static final EnumMap<DetailedState, State> stateMap = - new EnumMap<DetailedState, State>(DetailedState.class); - - static { - stateMap.put(DetailedState.IDLE, State.DISCONNECTED); - stateMap.put(DetailedState.SCANNING, State.DISCONNECTED); - stateMap.put(DetailedState.CONNECTING, State.CONNECTING); - stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING); - stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING); - stateMap.put(DetailedState.CONNECTED, State.CONNECTED); - stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED); - stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING); - stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); - stateMap.put(DetailedState.FAILED, State.DISCONNECTED); - } - - private int mNetworkType; - private int mSubtype; - private String mTypeName; - private String mSubtypeName; - private State mState; - private DetailedState mDetailedState; - private String mReason; - private String mExtraInfo; - private boolean mIsFailover; - private boolean mIsRoaming; - /** - * Indicates whether network connectivity is possible: - */ - private boolean mIsAvailable; - - /** - * TODO This is going away as soon as API council review happens. - * @param type network type - */ - public NetworkInfo(int type) {} - - NetworkInfo(int type, int subtype, String typeName, String subtypeName) { - if (!ConnectivityManager.isNetworkTypeValid(type)) { - throw new IllegalArgumentException("Invalid network type: " + type); - } - mNetworkType = type; - mSubtype = subtype; - mTypeName = typeName; - mSubtypeName = subtypeName; - setDetailedState(DetailedState.IDLE, null, null); - mState = State.UNKNOWN; - mIsAvailable = true; - mIsRoaming = false; - } - - /** - * Reports the type of network (currently mobile or Wi-Fi) to which the - * info in this object pertains. - * @return the network type - */ - public int getType() { - return mNetworkType; - } - - /** - * Return a network-type-specific integer describing the subtype - * of the network. - * @return the network subtype - * - * @hide pending API council review - */ - public int getSubtype() { - return mSubtype; - } - - void setSubtype(int subtype, String subtypeName) { - mSubtype = subtype; - mSubtypeName = subtypeName; - } - - /** - * Return a human-readable name describe the type of the network, - * for example "WIFI" or "MOBILE". - * @return the name of the network type - */ - public String getTypeName() { - return mTypeName; - } - - /** - * Return a human-readable name describing the subtype of the network. - * @return the name of the network subtype - * - * @hide pending API council review - */ - public String getSubtypeName() { - return mSubtypeName; - } - - /** - * Indicates whether network connectivity exists or is in the process - * of being established. This is good for applications that need to - * do anything related to the network other than read or write data. - * For the latter, call {@link #isConnected()} instead, which guarantees - * that the network is fully usable. - * @return {@code true} if network connectivity exists or is in the process - * of being established, {@code false} otherwise. - */ - public boolean isConnectedOrConnecting() { - return mState == State.CONNECTED || mState == State.CONNECTING; - } - - /** - * Indicates whether network connectivity exists and it is possible to establish - * connections and pass data. - * @return {@code true} if network connectivity exists, {@code false} otherwise. - */ - public boolean isConnected() { - return mState == State.CONNECTED; - } - - /** - * Indicates whether network connectivity is possible. A network is unavailable - * when a persistent or semi-persistent condition prevents the possibility - * of connecting to that network. Examples include - * <ul> - * <li>The device is out of the coverage area for any network of this type.</li> - * <li>The device is on a network other than the home network (i.e., roaming), and - * data roaming has been disabled.</li> - * <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li> - * </ul> - * @return {@code true} if the network is available, {@code false} otherwise - */ - public boolean isAvailable() { - return mIsAvailable; - } - - /** - * Sets if the network is available, ie, if the connectivity is possible. - * @param isAvailable the new availability value. - * - * @hide - */ - public void setIsAvailable(boolean isAvailable) { - mIsAvailable = isAvailable; - } - - /** - * Indicates whether the current attempt to connect to the network - * resulted from the ConnectivityManager trying to fail over to this - * network following a disconnect from another network. - * @return {@code true} if this is a failover attempt, {@code false} - * otherwise. - */ - public boolean isFailover() { - return mIsFailover; - } - - /** - * Set the failover boolean. - * @param isFailover {@code true} to mark the current connection attempt - * as a failover. - * @hide - */ - public void setFailover(boolean isFailover) { - mIsFailover = isFailover; - } - - /** - * Indicates whether the device is currently roaming on this network. - * When {@code true}, it suggests that use of data on this network - * may incur extra costs. - * @return {@code true} if roaming is in effect, {@code false} otherwise. - * - * @hide pending API council - */ - public boolean isRoaming() { - return mIsRoaming; - } - - void setRoaming(boolean isRoaming) { - mIsRoaming = isRoaming; - } - - /** - * Reports the current coarse-grained state of the network. - * @return the coarse-grained state - */ - public State getState() { - return mState; - } - - /** - * Reports the current fine-grained state of the network. - * @return the fine-grained state - */ - public DetailedState getDetailedState() { - return mDetailedState; - } - - /** - * Sets the fine-grained state of the network. - * @param detailedState the {@link DetailedState}. - * @param reason a {@code String} indicating the reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo an optional {@code String} providing addditional network state - * information passed up from the lower networking layers. - */ - void setDetailedState(DetailedState detailedState, String reason, String extraInfo) { - this.mDetailedState = detailedState; - this.mState = stateMap.get(detailedState); - this.mReason = reason; - this.mExtraInfo = extraInfo; - } - - /** - * Report the reason an attempt to establish connectivity failed, - * if one is available. - * @return the reason for failure, or null if not available - */ - public String getReason() { - return mReason; - } - - /** - * Report the extra information about the network state, if any was - * provided by the lower networking layers., - * if one is available. - * @return the extra information, or null if not available - */ - public String getExtraInfo() { - return mExtraInfo; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder("NetworkInfo: "); - builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()). - append("], state: ").append(mState).append("/").append(mDetailedState). - append(", reason: ").append(mReason == null ? "(unspecified)" : mReason). - append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). - append(", roaming: ").append(mIsRoaming). - append(", failover: ").append(mIsFailover). - append(", isAvailable: ").append(mIsAvailable); - return builder.toString(); - } - - /** - * Implement the Parcelable interface - * @hide - */ - public int describeContents() { - return 0; - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mNetworkType); - dest.writeInt(mSubtype); - dest.writeString(mTypeName); - dest.writeString(mSubtypeName); - dest.writeString(mState.name()); - dest.writeString(mDetailedState.name()); - dest.writeInt(mIsFailover ? 1 : 0); - dest.writeInt(mIsAvailable ? 1 : 0); - dest.writeInt(mIsRoaming ? 1 : 0); - dest.writeString(mReason); - dest.writeString(mExtraInfo); - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public static final Creator<NetworkInfo> CREATOR = - new Creator<NetworkInfo>() { - public NetworkInfo createFromParcel(Parcel in) { - int netType = in.readInt(); - int subtype = in.readInt(); - String typeName = in.readString(); - String subtypeName = in.readString(); - NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName); - netInfo.mState = State.valueOf(in.readString()); - netInfo.mDetailedState = DetailedState.valueOf(in.readString()); - netInfo.mIsFailover = in.readInt() != 0; - netInfo.mIsAvailable = in.readInt() != 0; - netInfo.mIsRoaming = in.readInt() != 0; - netInfo.mReason = in.readString(); - netInfo.mExtraInfo = in.readString(); - return netInfo; - } - - public NetworkInfo[] newArray(int size) { - return new NetworkInfo[size]; - } - }; -} diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java deleted file mode 100644 index 37087ac..0000000 --- a/core/java/android/net/NetworkStateTracker.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.io.FileWriter; -import java.io.IOException; - -import android.os.Handler; -import android.os.Message; -import android.os.SystemProperties; -import android.content.Context; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -/** - * Each subclass of this class keeps track of the state of connectivity - * of a network interface. All state information for a network should - * be kept in a Tracker class. This superclass manages the - * network-type-independent aspects of network state. - * - * {@hide} - */ -public abstract class NetworkStateTracker extends Handler { - - protected NetworkInfo mNetworkInfo; - protected Context mContext; - protected Handler mTarget; - private boolean mTeardownRequested; - - private static boolean DBG = Config.LOGV; - private static final String TAG = "NetworkStateTracker"; - - public static final int EVENT_STATE_CHANGED = 1; - public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2; - /** - * arg1: 1 to show, 0 to hide - * arg2: ID of the notification - * obj: Notification (if showing) - */ - public static final int EVENT_NOTIFICATION_CHANGED = 3; - public static final int EVENT_CONFIGURATION_CHANGED = 4; - public static final int EVENT_ROAMING_CHANGED = 5; - public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; - - public NetworkStateTracker(Context context, - Handler target, - int networkType, - int subType, - String typeName, - String subtypeName) { - super(); - mContext = context; - mTarget = target; - mTeardownRequested = false; - this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName); - } - - public NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - - /** - * Return the list of DNS servers associated with this network. - * @return a list of the IP addresses of the DNS servers available - * for the network. - */ - public abstract String[] getNameServers(); - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public abstract String getTcpBufferSizesPropName(); - - /** - * Return the IP addresses of the DNS servers available for this - * network interface. - * @param propertyNames the names of the system properties whose values - * give the IP addresses. Properties with no values are skipped. - * @return an array of {@code String}s containing the IP addresses - * of the DNS servers, in dot-notation. This may have fewer - * non-null entries than the list of names passed in, since - * some of the passed-in names may have empty values. - */ - static protected String[] getNameServerList(String[] propertyNames) { - String[] dnsAddresses = new String[propertyNames.length]; - int i, j; - - for (i = 0, j = 0; i < propertyNames.length; i++) { - String value = SystemProperties.get(propertyNames[i]); - // The GSM layer sometimes sets a bogus DNS server address of - // 0.0.0.0 - if (!TextUtils.isEmpty(value) && !TextUtils.equals(value, "0.0.0.0")) { - dnsAddresses[j++] = value; - } - } - return dnsAddresses; - } - - /** - * Reads the network specific TCP buffer sizes from SystemProperties - * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system - * wide use - */ - public void updateNetworkSettings() { - String key = getTcpBufferSizesPropName(); - String bufferSizes = SystemProperties.get(key); - - if (bufferSizes.length() == 0) { - Log.e(TAG, key + " not found in system properties. Using defaults"); - - // Setting to default values so we won't be stuck to previous values - key = "net.tcp.buffersize.default"; - bufferSizes = SystemProperties.get(key); - } - - // Set values in kernel - if (bufferSizes.length() != 0) { - if (DBG) { - Log.v(TAG, "Setting TCP values: [" + bufferSizes - + "] which comes from [" + key + "]"); - } - setBufferSize(bufferSizes); - } - } - - /** - * Release the wakelock, if any, that may be held while handling a - * disconnect operation. - */ - public void releaseWakeLock() { - } - - /** - * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max] - * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem - * - * @param bufferSizes in the format of "readMin, readInitial, readMax, - * writeMin, writeInitial, writeMax" - */ - private void setBufferSize(String bufferSizes) { - try { - String[] values = bufferSizes.split(","); - - if (values.length == 6) { - final String prefix = "/sys/kernel/ipv4/tcp_"; - stringToFile(prefix + "rmem_min", values[0]); - stringToFile(prefix + "rmem_def", values[1]); - stringToFile(prefix + "rmem_max", values[2]); - stringToFile(prefix + "wmem_min", values[3]); - stringToFile(prefix + "wmem_def", values[4]); - stringToFile(prefix + "wmem_max", values[5]); - } else { - Log.e(TAG, "Invalid buffersize string: " + bufferSizes); - } - } catch (IOException e) { - Log.e(TAG, "Can't set tcp buffer sizes:" + e); - } - } - - /** - * Writes string to file. Basically same as "echo -n $string > $filename" - * - * @param filename - * @param string - * @throws IOException - */ - private void stringToFile(String filename, String string) throws IOException { - FileWriter out = new FileWriter(filename); - try { - out.write(string); - } finally { - out.close(); - } - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new @{code DetailedState} - */ - public void setDetailedState(NetworkInfo.DetailedState state) { - setDetailedState(state, null, null); - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new @{code DetailedState} - * @param reason a {@code String} indicating a reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo optional {@code String} providing extra information about the state change - */ - public void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) { - if (state != mNetworkInfo.getDetailedState()) { - boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); - String lastReason = mNetworkInfo.getReason(); - /* - * If a reason was supplied when the CONNECTING state was entered, and no - * reason was supplied for entering the CONNECTED state, then retain the - * reason that was supplied when going to CONNECTING. - */ - if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null - && lastReason != null) - reason = lastReason; - mNetworkInfo.setDetailedState(state, reason, extraInfo); - Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); - msg.sendToTarget(); - } - } - - protected void setDetailedStateInternal(NetworkInfo.DetailedState state) { - mNetworkInfo.setDetailedState(state, null, null); - } - - public void setTeardownRequested(boolean isRequested) { - mTeardownRequested = isRequested; - } - - public boolean isTeardownRequested() { - return mTeardownRequested; - } - - /** - * Send a notification that the results of a scan for network access - * points has completed, and results are available. - */ - protected void sendScanResultsAvailable() { - Message msg = mTarget.obtainMessage(EVENT_SCAN_RESULTS_AVAILABLE, mNetworkInfo); - msg.sendToTarget(); - } - - /** - * Record the roaming status of the device, and if it is a change from the previous - * status, send a notification to any listeners. - * @param isRoaming {@code true} if the device is now roaming, {@code false} - * if it is no longer roaming. - */ - protected void setRoamingStatus(boolean isRoaming) { - if (isRoaming != mNetworkInfo.isRoaming()) { - mNetworkInfo.setRoaming(isRoaming); - Message msg = mTarget.obtainMessage(EVENT_ROAMING_CHANGED, mNetworkInfo); - msg.sendToTarget(); - } - } - - protected void setSubtype(int subtype, String subtypeName) { - if (mNetworkInfo.isConnected()) { - int oldSubtype = mNetworkInfo.getSubtype(); - if (subtype != oldSubtype) { - mNetworkInfo.setSubtype(subtype, subtypeName); - Message msg = mTarget.obtainMessage( - EVENT_NETWORK_SUBTYPE_CHANGED, oldSubtype, 0, mNetworkInfo); - msg.sendToTarget(); - } - } - } - - public abstract void startMonitoring(); - - /** - * Disable connectivity to a network - * @return {@code true} if a teardown occurred, {@code false} if the - * teardown did not occur. - */ - public abstract boolean teardown(); - - /** - * Reenable connectivity to a network after a {@link #teardown()}. - */ - public abstract boolean reconnect(); - - /** - * Turn the wireless radio off for a network. - * @param turnOn {@code true} to turn the radio on, {@code false} - */ - public abstract boolean setRadio(boolean turnOn); - - /** - * Returns an indication of whether this network is available for - * connections. A value of {@code false} means that some quasi-permanent - * condition prevents connectivity to this network. - */ - public abstract boolean isAvailable(); - - /** - * Tells the underlying networking system that the caller wants to - * begin using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - * @param feature the name of the feature to be used - * @param callingPid the process ID of the process that is issuing this request - * @param callingUid the user ID of the process that is issuing this request - * @return an integer value representing the outcome of the request. - * The interpretation of this value is specific to each networking - * implementation+feature combination, except that the value {@code -1} - * always indicates failure. - */ - public abstract int startUsingNetworkFeature(String feature, int callingPid, int callingUid); - - /** - * Tells the underlying networking system that the caller is finished - * using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - * @param feature the name of the feature that is no longer needed. - * @param callingPid the process ID of the process that is issuing this request - * @param callingUid the user ID of the process that is issuing this request - * @return an integer value representing the outcome of the request. - * The interpretation of this value is specific to each networking - * implementation+feature combination, except that the value {@code -1} - * always indicates failure. - */ - public abstract int stopUsingNetworkFeature(String feature, int callingPid, int callingUid); - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via this network interface. - * @param hostAddress the IP address of the host to which the route is desired - * @return {@code true} on success, {@code false} on failure - */ - public boolean requestRouteToHost(int hostAddress) { - return false; - } - - /** - * Interprets scan results. This will be called at a safe time for - * processing, and from a safe thread. - */ - public void interpretScanResultsAvailable() { - } - -} diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java deleted file mode 100644 index 1153648..0000000 --- a/core/java/android/net/NetworkUtils.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Native methods for managing network interfaces. - * - * {@hide} - */ -public class NetworkUtils { - /** Bring the named network interface down. */ - public native static int disableInterface(String interfaceName); - - /** Add a route to the specified host via the named interface. */ - public native static int addHostRoute(String interfaceName, int hostaddr); - - /** Add a default route for the named interface. */ - public native static int setDefaultRoute(String interfaceName, int gwayAddr); - - /** Return the gateway address for the default route for the named interface. */ - public native static int getDefaultRoute(String interfaceName); - - /** Remove host routes that uses the named interface. */ - public native static int removeHostRoutes(String interfaceName); - - /** Remove the default route for the named interface. */ - public native static int removeDefaultRoute(String interfaceName); - - /** Reset any sockets that are connected via the named interface. */ - public native static int resetConnections(String interfaceName); - - /** - * Start the DHCP client daemon, in order to have it request addresses - * for the named interface, and then configure the interface with those - * addresses. This call blocks until it obtains a result (either success - * or failure) from the daemon. - * @param interfaceName the name of the interface to configure - * @param ipInfo if the request succeeds, this object is filled in with - * the IP address information. - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean runDhcp(String interfaceName, DhcpInfo ipInfo); - - /** - * Shut down the DHCP client daemon. - * @param interfaceName the name of the interface for which the daemon - * should be stopped - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean stopDhcp(String interfaceName); - - /** - * Release the current DHCP lease. - * @param interfaceName the name of the interface for which the lease should - * be released - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean releaseDhcpLease(String interfaceName); - - /** - * Return the last DHCP-related error message that was recorded. - * <p/>NOTE: This string is not localized, but currently it is only - * used in logging. - * @return the most recent error message, if any - */ - public native static String getDhcpError(); - - /** - * When static IP configuration has been specified, configure the network - * interface according to the values supplied. - * @param interfaceName the name of the interface to configure - * @param ipInfo the IP address, default gateway, and DNS server addresses - * with which to configure the interface. - * @return {@code true} for success, {@code false} for failure - */ - public static boolean configureInterface(String interfaceName, DhcpInfo ipInfo) { - return configureNative(interfaceName, - ipInfo.ipAddress, - ipInfo.netmask, - ipInfo.gateway, - ipInfo.dns1, - ipInfo.dns2); - } - - private native static boolean configureNative( - String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2); - - /** - * Look up a host name and return the result as an int. Works if the argument - * is an IP address in dot notation. Obviously, this can only be used for IPv4 - * addresses. - * @param hostname the name of the host (or the IP address) - * @return the IP address as an {@code int} in network byte order - */ - public static int lookupHost(String hostname) { - InetAddress inetAddress; - try { - inetAddress = InetAddress.getByName(hostname); - } catch (UnknownHostException e) { - return -1; - } - byte[] addrBytes; - int addr; - addrBytes = inetAddress.getAddress(); - addr = ((addrBytes[3] & 0xff) << 24) - | ((addrBytes[2] & 0xff) << 16) - | ((addrBytes[1] & 0xff) << 8) - | (addrBytes[0] & 0xff); - return addr; - } -} diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java deleted file mode 100644 index 000fa68..0000000 --- a/core/java/android/net/ParseException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * - * - * When WebAddress Parser Fails, this exception is thrown - */ -public class ParseException extends RuntimeException { - public String response; - - ParseException(String response) { - this.response = response; - } -} diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java deleted file mode 100644 index 9f07c0a..0000000 --- a/core/java/android/net/Proxy.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.content.ContentResolver; -import android.content.Context; -import android.os.SystemProperties; -import android.provider.Settings; -import android.util.Log; - -import junit.framework.Assert; - -/** - * A convenience class for accessing the user and default proxy - * settings. - */ -final public class Proxy { - - static final public String PROXY_CHANGE_ACTION = - "android.intent.action.PROXY_CHANGE"; - - /** - * Return the proxy host set by the user. - * @param ctx A Context used to get the settings for the proxy host. - * @return String containing the host name. If the user did not set a host - * name it returns the default host. A null value means that no - * host is to be used. - */ - static final public String getHost(Context ctx) { - ContentResolver contentResolver = ctx.getContentResolver(); - Assert.assertNotNull(contentResolver); - String host = Settings.Secure.getString( - contentResolver, - Settings.Secure.HTTP_PROXY); - if (host != null) { - int i = host.indexOf(':'); - if (i == -1) { - if (android.util.Config.DEBUG) { - Assert.assertTrue(host.length() == 0); - } - return null; - } - return host.substring(0, i); - } - return getDefaultHost(); - } - - /** - * Return the proxy port set by the user. - * @param ctx A Context used to get the settings for the proxy port. - * @return The port number to use or -1 if no proxy is to be used. - */ - static final public int getPort(Context ctx) { - ContentResolver contentResolver = ctx.getContentResolver(); - Assert.assertNotNull(contentResolver); - String host = Settings.Secure.getString( - contentResolver, - Settings.Secure.HTTP_PROXY); - if (host != null) { - int i = host.indexOf(':'); - if (i == -1) { - if (android.util.Config.DEBUG) { - Assert.assertTrue(host.length() == 0); - } - return -1; - } - if (android.util.Config.DEBUG) { - Assert.assertTrue(i < host.length()); - } - return Integer.parseInt(host.substring(i+1)); - } - return getDefaultPort(); - } - - /** - * Return the default proxy host specified by the carrier. - * @return String containing the host name or null if there is no proxy for - * this carrier. - */ - static final public String getDefaultHost() { - String host = SystemProperties.get("net.gprs.http-proxy"); - if (host != null) { - Uri u = Uri.parse(host); - host = u.getHost(); - return host; - } else { - return null; - } - } - - /** - * Return the default proxy port specified by the carrier. - * @return The port number to be used with the proxy host or -1 if there is - * no proxy for this carrier. - */ - static final public int getDefaultPort() { - String host = SystemProperties.get("net.gprs.http-proxy"); - if (host != null) { - Uri u = Uri.parse(host); - return u.getPort(); - } else { - return -1; - } - } - -}; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java deleted file mode 100644 index f816caa..0000000 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.util.Log; -import android.util.Config; -import android.net.http.DomainNameChecker; -import android.os.SystemProperties; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.security.NoSuchAlgorithmException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.GeneralSecurityException; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; - -public class SSLCertificateSocketFactory extends SSLSocketFactory { - - private static final boolean DBG = true; - private static final String LOG_TAG = "SSLCertificateSocketFactory"; - - private static X509TrustManager sDefaultTrustManager; - - private final int socketReadTimeoutForSslHandshake; - - static { - try { - TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); - tmf.init((KeyStore)null); - TrustManager[] tms = tmf.getTrustManagers(); - if (tms != null) { - for (TrustManager tm : tms) { - if (tm instanceof X509TrustManager) { - sDefaultTrustManager = (X509TrustManager)tm; - break; - } - } - } - } catch (NoSuchAlgorithmException e) { - Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e); - } catch (KeyStoreException e) { - Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e); - } - } - - private static final TrustManager[] TRUST_MANAGER = new TrustManager[] { - new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] certs, - String authType) { } - - public void checkServerTrusted(X509Certificate[] certs, - String authType) { } - } - }; - - private SSLSocketFactory factory; - - public SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake) - throws NoSuchAlgorithmException, KeyManagementException { - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, TRUST_MANAGER, new java.security.SecureRandom()); - factory = (SSLSocketFactory) context.getSocketFactory(); - this.socketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake; - } - - /** - * Returns a default instantiation of a new socket factory which - * only allows SSL connections with valid certificates. - * - * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing - * ssl handshake. The socket read timeout is set back to 0 after the handshake. - * @return a new SocketFactory, or null on error - */ - public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake) { - try { - return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake); - } catch (NoSuchAlgorithmException e) { - Log.e(LOG_TAG, - "SSLCertifcateSocketFactory.getDefault" + - " NoSuchAlgorithmException " , e); - return null; - } catch (KeyManagementException e) { - Log.e(LOG_TAG, - "SSLCertifcateSocketFactory.getDefault" + - " KeyManagementException " , e); - return null; - } - } - - private boolean hasValidCertificateChain(Certificate[] certs) - throws IOException { - if (sDefaultTrustManager == null) { - if (Config.LOGD) { - Log.d(LOG_TAG,"hasValidCertificateChain():" + - " null default trust manager!"); - } - throw new IOException("null default trust manager"); - } - - boolean trusted = (certs != null && (certs.length > 0)); - - if (trusted) { - try { - // the authtype we pass in doesn't actually matter - sDefaultTrustManager.checkServerTrusted((X509Certificate[]) certs, "RSA"); - } catch (GeneralSecurityException e) { - String exceptionMessage = e != null ? e.getMessage() : "none"; - if (Config.LOGD) { - Log.d(LOG_TAG,"hasValidCertificateChain(): sec. exception: " - + exceptionMessage); - } - trusted = false; - } - } - - return trusted; - } - - private void validateSocket(SSLSocket sslSock, String destHost) - throws IOException - { - if (Config.LOGV) { - Log.v(LOG_TAG,"validateSocket() to host "+destHost); - } - - String relaxSslCheck = SystemProperties.get("socket.relaxsslcheck"); - String secure = SystemProperties.get("ro.secure"); - - // only allow relaxing the ssl check on non-secure builds where the relaxation is - // specifically requested. - if ("0".equals(secure) && "yes".equals(relaxSslCheck)) { - if (Config.LOGD) { - Log.d(LOG_TAG,"sys prop socket.relaxsslcheck is set," + - " ignoring invalid certs"); - } - return; - } - - Certificate[] certs = null; - sslSock.setUseClientMode(true); - sslSock.startHandshake(); - certs = sslSock.getSession().getPeerCertificates(); - - // check that the root certificate in the chain belongs to - // a CA we trust - if (certs == null) { - Log.e(LOG_TAG, - "[SSLCertificateSocketFactory] no trusted root CA"); - throw new IOException("no trusted root CA"); - } - - if (Config.LOGV) { - Log.v(LOG_TAG,"validateSocket # certs = " +certs.length); - } - - if (!hasValidCertificateChain(certs)) { - if (Config.LOGD) { - Log.d(LOG_TAG,"validateSocket(): certificate untrusted!"); - } - throw new IOException("Certificate untrusted"); - } - - X509Certificate lastChainCert = (X509Certificate) certs[0]; - - if (!DomainNameChecker.match(lastChainCert, destHost)) { - if (Config.LOGD) { - Log.d(LOG_TAG,"validateSocket(): domain name check failed"); - } - throw new IOException("Domain Name check failed"); - } - } - - public Socket createSocket(Socket socket, String s, int i, boolean flag) - throws IOException - { - throw new IOException("Cannot validate certification without a hostname"); - } - - public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr2, int j) - throws IOException - { - throw new IOException("Cannot validate certification without a hostname"); - } - - public Socket createSocket(InetAddress inaddr, int i) throws IOException { - throw new IOException("Cannot validate certification without a hostname"); - } - - public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException { - SSLSocket sslSock = (SSLSocket) factory.createSocket(s, i, inaddr, j); - - if (socketReadTimeoutForSslHandshake >= 0) { - sslSock.setSoTimeout(socketReadTimeoutForSslHandshake); - } - - validateSocket(sslSock,s); - sslSock.setSoTimeout(0); - - return sslSock; - } - - public Socket createSocket(String s, int i) throws IOException { - SSLSocket sslSock = (SSLSocket) factory.createSocket(s, i); - - if (socketReadTimeoutForSslHandshake >= 0) { - sslSock.setSoTimeout(socketReadTimeoutForSslHandshake); - } - - validateSocket(sslSock,s); - sslSock.setSoTimeout(0); - - return sslSock; - } - - public String[] getDefaultCipherSuites() { - return factory.getSupportedCipherSuites(); - } - - public String[] getSupportedCipherSuites() { - return factory.getSupportedCipherSuites(); - } -} - - diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java deleted file mode 100644 index 28134b2..0000000 --- a/core/java/android/net/SntpClient.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.SystemClock; -import android.util.Config; -import android.util.Log; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; - -/** - * {@hide} - * - * Simple SNTP client class for retrieving network time. - * - * Sample usage: - * <pre>SntpClient client = new SntpClient(); - * if (client.requestTime("time.foo.com")) { - * long now = client.getNtpTime() + SystemClock.elapsedRealtime() - client.getNtpTimeReference(); - * } - * </pre> - */ -public class SntpClient -{ - private static final String TAG = "SntpClient"; - - private static final int REFERENCE_TIME_OFFSET = 16; - private static final int ORIGINATE_TIME_OFFSET = 24; - private static final int RECEIVE_TIME_OFFSET = 32; - private static final int TRANSMIT_TIME_OFFSET = 40; - private static final int NTP_PACKET_SIZE = 48; - - private static final int NTP_PORT = 123; - private static final int NTP_MODE_CLIENT = 3; - private static final int NTP_VERSION = 3; - - // Number of seconds between Jan 1, 1900 and Jan 1, 1970 - // 70 years plus 17 leap days - private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L; - - // system time computed from NTP server response - private long mNtpTime; - - // value of SystemClock.elapsedRealtime() corresponding to mNtpTime - private long mNtpTimeReference; - - // round trip time in milliseconds - private long mRoundTripTime; - - /** - * Sends an SNTP request to the given host and processes the response. - * - * @param host host name of the server. - * @param timeout network timeout in milliseconds. - * @return true if the transaction was successful. - */ - public boolean requestTime(String host, int timeout) { - try { - DatagramSocket socket = new DatagramSocket(); - socket.setSoTimeout(timeout); - InetAddress address = InetAddress.getByName(host); - byte[] buffer = new byte[NTP_PACKET_SIZE]; - DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT); - - // set mode = 3 (client) and version = 3 - // mode is in low 3 bits of first byte - // version is in bits 3-5 of first byte - buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3); - - // get current time and write it to the request packet - long requestTime = System.currentTimeMillis(); - long requestTicks = SystemClock.elapsedRealtime(); - writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime); - - socket.send(request); - - // read the response - DatagramPacket response = new DatagramPacket(buffer, buffer.length); - socket.receive(response); - long responseTicks = SystemClock.elapsedRealtime(); - long responseTime = requestTime + (responseTicks - requestTicks); - socket.close(); - - // extract the results - long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET); - long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET); - long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET); - long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime); - long clockOffset = (receiveTime - originateTime) + (transmitTime - responseTime); - if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime + " ms"); - if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset + " ms"); - - // save our results - mNtpTime = requestTime + clockOffset; - mNtpTimeReference = requestTicks; - mRoundTripTime = roundTripTime; - } catch (Exception e) { - if (Config.LOGD) Log.d(TAG, "request time failed: " + e); - return false; - } - - return true; - } - - /** - * Returns the time computed from the NTP transaction. - * - * @return time value computed from NTP server response. - */ - public long getNtpTime() { - return mNtpTime; - } - - /** - * Returns the reference clock value (value of SystemClock.elapsedRealtime()) - * corresponding to the NTP time. - * - * @return reference clock corresponding to the NTP time. - */ - public long getNtpTimeReference() { - return mNtpTimeReference; - } - - /** - * Returns the round trip time of the NTP transaction - * - * @return round trip time in milliseconds. - */ - public long getRoundTripTime() { - return mRoundTripTime; - } - - /** - * Reads an unsigned 32 bit big endian number from the given offset in the buffer. - */ - private long read32(byte[] buffer, int offset) { - byte b0 = buffer[offset]; - byte b1 = buffer[offset+1]; - byte b2 = buffer[offset+2]; - byte b3 = buffer[offset+3]; - - // convert signed bytes to unsigned values - int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0); - int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1); - int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2); - int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3); - - return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3; - } - - /** - * Reads the NTP time stamp at the given offset in the buffer and returns - * it as a system time (milliseconds since January 1, 1970). - */ - private long readTimeStamp(byte[] buffer, int offset) { - long seconds = read32(buffer, offset); - long fraction = read32(buffer, offset + 4); - return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L); - } - - /** - * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp - * at the given offset in the buffer. - */ - private void writeTimeStamp(byte[] buffer, int offset, long time) { - long seconds = time / 1000L; - long milliseconds = time - seconds * 1000L; - seconds += OFFSET_1900_TO_1970; - - // write seconds in big endian format - buffer[offset++] = (byte)(seconds >> 24); - buffer[offset++] = (byte)(seconds >> 16); - buffer[offset++] = (byte)(seconds >> 8); - buffer[offset++] = (byte)(seconds >> 0); - - long fraction = milliseconds * 0x100000000L / 1000L; - // write fraction in big endian format - buffer[offset++] = (byte)(fraction >> 24); - buffer[offset++] = (byte)(fraction >> 16); - buffer[offset++] = (byte)(fraction >> 8); - // low order bits should be random data - buffer[offset++] = (byte)(Math.random() * 255.0); - } -} diff --git a/core/java/android/net/Uri.aidl b/core/java/android/net/Uri.aidl deleted file mode 100755 index 6bd3be5..0000000 --- a/core/java/android/net/Uri.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable Uri; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java deleted file mode 100644 index c23df21..0000000 --- a/core/java/android/net/Uri.java +++ /dev/null @@ -1,2252 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.io.ByteArrayOutputStream; -import java.net.URLEncoder; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.RandomAccess; - -/** - * Immutable URI reference. A URI reference includes a URI and a fragment, the - * component of the URI following a '#'. Builds and parses URI references - * which conform to - * <a href="http://www.faqs.org/rfcs/rfc2396.html">RFC 2396</a>. - * - * <p>In the interest of performance, this class performs little to no - * validation. Behavior is undefined for invalid input. This class is very - * forgiving--in the face of invalid input, it will return garbage - * rather than throw an exception unless otherwise specified. - */ -public abstract class Uri implements Parcelable, Comparable<Uri> { - - /* - - This class aims to do as little up front work as possible. To accomplish - that, we vary the implementation dependending on what the user passes in. - For example, we have one implementation if the user passes in a - URI string (StringUri) and another if the user passes in the - individual components (OpaqueUri). - - *Concurrency notes*: Like any truly immutable object, this class is safe - for concurrent use. This class uses a caching pattern in some places where - it doesn't use volatile or synchronized. This is safe to do with ints - because getting or setting an int is atomic. It's safe to do with a String - because the internal fields are final and the memory model guarantees other - threads won't see a partially initialized instance. We are not guaranteed - that some threads will immediately see changes from other threads on - certain platforms, but we don't mind if those threads reconstruct the - cached result. As a result, we get thread safe caching with no concurrency - overhead, which means the most common case, access from a single thread, - is as fast as possible. - - From the Java Language spec.: - - "17.5 Final Field Semantics - - ... when the object is seen by another thread, that thread will always - see the correctly constructed version of that object's final fields. - It will also see versions of any object or array referenced by - those final fields that are at least as up-to-date as the final fields - are." - - In that same vein, all non-transient fields within Uri - implementations should be final and immutable so as to ensure true - immutability for clients even when they don't use proper concurrency - control. - - For reference, from RFC 2396: - - "4.3. Parsing a URI Reference - - A URI reference is typically parsed according to the four main - components and fragment identifier in order to determine what - components are present and whether the reference is relative or - absolute. The individual components are then parsed for their - subparts and, if not opaque, to verify their validity. - - Although the BNF defines what is allowed in each component, it is - ambiguous in terms of differentiating between an authority component - and a path component that begins with two slash characters. The - greedy algorithm is used for disambiguation: the left-most matching - rule soaks up as much of the URI reference string as it is capable of - matching. In other words, the authority component wins." - - The "four main components" of a hierarchical URI consist of - <scheme>://<authority><path>?<query> - - */ - - /** Log tag. */ - private static final String LOG = Uri.class.getSimpleName(); - - /** - * The empty URI, equivalent to "". - */ - public static final Uri EMPTY = new HierarchicalUri(null, Part.NULL, - PathPart.EMPTY, Part.NULL, Part.NULL); - - /** - * Prevents external subclassing. - */ - private Uri() {} - - /** - * Returns true if this URI is hierarchical like "http://google.com". - * Absolute URIs are hierarchical if the scheme-specific part starts with - * a '/'. Relative URIs are always hierarchical. - */ - public abstract boolean isHierarchical(); - - /** - * Returns true if this URI is opaque like "mailto:nobody@google.com". The - * scheme-specific part of an opaque URI cannot start with a '/'. - */ - public boolean isOpaque() { - return !isHierarchical(); - } - - /** - * Returns true if this URI is relative, i.e. if it doesn't contain an - * explicit scheme. - * - * @return true if this URI is relative, false if it's absolute - */ - public abstract boolean isRelative(); - - /** - * Returns true if this URI is absolute, i.e. if it contains an - * explicit scheme. - * - * @return true if this URI is absolute, false if it's relative - */ - public boolean isAbsolute() { - return !isRelative(); - } - - /** - * Gets the scheme of this URI. Example: "http" - * - * @return the scheme or null if this is a relative URI - */ - public abstract String getScheme(); - - /** - * Gets the scheme-specific part of this URI, i.e. everything between the - * scheme separator ':' and the fragment separator '#'. If this is a - * relative URI, this method returns the entire URI. Decodes escaped octets. - * - * <p>Example: "//www.google.com/search?q=android" - * - * @return the decoded scheme-specific-part - */ - public abstract String getSchemeSpecificPart(); - - /** - * Gets the scheme-specific part of this URI, i.e. everything between the - * scheme separator ':' and the fragment separator '#'. If this is a - * relative URI, this method returns the entire URI. Leaves escaped octets - * intact. - * - * <p>Example: "//www.google.com/search?q=android" - * - * @return the decoded scheme-specific-part - */ - public abstract String getEncodedSchemeSpecificPart(); - - /** - * Gets the decoded authority part of this URI. For - * server addresses, the authority is structured as follows: - * {@code [ userinfo '@' ] host [ ':' port ]} - * - * <p>Examples: "google.com", "bob@google.com:80" - * - * @return the authority for this URI or null if not present - */ - public abstract String getAuthority(); - - /** - * Gets the encoded authority part of this URI. For - * server addresses, the authority is structured as follows: - * {@code [ userinfo '@' ] host [ ':' port ]} - * - * <p>Examples: "google.com", "bob@google.com:80" - * - * @return the authority for this URI or null if not present - */ - public abstract String getEncodedAuthority(); - - /** - * Gets the decoded user information from the authority. - * For example, if the authority is "nobody@google.com", this method will - * return "nobody". - * - * @return the user info for this URI or null if not present - */ - public abstract String getUserInfo(); - - /** - * Gets the encoded user information from the authority. - * For example, if the authority is "nobody@google.com", this method will - * return "nobody". - * - * @return the user info for this URI or null if not present - */ - public abstract String getEncodedUserInfo(); - - /** - * Gets the encoded host from the authority for this URI. For example, - * if the authority is "bob@google.com", this method will return - * "google.com". - * - * @return the host for this URI or null if not present - */ - public abstract String getHost(); - - /** - * Gets the port from the authority for this URI. For example, - * if the authority is "google.com:80", this method will return 80. - * - * @return the port for this URI or -1 if invalid or not present - */ - public abstract int getPort(); - - /** - * Gets the decoded path. - * - * @return the decoded path, or null if this is not a hierarchical URI - * (like "mailto:nobody@google.com") or the URI is invalid - */ - public abstract String getPath(); - - /** - * Gets the encoded path. - * - * @return the encoded path, or null if this is not a hierarchical URI - * (like "mailto:nobody@google.com") or the URI is invalid - */ - public abstract String getEncodedPath(); - - /** - * Gets the decoded query component from this URI. The query comes after - * the query separator ('?') and before the fragment separator ('#'). This - * method would return "q=android" for - * "http://www.google.com/search?q=android". - * - * @return the decoded query or null if there isn't one - */ - public abstract String getQuery(); - - /** - * Gets the encoded query component from this URI. The query comes after - * the query separator ('?') and before the fragment separator ('#'). This - * method would return "q=android" for - * "http://www.google.com/search?q=android". - * - * @return the encoded query or null if there isn't one - */ - public abstract String getEncodedQuery(); - - /** - * Gets the decoded fragment part of this URI, everything after the '#'. - * - * @return the decoded fragment or null if there isn't one - */ - public abstract String getFragment(); - - /** - * Gets the encoded fragment part of this URI, everything after the '#'. - * - * @return the encoded fragment or null if there isn't one - */ - public abstract String getEncodedFragment(); - - /** - * Gets the decoded path segments. - * - * @return decoded path segments, each without a leading or trailing '/' - */ - public abstract List<String> getPathSegments(); - - /** - * Gets the decoded last segment in the path. - * - * @return the decoded last segment or null if the path is empty - */ - public abstract String getLastPathSegment(); - - /** - * Compares this Uri to another object for equality. Returns true if the - * encoded string representations of this Uri and the given Uri are - * equal. Case counts. Paths are not normalized. If one Uri specifies a - * default port explicitly and the other leaves it implicit, they will not - * be considered equal. - */ - public boolean equals(Object o) { - if (!(o instanceof Uri)) { - return false; - } - - Uri other = (Uri) o; - - return toString().equals(other.toString()); - } - - /** - * Hashes the encoded string represention of this Uri consistently with - * {@link #equals(Object)}. - */ - public int hashCode() { - return toString().hashCode(); - } - - /** - * Compares the string representation of this Uri with that of - * another. - */ - public int compareTo(Uri other) { - return toString().compareTo(other.toString()); - } - - /** - * Returns the encoded string representation of this URI. - * Example: "http://google.com/" - */ - public abstract String toString(); - - /** - * Constructs a new builder, copying the attributes from this Uri. - */ - public abstract Builder buildUpon(); - - /** Index of a component which was not found. */ - private final static int NOT_FOUND = -1; - - /** Placeholder value for an index which hasn't been calculated yet. */ - private final static int NOT_CALCULATED = -2; - - /** - * Placeholder for strings which haven't been cached. This enables us - * to cache null. We intentionally create a new String instance so we can - * compare its identity and there is no chance we will confuse it with - * user data. - */ - @SuppressWarnings("RedundantStringConstructorCall") - private static final String NOT_CACHED = new String("NOT CACHED"); - - /** - * Error message presented when a user tries to treat an opaque URI as - * hierarchical. - */ - private static final String NOT_HIERARCHICAL - = "This isn't a hierarchical URI."; - - /** Default encoding. */ - private static final String DEFAULT_ENCODING = "UTF-8"; - - /** - * Creates a Uri which parses the given encoded URI string. - * - * @param uriString an RFC 3296-compliant, encoded URI - * @throws NullPointerException if uriString is null - * @return Uri for this given uri string - */ - public static Uri parse(String uriString) { - return new StringUri(uriString); - } - - /** - * Creates a Uri from a file. The URI has the form - * "file://<absolute path>". Encodes path characters with the exception of - * '/'. - * - * <p>Example: "file:///tmp/android.txt" - * - * @throws NullPointerException if file is null - * @return a Uri for the given file - */ - public static Uri fromFile(File file) { - if (file == null) { - throw new NullPointerException("file"); - } - - PathPart path = PathPart.fromDecoded(file.getAbsolutePath()); - return new HierarchicalUri( - "file", Part.EMPTY, path, Part.NULL, Part.NULL); - } - - /** - * An implementation which wraps a String URI. This URI can be opaque or - * hierarchical, but we extend AbstractHierarchicalUri in case we need - * the hierarchical functionality. - */ - private static class StringUri extends AbstractHierarchicalUri { - - /** Used in parcelling. */ - static final int TYPE_ID = 1; - - /** URI string representation. */ - private final String uriString; - - private StringUri(String uriString) { - if (uriString == null) { - throw new NullPointerException("uriString"); - } - - this.uriString = uriString; - } - - static Uri readFrom(Parcel parcel) { - return new StringUri(parcel.readString()); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(TYPE_ID); - parcel.writeString(uriString); - } - - /** Cached scheme separator index. */ - private volatile int cachedSsi = NOT_CALCULATED; - - /** Finds the first ':'. Returns -1 if none found. */ - private int findSchemeSeparator() { - return cachedSsi == NOT_CALCULATED - ? cachedSsi = uriString.indexOf(':') - : cachedSsi; - } - - /** Cached fragment separator index. */ - private volatile int cachedFsi = NOT_CALCULATED; - - /** Finds the first '#'. Returns -1 if none found. */ - private int findFragmentSeparator() { - return cachedFsi == NOT_CALCULATED - ? cachedFsi = uriString.indexOf('#', findSchemeSeparator()) - : cachedFsi; - } - - public boolean isHierarchical() { - int ssi = findSchemeSeparator(); - - if (ssi == NOT_FOUND) { - // All relative URIs are hierarchical. - return true; - } - - if (uriString.length() == ssi + 1) { - // No ssp. - return false; - } - - // If the ssp starts with a '/', this is hierarchical. - return uriString.charAt(ssi + 1) == '/'; - } - - public boolean isRelative() { - // Note: We return true if the index is 0 - return findSchemeSeparator() == NOT_FOUND; - } - - private volatile String scheme = NOT_CACHED; - - public String getScheme() { - @SuppressWarnings("StringEquality") - boolean cached = (scheme != NOT_CACHED); - return cached ? scheme : (scheme = parseScheme()); - } - - private String parseScheme() { - int ssi = findSchemeSeparator(); - return ssi == NOT_FOUND ? null : uriString.substring(0, ssi); - } - - private Part ssp; - - private Part getSsp() { - return ssp == null ? ssp = Part.fromEncoded(parseSsp()) : ssp; - } - - public String getEncodedSchemeSpecificPart() { - return getSsp().getEncoded(); - } - - public String getSchemeSpecificPart() { - return getSsp().getDecoded(); - } - - private String parseSsp() { - int ssi = findSchemeSeparator(); - int fsi = findFragmentSeparator(); - - // Return everything between ssi and fsi. - return fsi == NOT_FOUND - ? uriString.substring(ssi + 1) - : uriString.substring(ssi + 1, fsi); - } - - private Part authority; - - private Part getAuthorityPart() { - if (authority == null) { - String encodedAuthority - = parseAuthority(this.uriString, findSchemeSeparator()); - return authority = Part.fromEncoded(encodedAuthority); - } - - return authority; - } - - public String getEncodedAuthority() { - return getAuthorityPart().getEncoded(); - } - - public String getAuthority() { - return getAuthorityPart().getDecoded(); - } - - private PathPart path; - - private PathPart getPathPart() { - return path == null - ? path = PathPart.fromEncoded(parsePath()) - : path; - } - - public String getPath() { - return getPathPart().getDecoded(); - } - - public String getEncodedPath() { - return getPathPart().getEncoded(); - } - - public List<String> getPathSegments() { - return getPathPart().getPathSegments(); - } - - private String parsePath() { - String uriString = this.uriString; - int ssi = findSchemeSeparator(); - - // If the URI is absolute. - if (ssi > -1) { - // Is there anything after the ':'? - boolean schemeOnly = ssi + 1 == uriString.length(); - if (schemeOnly) { - // Opaque URI. - return null; - } - - // A '/' after the ':' means this is hierarchical. - if (uriString.charAt(ssi + 1) != '/') { - // Opaque URI. - return null; - } - } else { - // All relative URIs are hierarchical. - } - - return parsePath(uriString, ssi); - } - - private Part query; - - private Part getQueryPart() { - return query == null - ? query = Part.fromEncoded(parseQuery()) : query; - } - - public String getEncodedQuery() { - return getQueryPart().getEncoded(); - } - - private String parseQuery() { - // It doesn't make sense to cache this index. We only ever - // calculate it once. - int qsi = uriString.indexOf('?', findSchemeSeparator()); - if (qsi == NOT_FOUND) { - return null; - } - - int fsi = findFragmentSeparator(); - - if (fsi == NOT_FOUND) { - return uriString.substring(qsi + 1); - } - - if (fsi < qsi) { - // Invalid. - return null; - } - - return uriString.substring(qsi + 1, fsi); - } - - public String getQuery() { - return getQueryPart().getDecoded(); - } - - private Part fragment; - - private Part getFragmentPart() { - return fragment == null - ? fragment = Part.fromEncoded(parseFragment()) : fragment; - } - - public String getEncodedFragment() { - return getFragmentPart().getEncoded(); - } - - private String parseFragment() { - int fsi = findFragmentSeparator(); - return fsi == NOT_FOUND ? null : uriString.substring(fsi + 1); - } - - public String getFragment() { - return getFragmentPart().getDecoded(); - } - - public String toString() { - return uriString; - } - - /** - * Parses an authority out of the given URI string. - * - * @param uriString URI string - * @param ssi scheme separator index, -1 for a relative URI - * - * @return the authority or null if none is found - */ - static String parseAuthority(String uriString, int ssi) { - int length = uriString.length(); - - // If "//" follows the scheme separator, we have an authority. - if (length > ssi + 2 - && uriString.charAt(ssi + 1) == '/' - && uriString.charAt(ssi + 2) == '/') { - // We have an authority. - - // Look for the start of the path, query, or fragment, or the - // end of the string. - int end = ssi + 3; - LOOP: while (end < length) { - switch (uriString.charAt(end)) { - case '/': // Start of path - case '?': // Start of query - case '#': // Start of fragment - break LOOP; - } - end++; - } - - return uriString.substring(ssi + 3, end); - } else { - return null; - } - - } - - /** - * Parses a path out of this given URI string. - * - * @param uriString URI string - * @param ssi scheme separator index, -1 for a relative URI - * - * @return the path - */ - static String parsePath(String uriString, int ssi) { - int length = uriString.length(); - - // Find start of path. - int pathStart; - if (length > ssi + 2 - && uriString.charAt(ssi + 1) == '/' - && uriString.charAt(ssi + 2) == '/') { - // Skip over authority to path. - pathStart = ssi + 3; - LOOP: while (pathStart < length) { - switch (uriString.charAt(pathStart)) { - case '?': // Start of query - case '#': // Start of fragment - return ""; // Empty path. - case '/': // Start of path! - break LOOP; - } - pathStart++; - } - } else { - // Path starts immediately after scheme separator. - pathStart = ssi + 1; - } - - // Find end of path. - int pathEnd = pathStart; - LOOP: while (pathEnd < length) { - switch (uriString.charAt(pathEnd)) { - case '?': // Start of query - case '#': // Start of fragment - break LOOP; - } - pathEnd++; - } - - return uriString.substring(pathStart, pathEnd); - } - - public Builder buildUpon() { - if (isHierarchical()) { - return new Builder() - .scheme(getScheme()) - .authority(getAuthorityPart()) - .path(getPathPart()) - .query(getQueryPart()) - .fragment(getFragmentPart()); - } else { - return new Builder() - .scheme(getScheme()) - .opaquePart(getSsp()) - .fragment(getFragmentPart()); - } - } - } - - /** - * Creates an opaque Uri from the given components. Encodes the ssp - * which means this method cannot be used to create hierarchical URIs. - * - * @param scheme of the URI - * @param ssp scheme-specific-part, everything between the - * scheme separator (':') and the fragment separator ('#'), which will - * get encoded - * @param fragment fragment, everything after the '#', null if undefined, - * will get encoded - * - * @throws NullPointerException if scheme or ssp is null - * @return Uri composed of the given scheme, ssp, and fragment - * - * @see Builder if you don't want the ssp and fragment to be encoded - */ - public static Uri fromParts(String scheme, String ssp, - String fragment) { - if (scheme == null) { - throw new NullPointerException("scheme"); - } - if (ssp == null) { - throw new NullPointerException("ssp"); - } - - return new OpaqueUri(scheme, Part.fromDecoded(ssp), - Part.fromDecoded(fragment)); - } - - /** - * Opaque URI. - */ - private static class OpaqueUri extends Uri { - - /** Used in parcelling. */ - static final int TYPE_ID = 2; - - private final String scheme; - private final Part ssp; - private final Part fragment; - - private OpaqueUri(String scheme, Part ssp, Part fragment) { - this.scheme = scheme; - this.ssp = ssp; - this.fragment = fragment == null ? Part.NULL : fragment; - } - - static Uri readFrom(Parcel parcel) { - return new OpaqueUri( - parcel.readString(), - Part.readFrom(parcel), - Part.readFrom(parcel) - ); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(TYPE_ID); - parcel.writeString(scheme); - ssp.writeTo(parcel); - fragment.writeTo(parcel); - } - - public boolean isHierarchical() { - return false; - } - - public boolean isRelative() { - return scheme == null; - } - - public String getScheme() { - return this.scheme; - } - - public String getEncodedSchemeSpecificPart() { - return ssp.getEncoded(); - } - - public String getSchemeSpecificPart() { - return ssp.getDecoded(); - } - - public String getAuthority() { - return null; - } - - public String getEncodedAuthority() { - return null; - } - - public String getPath() { - return null; - } - - public String getEncodedPath() { - return null; - } - - public String getQuery() { - return null; - } - - public String getEncodedQuery() { - return null; - } - - public String getFragment() { - return fragment.getDecoded(); - } - - public String getEncodedFragment() { - return fragment.getEncoded(); - } - - public List<String> getPathSegments() { - return Collections.emptyList(); - } - - public String getLastPathSegment() { - return null; - } - - public String getUserInfo() { - return null; - } - - public String getEncodedUserInfo() { - return null; - } - - public String getHost() { - return null; - } - - public int getPort() { - return -1; - } - - private volatile String cachedString = NOT_CACHED; - - public String toString() { - @SuppressWarnings("StringEquality") - boolean cached = cachedString != NOT_CACHED; - if (cached) { - return cachedString; - } - - StringBuilder sb = new StringBuilder(); - - sb.append(scheme).append(':'); - sb.append(getEncodedSchemeSpecificPart()); - - if (!fragment.isEmpty()) { - sb.append('#').append(fragment.getEncoded()); - } - - return cachedString = sb.toString(); - } - - public Builder buildUpon() { - return new Builder() - .scheme(this.scheme) - .opaquePart(this.ssp) - .fragment(this.fragment); - } - } - - /** - * Wrapper for path segment array. - */ - static class PathSegments extends AbstractList<String> - implements RandomAccess { - - static final PathSegments EMPTY = new PathSegments(null, 0); - - final String[] segments; - final int size; - - PathSegments(String[] segments, int size) { - this.segments = segments; - this.size = size; - } - - public String get(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException(); - } - - return segments[index]; - } - - public int size() { - return this.size; - } - } - - /** - * Builds PathSegments. - */ - static class PathSegmentsBuilder { - - String[] segments; - int size = 0; - - void add(String segment) { - if (segments == null) { - segments = new String[4]; - } else if (size + 1 == segments.length) { - String[] expanded = new String[segments.length * 2]; - System.arraycopy(segments, 0, expanded, 0, segments.length); - segments = expanded; - } - - segments[size++] = segment; - } - - PathSegments build() { - if (segments == null) { - return PathSegments.EMPTY; - } - - try { - return new PathSegments(segments, size); - } finally { - // Makes sure this doesn't get reused. - segments = null; - } - } - } - - /** - * Support for hierarchical URIs. - */ - private abstract static class AbstractHierarchicalUri extends Uri { - - public String getLastPathSegment() { - // TODO: If we haven't parsed all of the segments already, just - // grab the last one directly so we only allocate one string. - - List<String> segments = getPathSegments(); - int size = segments.size(); - if (size == 0) { - return null; - } - return segments.get(size - 1); - } - - private Part userInfo; - - private Part getUserInfoPart() { - return userInfo == null - ? userInfo = Part.fromEncoded(parseUserInfo()) : userInfo; - } - - public final String getEncodedUserInfo() { - return getUserInfoPart().getEncoded(); - } - - private String parseUserInfo() { - String authority = getEncodedAuthority(); - if (authority == null) { - return null; - } - - int end = authority.indexOf('@'); - return end == NOT_FOUND ? null : authority.substring(0, end); - } - - public String getUserInfo() { - return getUserInfoPart().getDecoded(); - } - - private volatile String host = NOT_CACHED; - - public String getHost() { - @SuppressWarnings("StringEquality") - boolean cached = (host != NOT_CACHED); - return cached ? host - : (host = parseHost()); - } - - private String parseHost() { - String authority = getAuthority(); - if (authority == null) { - return null; - } - - // Parse out user info and then port. - int userInfoSeparator = authority.indexOf('@'); - int portSeparator = authority.indexOf(':', userInfoSeparator); - - return portSeparator == NOT_FOUND - ? authority.substring(userInfoSeparator + 1) - : authority.substring(userInfoSeparator + 1, portSeparator); - } - - private volatile int port = NOT_CALCULATED; - - public int getPort() { - return port == NOT_CALCULATED - ? port = parsePort() - : port; - } - - private int parsePort() { - String authority = getAuthority(); - if (authority == null) { - return -1; - } - - // Make sure we look for the port separtor *after* the user info - // separator. We have URLs with a ':' in the user info. - int userInfoSeparator = authority.indexOf('@'); - int portSeparator = authority.indexOf(':', userInfoSeparator); - - if (portSeparator == NOT_FOUND) { - return -1; - } - - String portString = authority.substring(portSeparator + 1); - try { - return Integer.parseInt(portString); - } catch (NumberFormatException e) { - Log.w(LOG, "Error parsing port string.", e); - return -1; - } - } - } - - /** - * Hierarchical Uri. - */ - private static class HierarchicalUri extends AbstractHierarchicalUri { - - /** Used in parcelling. */ - static final int TYPE_ID = 3; - - private final String scheme; - private final Part authority; - private final PathPart path; - private final Part query; - private final Part fragment; - - private HierarchicalUri(String scheme, Part authority, PathPart path, - Part query, Part fragment) { - this.scheme = scheme; - this.authority = authority; - this.path = path; - this.query = query; - this.fragment = fragment; - } - - static Uri readFrom(Parcel parcel) { - return new HierarchicalUri( - parcel.readString(), - Part.readFrom(parcel), - PathPart.readFrom(parcel), - Part.readFrom(parcel), - Part.readFrom(parcel) - ); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(TYPE_ID); - parcel.writeString(scheme); - authority.writeTo(parcel); - path.writeTo(parcel); - query.writeTo(parcel); - fragment.writeTo(parcel); - } - - public boolean isHierarchical() { - return true; - } - - public boolean isRelative() { - return scheme == null; - } - - public String getScheme() { - return scheme; - } - - private Part ssp; - - private Part getSsp() { - return ssp == null - ? ssp = Part.fromEncoded(makeSchemeSpecificPart()) : ssp; - } - - public String getEncodedSchemeSpecificPart() { - return getSsp().getEncoded(); - } - - public String getSchemeSpecificPart() { - return getSsp().getDecoded(); - } - - /** - * Creates the encoded scheme-specific part from its sub parts. - */ - private String makeSchemeSpecificPart() { - StringBuilder builder = new StringBuilder(); - appendSspTo(builder); - return builder.toString(); - } - - private void appendSspTo(StringBuilder builder) { - if (authority != null) { - String encodedAuthority = authority.getEncoded(); - if (encodedAuthority != null) { - // Even if the authority is "", we still want to append "//". - builder.append("//").append(encodedAuthority); - } - } - - // path is never null. - String encodedPath = path.getEncoded(); - if (encodedPath != null) { - builder.append(encodedPath); - } - - if (query != null && !query.isEmpty()) { - builder.append('?').append(query.getEncoded()); - } - } - - public String getAuthority() { - return this.authority.getDecoded(); - } - - public String getEncodedAuthority() { - return this.authority.getEncoded(); - } - - public String getEncodedPath() { - return this.path.getEncoded(); - } - - public String getPath() { - return this.path.getDecoded(); - } - - public String getQuery() { - return this.query.getDecoded(); - } - - public String getEncodedQuery() { - return this.query.getEncoded(); - } - - public String getFragment() { - return this.fragment.getDecoded(); - } - - public String getEncodedFragment() { - return this.fragment.getEncoded(); - } - - public List<String> getPathSegments() { - return this.path.getPathSegments(); - } - - private volatile String uriString = NOT_CACHED; - - @Override - public String toString() { - @SuppressWarnings("StringEquality") - boolean cached = (uriString != NOT_CACHED); - return cached ? uriString - : (uriString = makeUriString()); - } - - private String makeUriString() { - StringBuilder builder = new StringBuilder(); - - if (scheme != null) { - builder.append(scheme).append(':'); - } - - appendSspTo(builder); - - if (fragment != null && !fragment.isEmpty()) { - builder.append('#').append(fragment.getEncoded()); - } - - return builder.toString(); - } - - public Builder buildUpon() { - return new Builder() - .scheme(scheme) - .authority(authority) - .path(path) - .query(query) - .fragment(fragment); - } - } - - /** - * Helper class for building or manipulating URI references. Not safe for - * concurrent use. - * - * <p>An absolute hierarchical URI reference follows the pattern: - * {@code <scheme>://<authority><absolute path>?<query>#<fragment>} - * - * <p>Relative URI references (which are always hierarchical) follow one - * of two patterns: {@code <relative or absolute path>?<query>#<fragment>} - * or {@code //<authority><absolute path>?<query>#<fragment>} - * - * <p>An opaque URI follows this pattern: - * {@code <scheme>:<opaque part>#<fragment>} - */ - public static final class Builder { - - private String scheme; - private Part opaquePart; - private Part authority; - private PathPart path; - private Part query; - private Part fragment; - - /** - * Constructs a new Builder. - */ - public Builder() {} - - /** - * Sets the scheme. - * - * @param scheme name or {@code null} if this is a relative Uri - */ - public Builder scheme(String scheme) { - this.scheme = scheme; - return this; - } - - Builder opaquePart(Part opaquePart) { - this.opaquePart = opaquePart; - return this; - } - - /** - * Encodes and sets the given opaque scheme-specific-part. - * - * @param opaquePart decoded opaque part - */ - public Builder opaquePart(String opaquePart) { - return opaquePart(Part.fromDecoded(opaquePart)); - } - - /** - * Sets the previously encoded opaque scheme-specific-part. - * - * @param opaquePart encoded opaque part - */ - public Builder encodedOpaquePart(String opaquePart) { - return opaquePart(Part.fromEncoded(opaquePart)); - } - - Builder authority(Part authority) { - // This URI will be hierarchical. - this.opaquePart = null; - - this.authority = authority; - return this; - } - - /** - * Encodes and sets the authority. - */ - public Builder authority(String authority) { - return authority(Part.fromDecoded(authority)); - } - - /** - * Sets the previously encoded authority. - */ - public Builder encodedAuthority(String authority) { - return authority(Part.fromEncoded(authority)); - } - - Builder path(PathPart path) { - // This URI will be hierarchical. - this.opaquePart = null; - - this.path = path; - return this; - } - - /** - * Sets the path. Leaves '/' characters intact but encodes others as - * necessary. - * - * <p>If the path is not null and doesn't start with a '/', and if - * you specify a scheme and/or authority, the builder will prepend the - * given path with a '/'. - */ - public Builder path(String path) { - return path(PathPart.fromDecoded(path)); - } - - /** - * Sets the previously encoded path. - * - * <p>If the path is not null and doesn't start with a '/', and if - * you specify a scheme and/or authority, the builder will prepend the - * given path with a '/'. - */ - public Builder encodedPath(String path) { - return path(PathPart.fromEncoded(path)); - } - - /** - * Encodes the given segment and appends it to the path. - */ - public Builder appendPath(String newSegment) { - return path(PathPart.appendDecodedSegment(path, newSegment)); - } - - /** - * Appends the given segment to the path. - */ - public Builder appendEncodedPath(String newSegment) { - return path(PathPart.appendEncodedSegment(path, newSegment)); - } - - Builder query(Part query) { - // This URI will be hierarchical. - this.opaquePart = null; - - this.query = query; - return this; - } - - /** - * Encodes and sets the query. - */ - public Builder query(String query) { - return query(Part.fromDecoded(query)); - } - - /** - * Sets the previously encoded query. - */ - public Builder encodedQuery(String query) { - return query(Part.fromEncoded(query)); - } - - Builder fragment(Part fragment) { - this.fragment = fragment; - return this; - } - - /** - * Encodes and sets the fragment. - */ - public Builder fragment(String fragment) { - return fragment(Part.fromDecoded(fragment)); - } - - /** - * Sets the previously encoded fragment. - */ - public Builder encodedFragment(String fragment) { - return fragment(Part.fromEncoded(fragment)); - } - - /** - * Encodes the key and value and then appends the parameter to the - * query string. - * - * @param key which will be encoded - * @param value which will be encoded - */ - public Builder appendQueryParameter(String key, String value) { - // This URI will be hierarchical. - this.opaquePart = null; - - String encodedParameter = encode(key, null) + "=" - + encode(value, null); - - if (query == null) { - query = Part.fromEncoded(encodedParameter); - return this; - } - - String oldQuery = query.getEncoded(); - if (oldQuery == null || oldQuery.length() == 0) { - query = Part.fromEncoded(encodedParameter); - } else { - query = Part.fromEncoded(oldQuery + "&" + encodedParameter); - } - - return this; - } - - /** - * Constructs a Uri with the current attributes. - * - * @throws UnsupportedOperationException if the URI is opaque and the - * scheme is null - */ - public Uri build() { - if (opaquePart != null) { - if (this.scheme == null) { - throw new UnsupportedOperationException( - "An opaque URI must have a scheme."); - } - - return new OpaqueUri(scheme, opaquePart, fragment); - } else { - // Hierarchical URIs should not return null for getPath(). - PathPart path = this.path; - if (path == null || path == PathPart.NULL) { - path = PathPart.EMPTY; - } else { - // If we have a scheme and/or authority, the path must - // be absolute. Prepend it with a '/' if necessary. - if (hasSchemeOrAuthority()) { - path = PathPart.makeAbsolute(path); - } - } - - return new HierarchicalUri( - scheme, authority, path, query, fragment); - } - } - - private boolean hasSchemeOrAuthority() { - return scheme != null - || (authority != null && authority != Part.NULL); - - } - - @Override - public String toString() { - return build().toString(); - } - } - - /** - * Searches the query string for parameter values with the given key. - * - * @param key which will be encoded - * - * @throws UnsupportedOperationException if this isn't a hierarchical URI - * @throws NullPointerException if key is null - * - * @return a list of decoded values - */ - public List<String> getQueryParameters(String key) { - if (isOpaque()) { - throw new UnsupportedOperationException(NOT_HIERARCHICAL); - } - - String query = getQuery(); - if (query == null) { - return Collections.emptyList(); - } - - String encodedKey; - try { - encodedKey = URLEncoder.encode(key, DEFAULT_ENCODING); - } catch (UnsupportedEncodingException e) { - throw new AssertionError(e); - } - - // Prepend query with "&" making the first parameter the same as the - // rest. - query = "&" + query; - - // Parameter prefix. - String prefix = "&" + encodedKey + "="; - - ArrayList<String> values = new ArrayList<String>(); - - int start = 0; - int length = query.length(); - while (start < length) { - start = query.indexOf(prefix, start); - - if (start == -1) { - // No more values. - break; - } - - // Move start to start of value. - start += prefix.length(); - - // Find end of value. - int end = query.indexOf('&', start); - if (end == -1) { - end = query.length(); - } - - String value = query.substring(start, end); - values.add(decode(value)); - - start = end; - } - - return Collections.unmodifiableList(values); - } - - /** - * Searches the query string for the first value with the given key. - * - * @param key which will be encoded - * @throws UnsupportedOperationException if this isn't a hierarchical URI - * @throws NullPointerException if key is null - * - * @return the decoded value or null if no parameter is found - */ - public String getQueryParameter(String key) { - if (isOpaque()) { - throw new UnsupportedOperationException(NOT_HIERARCHICAL); - } - - String query = getQuery(); - - if (query == null) { - return null; - } - - String encodedKey; - try { - encodedKey = URLEncoder.encode(key, DEFAULT_ENCODING); - } catch (UnsupportedEncodingException e) { - throw new AssertionError(e); - } - - String prefix = encodedKey + "="; - - if (query.length() < prefix.length()) { - return null; - } - - int start; - if (query.startsWith(prefix)) { - // It's the first parameter. - start = prefix.length(); - } else { - // It must be later in the query string. - prefix = "&" + prefix; - start = query.indexOf(prefix); - - if (start == -1) { - // Not found. - return null; - } - - start += prefix.length(); - } - - // Find end of value. - int end = query.indexOf('&', start); - if (end == -1) { - end = query.length(); - } - - String value = query.substring(start, end); - return decode(value); - } - - /** Identifies a null parcelled Uri. */ - private static final int NULL_TYPE_ID = 0; - - /** - * Reads Uris from Parcels. - */ - public static final Parcelable.Creator<Uri> CREATOR - = new Parcelable.Creator<Uri>() { - public Uri createFromParcel(Parcel in) { - int type = in.readInt(); - switch (type) { - case NULL_TYPE_ID: return null; - case StringUri.TYPE_ID: return StringUri.readFrom(in); - case OpaqueUri.TYPE_ID: return OpaqueUri.readFrom(in); - case HierarchicalUri.TYPE_ID: - return HierarchicalUri.readFrom(in); - } - - throw new AssertionError("Unknown URI type: " + type); - } - - public Uri[] newArray(int size) { - return new Uri[size]; - } - }; - - /** - * Writes a Uri to a Parcel. - * - * @param out parcel to write to - * @param uri to write, can be null - */ - public static void writeToParcel(Parcel out, Uri uri) { - if (uri == null) { - out.writeInt(NULL_TYPE_ID); - } else { - uri.writeToParcel(out, 0); - } - } - - private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); - - /** - * Encodes characters in the given string as '%'-escaped octets - * using the UTF-8 scheme. Leaves letters ("A-Z", "a-z"), numbers - * ("0-9"), and unreserved characters ("_-!.~'()*") intact. Encodes - * all other characters. - * - * @param s string to encode - * @return an encoded version of s suitable for use as a URI component, - * or null if s is null - */ - public static String encode(String s) { - return encode(s, null); - } - - /** - * Encodes characters in the given string as '%'-escaped octets - * using the UTF-8 scheme. Leaves letters ("A-Z", "a-z"), numbers - * ("0-9"), and unreserved characters ("_-!.~'()*") intact. Encodes - * all other characters with the exception of those specified in the - * allow argument. - * - * @param s string to encode - * @param allow set of additional characters to allow in the encoded form, - * null if no characters should be skipped - * @return an encoded version of s suitable for use as a URI component, - * or null if s is null - */ - public static String encode(String s, String allow) { - if (s == null) { - return null; - } - - // Lazily-initialized buffers. - StringBuilder encoded = null; - - int oldLength = s.length(); - - // This loop alternates between copying over allowed characters and - // encoding in chunks. This results in fewer method calls and - // allocations than encoding one character at a time. - int current = 0; - while (current < oldLength) { - // Start in "copying" mode where we copy over allowed chars. - - // Find the next character which needs to be encoded. - int nextToEncode = current; - while (nextToEncode < oldLength - && isAllowed(s.charAt(nextToEncode), allow)) { - nextToEncode++; - } - - // If there's nothing more to encode... - if (nextToEncode == oldLength) { - if (current == 0) { - // We didn't need to encode anything! - return s; - } else { - // Presumably, we've already done some encoding. - encoded.append(s, current, oldLength); - return encoded.toString(); - } - } - - if (encoded == null) { - encoded = new StringBuilder(); - } - - if (nextToEncode > current) { - // Append allowed characters leading up to this point. - encoded.append(s, current, nextToEncode); - } else { - // assert nextToEncode == current - } - - // Switch to "encoding" mode. - - // Find the next allowed character. - current = nextToEncode; - int nextAllowed = current + 1; - while (nextAllowed < oldLength - && !isAllowed(s.charAt(nextAllowed), allow)) { - nextAllowed++; - } - - // Convert the substring to bytes and encode the bytes as - // '%'-escaped octets. - String toEncode = s.substring(current, nextAllowed); - try { - byte[] bytes = toEncode.getBytes(DEFAULT_ENCODING); - int bytesLength = bytes.length; - for (int i = 0; i < bytesLength; i++) { - encoded.append('%'); - encoded.append(HEX_DIGITS[(bytes[i] & 0xf0) >> 4]); - encoded.append(HEX_DIGITS[bytes[i] & 0xf]); - } - } catch (UnsupportedEncodingException e) { - throw new AssertionError(e); - } - - current = nextAllowed; - } - - // Encoded could still be null at this point if s is empty. - return encoded == null ? s : encoded.toString(); - } - - /** - * Returns true if the given character is allowed. - * - * @param c character to check - * @param allow characters to allow - * @return true if the character is allowed or false if it should be - * encoded - */ - private static boolean isAllowed(char c, String allow) { - return (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z') - || (c >= '0' && c <= '9') - || "_-!.~'()*".indexOf(c) != NOT_FOUND - || (allow != null && allow.indexOf(c) != NOT_FOUND); - } - - /** Unicode replacement character: \\uFFFD. */ - private static final byte[] REPLACEMENT = { (byte) 0xFF, (byte) 0xFD }; - - /** - * Decodes '%'-escaped octets in the given string using the UTF-8 scheme. - * Replaces invalid octets with the unicode replacement character - * ("\\uFFFD"). - * - * @param s encoded string to decode - * @return the given string with escaped octets decoded, or null if - * s is null - */ - public static String decode(String s) { - /* - Compared to java.net.URLEncoderDecoder.decode(), this method decodes a - chunk at a time instead of one character at a time, and it doesn't - throw exceptions. It also only allocates memory when necessary--if - there's nothing to decode, this method won't do much. - */ - - if (s == null) { - return null; - } - - // Lazily-initialized buffers. - StringBuilder decoded = null; - ByteArrayOutputStream out = null; - - int oldLength = s.length(); - - // This loop alternates between copying over normal characters and - // escaping in chunks. This results in fewer method calls and - // allocations than decoding one character at a time. - int current = 0; - while (current < oldLength) { - // Start in "copying" mode where we copy over normal characters. - - // Find the next escape sequence. - int nextEscape = s.indexOf('%', current); - - if (nextEscape == NOT_FOUND) { - if (decoded == null) { - // We didn't actually decode anything. - return s; - } else { - // Append the remainder and return the decoded string. - decoded.append(s, current, oldLength); - return decoded.toString(); - } - } - - // Prepare buffers. - if (decoded == null) { - // Looks like we're going to need the buffers... - // We know the new string will be shorter. Using the old length - // may overshoot a bit, but it will save us from resizing the - // buffer. - decoded = new StringBuilder(oldLength); - out = new ByteArrayOutputStream(4); - } else { - // Clear decoding buffer. - out.reset(); - } - - // Append characters leading up to the escape. - if (nextEscape > current) { - decoded.append(s, current, nextEscape); - - current = nextEscape; - } else { - // assert current == nextEscape - } - - // Switch to "decoding" mode where we decode a string of escape - // sequences. - - // Decode and append escape sequences. Escape sequences look like - // "%ab" where % is literal and a and b are hex digits. - try { - do { - if (current + 2 >= oldLength) { - // Truncated escape sequence. - out.write(REPLACEMENT); - } else { - int a = Character.digit(s.charAt(current + 1), 16); - int b = Character.digit(s.charAt(current + 2), 16); - - if (a == -1 || b == -1) { - // Non hex digits. - out.write(REPLACEMENT); - } else { - // Combine the hex digits into one byte and write. - out.write((a << 4) + b); - } - } - - // Move passed the escape sequence. - current += 3; - } while (current < oldLength && s.charAt(current) == '%'); - - // Decode UTF-8 bytes into a string and append it. - decoded.append(out.toString(DEFAULT_ENCODING)); - } catch (UnsupportedEncodingException e) { - throw new AssertionError(e); - } catch (IOException e) { - throw new AssertionError(e); - } - } - - // If we don't have a buffer, we didn't have to decode anything. - return decoded == null ? s : decoded.toString(); - } - - /** - * Support for part implementations. - */ - static abstract class AbstractPart { - - /** - * Enum which indicates which representation of a given part we have. - */ - static class Representation { - static final int BOTH = 0; - static final int ENCODED = 1; - static final int DECODED = 2; - } - - volatile String encoded; - volatile String decoded; - - AbstractPart(String encoded, String decoded) { - this.encoded = encoded; - this.decoded = decoded; - } - - abstract String getEncoded(); - - final String getDecoded() { - @SuppressWarnings("StringEquality") - boolean hasDecoded = decoded != NOT_CACHED; - return hasDecoded ? decoded : (decoded = decode(encoded)); - } - - final void writeTo(Parcel parcel) { - @SuppressWarnings("StringEquality") - boolean hasEncoded = encoded != NOT_CACHED; - - @SuppressWarnings("StringEquality") - boolean hasDecoded = decoded != NOT_CACHED; - - if (hasEncoded && hasDecoded) { - parcel.writeInt(Representation.BOTH); - parcel.writeString(encoded); - parcel.writeString(decoded); - } else if (hasEncoded) { - parcel.writeInt(Representation.ENCODED); - parcel.writeString(encoded); - } else if (hasDecoded) { - parcel.writeInt(Representation.DECODED); - parcel.writeString(decoded); - } else { - throw new AssertionError(); - } - } - } - - /** - * Immutable wrapper of encoded and decoded versions of a URI part. Lazily - * creates the encoded or decoded version from the other. - */ - static class Part extends AbstractPart { - - /** A part with null values. */ - static final Part NULL = new EmptyPart(null); - - /** A part with empty strings for values. */ - static final Part EMPTY = new EmptyPart(""); - - private Part(String encoded, String decoded) { - super(encoded, decoded); - } - - boolean isEmpty() { - return false; - } - - String getEncoded() { - @SuppressWarnings("StringEquality") - boolean hasEncoded = encoded != NOT_CACHED; - return hasEncoded ? encoded : (encoded = encode(decoded)); - } - - static Part readFrom(Parcel parcel) { - int representation = parcel.readInt(); - switch (representation) { - case Representation.BOTH: - return from(parcel.readString(), parcel.readString()); - case Representation.ENCODED: - return fromEncoded(parcel.readString()); - case Representation.DECODED: - return fromDecoded(parcel.readString()); - default: - throw new AssertionError(); - } - } - - /** - * Returns given part or {@link #NULL} if the given part is null. - */ - static Part nonNull(Part part) { - return part == null ? NULL : part; - } - - /** - * Creates a part from the encoded string. - * - * @param encoded part string - */ - static Part fromEncoded(String encoded) { - return from(encoded, NOT_CACHED); - } - - /** - * Creates a part from the decoded string. - * - * @param decoded part string - */ - static Part fromDecoded(String decoded) { - return from(NOT_CACHED, decoded); - } - - /** - * Creates a part from the encoded and decoded strings. - * - * @param encoded part string - * @param decoded part string - */ - static Part from(String encoded, String decoded) { - // We have to check both encoded and decoded in case one is - // NOT_CACHED. - - if (encoded == null) { - return NULL; - } - if (encoded.length() == 0) { - return EMPTY; - } - - if (decoded == null) { - return NULL; - } - if (decoded .length() == 0) { - return EMPTY; - } - - return new Part(encoded, decoded); - } - - private static class EmptyPart extends Part { - public EmptyPart(String value) { - super(value, value); - } - - @Override - boolean isEmpty() { - return true; - } - } - } - - /** - * Immutable wrapper of encoded and decoded versions of a path part. Lazily - * creates the encoded or decoded version from the other. - */ - static class PathPart extends AbstractPart { - - /** A part with null values. */ - static final PathPart NULL = new PathPart(null, null); - - /** A part with empty strings for values. */ - static final PathPart EMPTY = new PathPart("", ""); - - private PathPart(String encoded, String decoded) { - super(encoded, decoded); - } - - String getEncoded() { - @SuppressWarnings("StringEquality") - boolean hasEncoded = encoded != NOT_CACHED; - - // Don't encode '/'. - return hasEncoded ? encoded : (encoded = encode(decoded, "/")); - } - - /** - * Cached path segments. This doesn't need to be volatile--we don't - * care if other threads see the result. - */ - private PathSegments pathSegments; - - /** - * Gets the individual path segments. Parses them if necessary. - * - * @return parsed path segments or null if this isn't a hierarchical - * URI - */ - PathSegments getPathSegments() { - if (pathSegments != null) { - return pathSegments; - } - - String path = getEncoded(); - if (path == null) { - return pathSegments = PathSegments.EMPTY; - } - - PathSegmentsBuilder segmentBuilder = new PathSegmentsBuilder(); - - int previous = 0; - int current; - while ((current = path.indexOf('/', previous)) > -1) { - // This check keeps us from adding a segment if the path starts - // '/' and an empty segment for "//". - if (previous < current) { - String decodedSegment - = decode(path.substring(previous, current)); - segmentBuilder.add(decodedSegment); - } - previous = current + 1; - } - - // Add in the final path segment. - if (previous < path.length()) { - segmentBuilder.add(decode(path.substring(previous))); - } - - return pathSegments = segmentBuilder.build(); - } - - static PathPart appendEncodedSegment(PathPart oldPart, - String newSegment) { - // If there is no old path, should we make the new path relative - // or absolute? I pick absolute. - - if (oldPart == null) { - // No old path. - return fromEncoded("/" + newSegment); - } - - String oldPath = oldPart.getEncoded(); - - if (oldPath == null) { - oldPath = ""; - } - - int oldPathLength = oldPath.length(); - String newPath; - if (oldPathLength == 0) { - // No old path. - newPath = "/" + newSegment; - } else if (oldPath.charAt(oldPathLength - 1) == '/') { - newPath = oldPath + newSegment; - } else { - newPath = oldPath + "/" + newSegment; - } - - return fromEncoded(newPath); - } - - static PathPart appendDecodedSegment(PathPart oldPart, String decoded) { - String encoded = encode(decoded); - - // TODO: Should we reuse old PathSegments? Probably not. - return appendEncodedSegment(oldPart, encoded); - } - - static PathPart readFrom(Parcel parcel) { - int representation = parcel.readInt(); - switch (representation) { - case Representation.BOTH: - return from(parcel.readString(), parcel.readString()); - case Representation.ENCODED: - return fromEncoded(parcel.readString()); - case Representation.DECODED: - return fromDecoded(parcel.readString()); - default: - throw new AssertionError(); - } - } - - /** - * Creates a path from the encoded string. - * - * @param encoded part string - */ - static PathPart fromEncoded(String encoded) { - return from(encoded, NOT_CACHED); - } - - /** - * Creates a path from the decoded string. - * - * @param decoded part string - */ - static PathPart fromDecoded(String decoded) { - return from(NOT_CACHED, decoded); - } - - /** - * Creates a path from the encoded and decoded strings. - * - * @param encoded part string - * @param decoded part string - */ - static PathPart from(String encoded, String decoded) { - if (encoded == null) { - return NULL; - } - - if (encoded.length() == 0) { - return EMPTY; - } - - return new PathPart(encoded, decoded); - } - - /** - * Prepends path values with "/" if they're present, not empty, and - * they don't already start with "/". - */ - static PathPart makeAbsolute(PathPart oldPart) { - @SuppressWarnings("StringEquality") - boolean encodedCached = oldPart.encoded != NOT_CACHED; - - // We don't care which version we use, and we don't want to force - // unneccessary encoding/decoding. - String oldPath = encodedCached ? oldPart.encoded : oldPart.decoded; - - if (oldPath == null || oldPath.length() == 0 - || oldPath.startsWith("/")) { - return oldPart; - } - - // Prepend encoded string if present. - String newEncoded = encodedCached - ? "/" + oldPart.encoded : NOT_CACHED; - - // Prepend decoded string if present. - @SuppressWarnings("StringEquality") - boolean decodedCached = oldPart.decoded != NOT_CACHED; - String newDecoded = decodedCached - ? "/" + oldPart.decoded - : NOT_CACHED; - - return new PathPart(newEncoded, newDecoded); - } - } - - /** - * Creates a new Uri by appending an already-encoded path segment to a - * base Uri. - * - * @param baseUri Uri to append path segment to - * @param pathSegment encoded path segment to append - * @return a new Uri based on baseUri with the given segment appended to - * the path - * @throws NullPointerException if baseUri is null - */ - public static Uri withAppendedPath(Uri baseUri, String pathSegment) { - Builder builder = baseUri.buildUpon(); - builder = builder.appendEncodedPath(pathSegment); - return builder.build(); - } -} diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java deleted file mode 100644 index a6efcdd..0000000 --- a/core/java/android/net/UrlQuerySanitizer.java +++ /dev/null @@ -1,913 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.StringTokenizer; - -/** - * - * Sanitizes the Query portion of a URL. Simple example: - * <code> - * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(); - * sanitizer.setAllowUnregisteredParamaters(true); - * sanitizer.parseUrl("http://example.com/?name=Joe+User"); - * String name = sanitizer.getValue("name")); - * // name now contains "Joe_User" - * </code> - * - * Register ValueSanitizers to customize the way individual - * parameters are sanitized: - * <code> - * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(); - * sanitizer.registerParamater("name", UrlQuerySanitizer.createSpaceLegal()); - * sanitizer.parseUrl("http://example.com/?name=Joe+User"); - * String name = sanitizer.getValue("name")); - * // name now contains "Joe User". (The string is first decoded, which - * // converts the '+' to a ' '. Then the string is sanitized, which - * // converts the ' ' to an '_'. (The ' ' is converted because the default - * unregistered parameter sanitizer does not allow any special characters, - * and ' ' is a special character.) - * </code> - * - * There are several ways to create ValueSanitizers. In order of increasing - * sophistication: - * <ol> - * <li>Call one of the UrlQuerySanitizer.createXXX() methods. - * <li>Construct your own instance of - * UrlQuerySanitizer.IllegalCharacterValueSanitizer. - * <li>Subclass UrlQuerySanitizer.ValueSanitizer to define your own value - * sanitizer. - * </ol> - * - */ -public class UrlQuerySanitizer { - - /** - * A simple tuple that holds parameter-value pairs. - * - */ - public class ParameterValuePair { - /** - * Construct a parameter-value tuple. - * @param parameter an unencoded parameter - * @param value an unencoded value - */ - public ParameterValuePair(String parameter, - String value) { - mParameter = parameter; - mValue = value; - } - /** - * The unencoded parameter - */ - public String mParameter; - /** - * The unencoded value - */ - public String mValue; - } - - final private HashMap<String, ValueSanitizer> mSanitizers = - new HashMap<String, ValueSanitizer>(); - final private HashMap<String, String> mEntries = - new HashMap<String, String>(); - final private ArrayList<ParameterValuePair> mEntriesList = - new ArrayList<ParameterValuePair>(); - private boolean mAllowUnregisteredParamaters; - private boolean mPreferFirstRepeatedParameter; - private ValueSanitizer mUnregisteredParameterValueSanitizer = - getAllIllegal(); - - /** - * A functor used to sanitize a single query value. - * - */ - public static interface ValueSanitizer { - /** - * Sanitize an unencoded value. - * @param value - * @return the sanitized unencoded value - */ - public String sanitize(String value); - } - - /** - * Sanitize values based on which characters they contain. Illegal - * characters are replaced with either space or '_', depending upon - * whether space is a legal character or not. - */ - public static class IllegalCharacterValueSanitizer implements - ValueSanitizer { - private int mFlags; - - /** - * Allow space (' ') characters. - */ - public final static int SPACE_OK = 1 << 0; - /** - * Allow whitespace characters other than space. The - * other whitespace characters are - * '\t' '\f' '\n' '\r' and '\0x000b' (vertical tab) - */ - public final static int OTHER_WHITESPACE_OK = 1 << 1; - /** - * Allow characters with character codes 128 to 255. - */ - public final static int NON_7_BIT_ASCII_OK = 1 << 2; - /** - * Allow double quote characters. ('"') - */ - public final static int DQUOTE_OK = 1 << 3; - /** - * Allow single quote characters. ('\'') - */ - public final static int SQUOTE_OK = 1 << 4; - /** - * Allow less-than characters. ('<') - */ - public final static int LT_OK = 1 << 5; - /** - * Allow greater-than characters. ('>') - */ - public final static int GT_OK = 1 << 6; - /** - * Allow ampersand characters ('&') - */ - public final static int AMP_OK = 1 << 7; - /** - * Allow percent-sign characters ('%') - */ - public final static int PCT_OK = 1 << 8; - /** - * Allow nul characters ('\0') - */ - public final static int NUL_OK = 1 << 9; - /** - * Allow text to start with a script URL - * such as "javascript:" or "vbscript:" - */ - public final static int SCRIPT_URL_OK = 1 << 10; - - /** - * Mask with all fields set to OK - */ - public final static int ALL_OK = 0x7ff; - - /** - * Mask with both regular space and other whitespace OK - */ - public final static int ALL_WHITESPACE_OK = - SPACE_OK | OTHER_WHITESPACE_OK; - - - // Common flag combinations: - - /** - * <ul> - * <li>Deny all special characters. - * <li>Deny script URLs. - * </ul> - */ - public final static int ALL_ILLEGAL = - 0; - /** - * <ul> - * <li>Allow all special characters except Nul. ('\0'). - * <li>Allow script URLs. - * </ul> - */ - public final static int ALL_BUT_NUL_LEGAL = - ALL_OK & ~NUL_OK; - /** - * <ul> - * <li>Allow all special characters except for: - * <ul> - * <li>whitespace characters - * <li>Nul ('\0') - * </ul> - * <li>Allow script URLs. - * </ul> - */ - public final static int ALL_BUT_WHITESPACE_LEGAL = - ALL_OK & ~(ALL_WHITESPACE_OK | NUL_OK); - /** - * <ul> - * <li>Allow characters used by encoded URLs. - * <li>Deny script URLs. - * </ul> - */ - public final static int URL_LEGAL = - NON_7_BIT_ASCII_OK | SQUOTE_OK | AMP_OK | PCT_OK; - /** - * <ul> - * <li>Allow characters used by encoded URLs. - * <li>Allow spaces. - * <li>Deny script URLs. - * </ul> - */ - public final static int URL_AND_SPACE_LEGAL = - URL_LEGAL | SPACE_OK; - /** - * <ul> - * <li>Allow ampersand. - * <li>Deny script URLs. - * </ul> - */ - public final static int AMP_LEGAL = - AMP_OK; - /** - * <ul> - * <li>Allow ampersand. - * <li>Allow space. - * <li>Deny script URLs. - * </ul> - */ - public final static int AMP_AND_SPACE_LEGAL = - AMP_OK | SPACE_OK; - /** - * <ul> - * <li>Allow space. - * <li>Deny script URLs. - * </ul> - */ - public final static int SPACE_LEGAL = - SPACE_OK; - /** - * <ul> - * <li>Allow all but. - * <ul> - * <li>Nul ('\0') - * <li>Angle brackets ('<', '>') - * </ul> - * <li>Deny script URLs. - * </ul> - */ - public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL = - ALL_OK & ~(NUL_OK | LT_OK | GT_OK); - - /** - * Script URL definitions - */ - - private final static String JAVASCRIPT_PREFIX = "javascript:"; - - private final static String VBSCRIPT_PREFIX = "vbscript:"; - - private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min( - JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length()); - - /** - * Construct a sanitizer. The parameters set the behavior of the - * sanitizer. - * @param flags some combination of the XXX_OK flags. - */ - public IllegalCharacterValueSanitizer( - int flags) { - mFlags = flags; - } - /** - * Sanitize a value. - * <ol> - * <li>If script URLs are not OK, the will be removed. - * <li>If neither spaces nor other white space is OK, then - * white space will be trimmed from the beginning and end of - * the URL. (Just the actual white space characters are trimmed, not - * other control codes.) - * <li> Illegal characters will be replaced with - * either ' ' or '_', depending on whether a space is itself a - * legal character. - * </ol> - * @param value - * @return the sanitized value - */ - public String sanitize(String value) { - if (value == null) { - return null; - } - int length = value.length(); - if ((mFlags & SCRIPT_URL_OK) != 0) { - if (length >= MIN_SCRIPT_PREFIX_LENGTH) { - String asLower = value.toLowerCase(); - if (asLower.startsWith(JAVASCRIPT_PREFIX) || - asLower.startsWith(VBSCRIPT_PREFIX)) { - return ""; - } - } - } - - // If whitespace isn't OK, get rid of whitespace at beginning - // and end of value. - if ( (mFlags & ALL_WHITESPACE_OK) == 0) { - value = trimWhitespace(value); - // The length could have changed, so we need to correct - // the length variable. - length = value.length(); - } - - StringBuilder stringBuilder = new StringBuilder(length); - for(int i = 0; i < length; i++) { - char c = value.charAt(i); - if (!characterIsLegal(c)) { - if ((mFlags & SPACE_OK) != 0) { - c = ' '; - } - else { - c = '_'; - } - } - stringBuilder.append(c); - } - return stringBuilder.toString(); - } - - /** - * Trim whitespace from the beginning and end of a string. - * <p> - * Note: can't use {@link String#trim} because {@link String#trim} has a - * different definition of whitespace than we want. - * @param value the string to trim - * @return the trimmed string - */ - private String trimWhitespace(String value) { - int start = 0; - int last = value.length() - 1; - int end = last; - while (start <= end && isWhitespace(value.charAt(start))) { - start++; - } - while (end >= start && isWhitespace(value.charAt(end))) { - end--; - } - if (start == 0 && end == last) { - return value; - } - return value.substring(start, end + 1); - } - - /** - * Check if c is whitespace. - * @param c character to test - * @return true if c is a whitespace character - */ - private boolean isWhitespace(char c) { - switch(c) { - case ' ': - case '\t': - case '\f': - case '\n': - case '\r': - case 11: /* VT */ - return true; - default: - return false; - } - } - - /** - * Check whether an individual character is legal. Uses the - * flag bit-set passed into the constructor. - * @param c - * @return true if c is a legal character - */ - private boolean characterIsLegal(char c) { - switch(c) { - case ' ' : return (mFlags & SPACE_OK) != 0; - case '\t': case '\f': case '\n': case '\r': case 11: /* VT */ - return (mFlags & OTHER_WHITESPACE_OK) != 0; - case '\"': return (mFlags & DQUOTE_OK) != 0; - case '\'': return (mFlags & SQUOTE_OK) != 0; - case '<' : return (mFlags & LT_OK) != 0; - case '>' : return (mFlags & GT_OK) != 0; - case '&' : return (mFlags & AMP_OK) != 0; - case '%' : return (mFlags & PCT_OK) != 0; - case '\0': return (mFlags & NUL_OK) != 0; - default : return (c >= 32 && c < 127) || - ((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0)); - } - } - } - - /** - * Get the current value sanitizer used when processing - * unregistered parameter values. - * <p> - * <b>Note:</b> The default unregistered parameter value sanitizer is - * one that doesn't allow any special characters, similar to what - * is returned by calling createAllIllegal. - * - * @return the current ValueSanitizer used to sanitize unregistered - * parameter values. - */ - public ValueSanitizer getUnregisteredParameterValueSanitizer() { - return mUnregisteredParameterValueSanitizer; - } - - /** - * Set the value sanitizer used when processing unregistered - * parameter values. - * @param sanitizer set the ValueSanitizer used to sanitize unregistered - * parameter values. - */ - public void setUnregisteredParameterValueSanitizer( - ValueSanitizer sanitizer) { - mUnregisteredParameterValueSanitizer = sanitizer; - } - - - // Private fields for singleton sanitizers: - - private static final ValueSanitizer sAllIllegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.ALL_ILLEGAL); - - private static final ValueSanitizer sAllButNulLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL); - - private static final ValueSanitizer sAllButWhitespaceLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL); - - private static final ValueSanitizer sURLLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.URL_LEGAL); - - private static final ValueSanitizer sUrlAndSpaceLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL); - - private static final ValueSanitizer sAmpLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.AMP_LEGAL); - - private static final ValueSanitizer sAmpAndSpaceLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL); - - private static final ValueSanitizer sSpaceLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.SPACE_LEGAL); - - private static final ValueSanitizer sAllButNulAndAngleBracketsLegal = - new IllegalCharacterValueSanitizer( - IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL); - - /** - * Return a value sanitizer that does not allow any special characters, - * and also does not allow script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getAllIllegal() { - return sAllIllegal; - } - - /** - * Return a value sanitizer that allows everything except Nul ('\0') - * characters. Script URLs are allowed. - * @return a value sanitizer - */ - public static final ValueSanitizer getAllButNulLegal() { - return sAllButNulLegal; - } - /** - * Return a value sanitizer that allows everything except Nul ('\0') - * characters, space (' '), and other whitespace characters. - * Script URLs are allowed. - * @return a value sanitizer - */ - public static final ValueSanitizer getAllButWhitespaceLegal() { - return sAllButWhitespaceLegal; - } - /** - * Return a value sanitizer that allows all the characters used by - * encoded URLs. Does not allow script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getUrlLegal() { - return sURLLegal; - } - /** - * Return a value sanitizer that allows all the characters used by - * encoded URLs and allows spaces, which are not technically legal - * in encoded URLs, but commonly appear anyway. - * Does not allow script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getUrlAndSpaceLegal() { - return sUrlAndSpaceLegal; - } - /** - * Return a value sanitizer that does not allow any special characters - * except ampersand ('&'). Does not allow script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getAmpLegal() { - return sAmpLegal; - } - /** - * Return a value sanitizer that does not allow any special characters - * except ampersand ('&') and space (' '). Does not allow script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getAmpAndSpaceLegal() { - return sAmpAndSpaceLegal; - } - /** - * Return a value sanitizer that does not allow any special characters - * except space (' '). Does not allow script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getSpaceLegal() { - return sSpaceLegal; - } - /** - * Return a value sanitizer that allows any special characters - * except angle brackets ('<' and '>') and Nul ('\0'). - * Allows script URLs. - * @return a value sanitizer - */ - public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() { - return sAllButNulAndAngleBracketsLegal; - } - - /** - * Constructs a UrlQuerySanitizer. - * <p> - * Defaults: - * <ul> - * <li>unregistered parameters are not allowed. - * <li>the last instance of a repeated parameter is preferred. - * <li>The default value sanitizer is an AllIllegal value sanitizer. - * <ul> - */ - public UrlQuerySanitizer() { - } - - /** - * Constructs a UrlQuerySanitizer and parse a URL. - * This constructor is provided for convenience when the - * default parsing behavior is acceptable. - * <p> - * Because the URL is parsed before the constructor returns, there isn't - * a chance to configure the sanitizer to change the parsing behavior. - * <p> - * <code> - * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(myUrl); - * String name = sanitizer.getValue("name"); - * </code> - * <p> - * Defaults: - * <ul> - * <li>unregistered parameters <em>are</em> allowed. - * <li>the last instance of a repeated parameter is preferred. - * <li>The default value sanitizer is an AllIllegal value sanitizer. - * <ul> - */ - public UrlQuerySanitizer(String url) { - setAllowUnregisteredParamaters(true); - parseUrl(url); - } - - /** - * Parse the query parameters out of an encoded URL. - * Works by extracting the query portion from the URL and then - * calling parseQuery(). If there is no query portion it is - * treated as if the query portion is an empty string. - * @param url the encoded URL to parse. - */ - public void parseUrl(String url) { - int queryIndex = url.indexOf('?'); - String query; - if (queryIndex >= 0) { - query = url.substring(queryIndex + 1); - } - else { - query = ""; - } - parseQuery(query); - } - - /** - * Parse a query. A query string is any number of parameter-value clauses - * separated by any non-zero number of ampersands. A parameter-value clause - * is a parameter followed by an equal sign, followed by a value. If the - * equal sign is missing, the value is assumed to be the empty string. - * @param query the query to parse. - */ - public void parseQuery(String query) { - clear(); - // Split by '&' - StringTokenizer tokenizer = new StringTokenizer(query, "&"); - while(tokenizer.hasMoreElements()) { - String attributeValuePair = tokenizer.nextToken(); - if (attributeValuePair.length() > 0) { - int assignmentIndex = attributeValuePair.indexOf('='); - if (assignmentIndex < 0) { - // No assignment found, treat as if empty value - parseEntry(attributeValuePair, ""); - } - else { - parseEntry(attributeValuePair.substring(0, assignmentIndex), - attributeValuePair.substring(assignmentIndex + 1)); - } - } - } - } - - /** - * Get a set of all of the parameters found in the sanitized query. - * <p> - * Note: Do not modify this set. Treat it as a read-only set. - * @return all the parameters found in the current query. - */ - public Set<String> getParameterSet() { - return mEntries.keySet(); - } - - /** - * An array list of all of the parameter value pairs in the sanitized - * query, in the order they appeared in the query. May contain duplicate - * parameters. - * <p class="note"><b>Note:</b> Do not modify this list. Treat it as a read-only list.</p> - */ - public List<ParameterValuePair> getParameterList() { - return mEntriesList; - } - - /** - * Check if a parameter exists in the current sanitized query. - * @param parameter the unencoded name of a parameter. - * @return true if the paramater exists in the current sanitized queary. - */ - public boolean hasParameter(String parameter) { - return mEntries.containsKey(parameter); - } - - /** - * Get the value for a parameter in the current sanitized query. - * Returns null if the parameter does not - * exit. - * @param parameter the unencoded name of a parameter. - * @return the sanitized unencoded value of the parameter, - * or null if the parameter does not exist. - */ - public String getValue(String parameter) { - return mEntries.get(parameter); - } - - /** - * Register a value sanitizer for a particular parameter. Can also be used - * to replace or remove an already-set value sanitizer. - * <p> - * Registering a non-null value sanitizer for a particular parameter - * makes that parameter a registered parameter. - * @param parameter an unencoded parameter name - * @param valueSanitizer the value sanitizer to use for a particular - * parameter. May be null in order to unregister that parameter. - * @see #getAllowUnregisteredParamaters() - */ - public void registerParameter(String parameter, - ValueSanitizer valueSanitizer) { - if (valueSanitizer == null) { - mSanitizers.remove(parameter); - } - mSanitizers.put(parameter, valueSanitizer); - } - - /** - * Register a value sanitizer for an array of parameters. - * @param parameters An array of unencoded parameter names. - * @param valueSanitizer - * @see #registerParameter - */ - public void registerParameters(String[] parameters, - ValueSanitizer valueSanitizer) { - int length = parameters.length; - for(int i = 0; i < length; i++) { - mSanitizers.put(parameters[i], valueSanitizer); - } - } - - /** - * Set whether or not unregistered parameters are allowed. If they - * are not allowed, then they will be dropped when a query is sanitized. - * <p> - * Defaults to false. - * @param allowUnregisteredParamaters true to allow unregistered parameters. - * @see #getAllowUnregisteredParamaters() - */ - public void setAllowUnregisteredParamaters( - boolean allowUnregisteredParamaters) { - mAllowUnregisteredParamaters = allowUnregisteredParamaters; - } - - /** - * Get whether or not unregistered parameters are allowed. If not - * allowed, they will be dropped when a query is parsed. - * @return true if unregistered parameters are allowed. - * @see #setAllowUnregisteredParamaters(boolean) - */ - public boolean getAllowUnregisteredParamaters() { - return mAllowUnregisteredParamaters; - } - - /** - * Set whether or not the first occurrence of a repeated parameter is - * preferred. True means the first repeated parameter is preferred. - * False means that the last repeated parameter is preferred. - * <p> - * The preferred parameter is the one that is returned when getParameter - * is called. - * <p> - * defaults to false. - * @param preferFirstRepeatedParameter True if the first repeated - * parameter is preferred. - * @see #getPreferFirstRepeatedParameter() - */ - public void setPreferFirstRepeatedParameter( - boolean preferFirstRepeatedParameter) { - mPreferFirstRepeatedParameter = preferFirstRepeatedParameter; - } - - /** - * Get whether or not the first occurrence of a repeated parameter is - * preferred. - * @return true if the first occurrence of a repeated parameter is - * preferred. - * @see #setPreferFirstRepeatedParameter(boolean) - */ - public boolean getPreferFirstRepeatedParameter() { - return mPreferFirstRepeatedParameter; - } - - /** - * Parse an escaped parameter-value pair. The default implementation - * unescapes both the parameter and the value, then looks up the - * effective value sanitizer for the parameter and uses it to sanitize - * the value. If all goes well then addSanitizedValue is called with - * the unescaped parameter and the sanitized unescaped value. - * @param parameter an escaped parameter - * @param value an unsanitzied escaped value - */ - protected void parseEntry(String parameter, String value) { - String unescapedParameter = unescape(parameter); - ValueSanitizer valueSanitizer = - getEffectiveValueSanitizer(unescapedParameter); - - if (valueSanitizer == null) { - return; - } - String unescapedValue = unescape(value); - String sanitizedValue = valueSanitizer.sanitize(unescapedValue); - addSanitizedEntry(unescapedParameter, sanitizedValue); - } - - /** - * Record a sanitized parameter-value pair. Override if you want to - * do additional filtering or validation. - * @param parameter an unescaped parameter - * @param value a sanitized unescaped value - */ - protected void addSanitizedEntry(String parameter, String value) { - mEntriesList.add( - new ParameterValuePair(parameter, value)); - if (mPreferFirstRepeatedParameter) { - if (mEntries.containsKey(parameter)) { - return; - } - } - mEntries.put(parameter, value); - } - - /** - * Get the value sanitizer for a parameter. Returns null if there - * is no value sanitizer registered for the parameter. - * @param parameter the unescaped parameter - * @return the currently registered value sanitizer for this parameter. - * @see #registerParameter(String, android.net.UrlQuerySanitizer.ValueSanitizer) - */ - public ValueSanitizer getValueSanitizer(String parameter) { - return mSanitizers.get(parameter); - } - - /** - * Get the effective value sanitizer for a parameter. Like getValueSanitizer, - * except if there is no value sanitizer registered for a parameter, and - * unregistered paramaters are allowed, then the default value sanitizer is - * returned. - * @param parameter an unescaped parameter - * @return the effective value sanitizer for a parameter. - */ - public ValueSanitizer getEffectiveValueSanitizer(String parameter) { - ValueSanitizer sanitizer = getValueSanitizer(parameter); - if (sanitizer == null && mAllowUnregisteredParamaters) { - sanitizer = getUnregisteredParameterValueSanitizer(); - } - return sanitizer; - } - - /** - * Unescape an escaped string. - * <ul> - * <li>'+' characters are replaced by - * ' ' characters. - * <li>Valid "%xx" escape sequences are replaced by the - * corresponding unescaped character. - * <li>Invalid escape sequences such as %1z", are passed through unchanged. - * <ol> - * @param string the escaped string - * @return the unescaped string. - */ - public String unescape(String string) { - // Early exit if no escaped characters. - int firstEscape = string.indexOf('%'); - if ( firstEscape < 0) { - firstEscape = string.indexOf('+'); - if (firstEscape < 0) { - return string; - } - } - - int length = string.length(); - - StringBuilder stringBuilder = new StringBuilder(length); - stringBuilder.append(string.substring(0, firstEscape)); - for (int i = firstEscape; i < length; i++) { - char c = string.charAt(i); - if (c == '+') { - c = ' '; - } - else if ( c == '%' && i + 2 < length) { - char c1 = string.charAt(i + 1); - char c2 = string.charAt(i + 2); - if (isHexDigit(c1) && isHexDigit(c2)) { - c = (char) (decodeHexDigit(c1) * 16 + decodeHexDigit(c2)); - i += 2; - } - } - stringBuilder.append(c); - } - return stringBuilder.toString(); - } - - /** - * Test if a character is a hexidecimal digit. Both upper case and lower - * case hex digits are allowed. - * @param c the character to test - * @return true if c is a hex digit. - */ - protected boolean isHexDigit(char c) { - return decodeHexDigit(c) >= 0; - } - - /** - * Convert a character that represents a hexidecimal digit into an integer. - * If the character is not a hexidecimal digit, then -1 is returned. - * Both upper case and lower case hex digits are allowed. - * @param c the hexidecimal digit. - * @return the integer value of the hexidecimal digit. - */ - - protected int decodeHexDigit(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - else if (c >= 'A' && c <= 'F') { - return c - 'A' + 10; - } - else if (c >= 'a' && c <= 'f') { - return c - 'a' + 10; - } - else { - return -1; - } - } - - /** - * Clear the existing entries. Called to get ready to parse a new - * query string. - */ - protected void clear() { - mEntries.clear(); - mEntriesList.clear(); - } -} - diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java deleted file mode 100644 index f4a2a6a..0000000 --- a/core/java/android/net/WebAddress.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * {@hide} - * - * Web Address Parser - * - * This is called WebAddress, rather than URL or URI, because it - * attempts to parse the stuff that a user will actually type into a - * browser address widget. - * - * Unlike java.net.uri, this parser will not choke on URIs missing - * schemes. It will only throw a ParseException if the input is - * really hosed. - * - * If given an https scheme but no port, fills in port - * - */ -public class WebAddress { - - private final static String LOGTAG = "http"; - - public String mScheme; - public String mHost; - public int mPort; - public String mPath; - public String mAuthInfo; - - static final int MATCH_GROUP_SCHEME = 1; - static final int MATCH_GROUP_AUTHORITY = 2; - static final int MATCH_GROUP_HOST = 3; - static final int MATCH_GROUP_PORT = 4; - static final int MATCH_GROUP_PATH = 5; - - static Pattern sAddressPattern = Pattern.compile( - /* scheme */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" + - /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" + - /* host */ "([-A-Za-z0-9%]+(?:\\.[-A-Za-z0-9%]+)*)?" + - /* port */ "(?:\\:([0-9]+))?" + - /* path */ "(\\/?.*)?"); - - /** parses given uriString. */ - public WebAddress(String address) throws ParseException { - if (address == null) { - throw new NullPointerException(); - } - - // android.util.Log.d(LOGTAG, "WebAddress: " + address); - - mScheme = ""; - mHost = ""; - mPort = -1; - mPath = "/"; - mAuthInfo = ""; - - Matcher m = sAddressPattern.matcher(address); - String t; - if (m.matches()) { - t = m.group(MATCH_GROUP_SCHEME); - if (t != null) mScheme = t; - t = m.group(MATCH_GROUP_AUTHORITY); - if (t != null) mAuthInfo = t; - t = m.group(MATCH_GROUP_HOST); - if (t != null) mHost = t; - t = m.group(MATCH_GROUP_PORT); - if (t != null) { - try { - mPort = Integer.parseInt(t); - } catch (NumberFormatException ex) { - throw new ParseException("Bad port"); - } - } - t = m.group(MATCH_GROUP_PATH); - if (t != null && t.length() > 0) { - /* handle busted myspace frontpage redirect with - missing initial "/" */ - if (t.charAt(0) == '/') { - mPath = t; - } else { - mPath = "/" + t; - } - } - - } else { - // nothing found... outa here - throw new ParseException("Bad address"); - } - - /* Get port from scheme or scheme from port, if necessary and - possible */ - if (mPort == 443 && mScheme.equals("")) { - mScheme = "https"; - } else if (mPort == -1) { - if (mScheme.equals("https")) - mPort = 443; - else - mPort = 80; // default - } - if (mScheme.equals("")) mScheme = "http"; - } - - public String toString() { - String port = ""; - if ((mPort != 443 && mScheme.equals("https")) || - (mPort != 80 && mScheme.equals("http"))) { - port = ":" + Integer.toString(mPort); - } - String authInfo = ""; - if (mAuthInfo.length() > 0) { - authInfo = mAuthInfo + "@"; - } - - return mScheme + "://" + authInfo + mHost + port + mPath; - } -} diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java deleted file mode 100644 index 4fb1499..0000000 --- a/core/java/android/net/http/AndroidHttpClient.java +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponse; -import org.apache.http.entity.AbstractHttpEntity; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.client.HttpClient; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.params.HttpClientParams; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.RequestWrapper; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.BasicHttpProcessor; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.BasicHttpContext; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; -import java.net.URI; - -import android.util.Log; -import android.content.ContentResolver; -import android.provider.Settings; -import android.text.TextUtils; - -/** - * Subclass of the Apache {@link DefaultHttpClient} that is configured with - * reasonable default settings and registered schemes for Android, and - * also lets the user add {@link HttpRequestInterceptor} classes. - * Don't create this directly, use the {@link #newInstance} factory method. - * - * <p>This client processes cookies but does not retain them by default. - * To retain cookies, simply add a cookie store to the HttpContext:</p> - * - * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre> - * - * {@hide} - */ -public final class AndroidHttpClient implements HttpClient { - - // Gzip of data shorter than this probably won't be worthwhile - public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256; - - private static final String TAG = "AndroidHttpClient"; - - - /** Set if HTTP requests are blocked from being executed on this thread */ - private static final ThreadLocal<Boolean> sThreadBlocked = - new ThreadLocal<Boolean>(); - - /** Interceptor throws an exception if the executing thread is blocked */ - private static final HttpRequestInterceptor sThreadCheckInterceptor = - new HttpRequestInterceptor() { - public void process(HttpRequest request, HttpContext context) { - if (sThreadBlocked.get() != null && sThreadBlocked.get()) { - throw new RuntimeException("This thread forbids HTTP requests"); - } - } - }; - - /** - * Create a new HttpClient with reasonable defaults (which you can update). - * @param userAgent to report in your HTTP requests. - * @return AndroidHttpClient for you to use for all your requests. - */ - public static AndroidHttpClient newInstance(String userAgent) { - HttpParams params = new BasicHttpParams(); - - // Turn off stale checking. Our connections break all the time anyway, - // and it's not worth it to pay the penalty of checking every time. - HttpConnectionParams.setStaleCheckingEnabled(params, false); - - // Default connection and socket timeout of 20 seconds. Tweak to taste. - HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); - HttpConnectionParams.setSoTimeout(params, 20 * 1000); - HttpConnectionParams.setSocketBufferSize(params, 8192); - - // Don't handle redirects -- return them to the caller. Our code - // often wants to re-POST after a redirect, which we must do ourselves. - HttpClientParams.setRedirecting(params, false); - - // Set the specified user agent and register standard protocols. - HttpProtocolParams.setUserAgent(params, userAgent); - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(new Scheme("http", - PlainSocketFactory.getSocketFactory(), 80)); - schemeRegistry.register(new Scheme("https", - SSLSocketFactory.getSocketFactory(), 443)); - ClientConnectionManager manager = - new ThreadSafeClientConnManager(params, schemeRegistry); - - // We use a factory method to modify superclass initialization - // parameters without the funny call-a-static-method dance. - return new AndroidHttpClient(manager, params); - } - - private final HttpClient delegate; - - private RuntimeException mLeakedException = new IllegalStateException( - "AndroidHttpClient created and never closed"); - - private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) { - this.delegate = new DefaultHttpClient(ccm, params) { - @Override - protected BasicHttpProcessor createHttpProcessor() { - // Add interceptor to prevent making requests from main thread. - BasicHttpProcessor processor = super.createHttpProcessor(); - processor.addRequestInterceptor(sThreadCheckInterceptor); - processor.addRequestInterceptor(new CurlLogger()); - - return processor; - } - - @Override - protected HttpContext createHttpContext() { - // Same as DefaultHttpClient.createHttpContext() minus the - // cookie store. - HttpContext context = new BasicHttpContext(); - context.setAttribute( - ClientContext.AUTHSCHEME_REGISTRY, - getAuthSchemes()); - context.setAttribute( - ClientContext.COOKIESPEC_REGISTRY, - getCookieSpecs()); - context.setAttribute( - ClientContext.CREDS_PROVIDER, - getCredentialsProvider()); - return context; - } - }; - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - if (mLeakedException != null) { - Log.e(TAG, "Leak found", mLeakedException); - mLeakedException = null; - } - } - - /** - * Block this thread from executing HTTP requests. - * Used to guard against HTTP requests blocking the main application thread. - * @param blocked if HTTP requests run on this thread should be denied - */ - public static void setThreadBlocked(boolean blocked) { - sThreadBlocked.set(blocked); - } - - /** - * Modifies a request to indicate to the server that we would like a - * gzipped response. (Uses the "Accept-Encoding" HTTP header.) - * @param request the request to modify - * @see #getUngzippedContent - */ - public static void modifyRequestToAcceptGzipResponse(HttpRequest request) { - request.addHeader("Accept-Encoding", "gzip"); - } - - /** - * Gets the input stream from a response entity. If the entity is gzipped - * then this will get a stream over the uncompressed data. - * - * @param entity the entity whose content should be read - * @return the input stream to read from - * @throws IOException - */ - public static InputStream getUngzippedContent(HttpEntity entity) - throws IOException { - InputStream responseStream = entity.getContent(); - if (responseStream == null) return responseStream; - Header header = entity.getContentEncoding(); - if (header == null) return responseStream; - String contentEncoding = header.getValue(); - if (contentEncoding == null) return responseStream; - if (contentEncoding.contains("gzip")) responseStream - = new GZIPInputStream(responseStream); - return responseStream; - } - - /** - * Release resources associated with this client. You must call this, - * or significant resources (sockets and memory) may be leaked. - */ - public void close() { - if (mLeakedException != null) { - getConnectionManager().shutdown(); - mLeakedException = null; - } - } - - public HttpParams getParams() { - return delegate.getParams(); - } - - public ClientConnectionManager getConnectionManager() { - return delegate.getConnectionManager(); - } - - public HttpResponse execute(HttpUriRequest request) throws IOException { - return delegate.execute(request); - } - - public HttpResponse execute(HttpUriRequest request, HttpContext context) - throws IOException { - return delegate.execute(request, context); - } - - public HttpResponse execute(HttpHost target, HttpRequest request) - throws IOException { - return delegate.execute(target, request); - } - - public HttpResponse execute(HttpHost target, HttpRequest request, - HttpContext context) throws IOException { - return delegate.execute(target, request, context); - } - - public <T> T execute(HttpUriRequest request, - ResponseHandler<? extends T> responseHandler) - throws IOException, ClientProtocolException { - return delegate.execute(request, responseHandler); - } - - public <T> T execute(HttpUriRequest request, - ResponseHandler<? extends T> responseHandler, HttpContext context) - throws IOException, ClientProtocolException { - return delegate.execute(request, responseHandler, context); - } - - public <T> T execute(HttpHost target, HttpRequest request, - ResponseHandler<? extends T> responseHandler) throws IOException, - ClientProtocolException { - return delegate.execute(target, request, responseHandler); - } - - public <T> T execute(HttpHost target, HttpRequest request, - ResponseHandler<? extends T> responseHandler, HttpContext context) - throws IOException, ClientProtocolException { - return delegate.execute(target, request, responseHandler, context); - } - - /** - * Compress data to send to server. - * Creates a Http Entity holding the gzipped data. - * The data will not be compressed if it is too short. - * @param data The bytes to compress - * @return Entity holding the data - */ - public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver) - throws IOException { - AbstractHttpEntity entity; - if (data.length < getMinGzipSize(resolver)) { - entity = new ByteArrayEntity(data); - } else { - ByteArrayOutputStream arr = new ByteArrayOutputStream(); - OutputStream zipper = new GZIPOutputStream(arr); - zipper.write(data); - zipper.close(); - entity = new ByteArrayEntity(arr.toByteArray()); - entity.setContentEncoding("gzip"); - } - return entity; - } - - /** - * Retrieves the minimum size for compressing data. - * Shorter data will not be compressed. - */ - public static long getMinGzipSize(ContentResolver resolver) { - String sMinGzipBytes = Settings.Gservices.getString(resolver, - Settings.Gservices.SYNC_MIN_GZIP_BYTES); - - if (!TextUtils.isEmpty(sMinGzipBytes)) { - try { - return Long.parseLong(sMinGzipBytes); - } catch (NumberFormatException nfe) { - Log.w(TAG, "Unable to parse " + - Settings.Gservices.SYNC_MIN_GZIP_BYTES + " " + - sMinGzipBytes, nfe); - } - } - return DEFAULT_SYNC_MIN_GZIP_BYTES; - } - - /* cURL logging support. */ - - /** - * Logging tag and level. - */ - private static class LoggingConfiguration { - - private final String tag; - private final int level; - - private LoggingConfiguration(String tag, int level) { - this.tag = tag; - this.level = level; - } - - /** - * Returns true if logging is turned on for this configuration. - */ - private boolean isLoggable() { - return Log.isLoggable(tag, level); - } - - /** - * Returns true if auth logging is turned on for this configuration. - */ - private boolean isAuthLoggable() { - return Log.isLoggable(tag + "-auth", level); - } - - /** - * Prints a message using this configuration. - */ - private void println(String message) { - Log.println(level, tag, message); - } - } - - /** cURL logging configuration. */ - private volatile LoggingConfiguration curlConfiguration; - - /** - * Enables cURL request logging for this client. - * - * @param name to log messages with - * @param level at which to log messages (see {@link android.util.Log}) - */ - public void enableCurlLogging(String name, int level) { - if (name == null) { - throw new NullPointerException("name"); - } - if (level < Log.VERBOSE || level > Log.ASSERT) { - throw new IllegalArgumentException("Level is out of range [" - + Log.VERBOSE + ".." + Log.ASSERT + "]"); - } - - curlConfiguration = new LoggingConfiguration(name, level); - } - - /** - * Disables cURL logging for this client. - */ - public void disableCurlLogging() { - curlConfiguration = null; - } - - /** - * Logs cURL commands equivalent to requests. - */ - private class CurlLogger implements HttpRequestInterceptor { - public void process(HttpRequest request, HttpContext context) - throws HttpException, IOException { - LoggingConfiguration configuration = curlConfiguration; - if (configuration != null - && configuration.isLoggable() - && request instanceof HttpUriRequest) { - configuration.println(toCurl((HttpUriRequest) request, - configuration.isAuthLoggable())); - } - } - } - - /** - * Generates a cURL command equivalent to the given request. - */ - private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException { - StringBuilder builder = new StringBuilder(); - - builder.append("curl "); - - for (Header header: request.getAllHeaders()) { - if (!logAuthToken - && (header.getName().equals("Authorization") || - header.getName().equals("Cookie"))) { - continue; - } - builder.append("--header \""); - builder.append(header.toString().trim()); - builder.append("\" "); - } - - URI uri = request.getURI(); - - // If this is a wrapped request, use the URI from the original - // request instead. getURI() on the wrapper seems to return a - // relative URI. We want an absolute URI. - if (request instanceof RequestWrapper) { - HttpRequest original = ((RequestWrapper) request).getOriginal(); - if (original instanceof HttpUriRequest) { - uri = ((HttpUriRequest) original).getURI(); - } - } - - builder.append("\""); - builder.append(uri); - builder.append("\""); - - if (request instanceof HttpEntityEnclosingRequest) { - HttpEntityEnclosingRequest entityRequest = - (HttpEntityEnclosingRequest) request; - HttpEntity entity = entityRequest.getEntity(); - if (entity != null && entity.isRepeatable()) { - if (entity.getContentLength() < 1024) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - entity.writeTo(stream); - String entityString = stream.toString(); - - // TODO: Check the content type, too. - builder.append(" --data-ascii \"") - .append(entityString) - .append("\""); - } else { - builder.append(" [TOO MUCH DATA TO INCLUDE]"); - } - } - } - - return builder.toString(); - } -} diff --git a/core/java/android/net/http/AndroidHttpClientConnection.java b/core/java/android/net/http/AndroidHttpClientConnection.java deleted file mode 100644 index eb96679..0000000 --- a/core/java/android/net/http/AndroidHttpClientConnection.java +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import org.apache.http.Header; - -import org.apache.http.HttpConnection; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpConnectionMetrics; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpException; -import org.apache.http.HttpInetConnection; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpResponseFactory; -import org.apache.http.NoHttpResponseException; -import org.apache.http.StatusLine; -import org.apache.http.entity.BasicHttpEntity; -import org.apache.http.entity.ContentLengthStrategy; -import org.apache.http.impl.DefaultHttpResponseFactory; -import org.apache.http.impl.HttpConnectionMetricsImpl; -import org.apache.http.impl.entity.EntitySerializer; -import org.apache.http.impl.entity.StrictContentLengthStrategy; -import org.apache.http.impl.io.ChunkedInputStream; -import org.apache.http.impl.io.ContentLengthInputStream; -import org.apache.http.impl.io.HttpRequestWriter; -import org.apache.http.impl.io.IdentityInputStream; -import org.apache.http.impl.io.SocketInputBuffer; -import org.apache.http.impl.io.SocketOutputBuffer; -import org.apache.http.io.HttpMessageWriter; -import org.apache.http.io.SessionInputBuffer; -import org.apache.http.io.SessionOutputBuffer; -import org.apache.http.message.BasicLineParser; -import org.apache.http.message.ParserCursor; -import org.apache.http.params.CoreConnectionPNames; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.ParseException; -import org.apache.http.util.CharArrayBuffer; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; - -/** - * A alternate class for (@link DefaultHttpClientConnection). - * It has better performance than DefaultHttpClientConnection - * - * {@hide} - */ -public class AndroidHttpClientConnection - implements HttpInetConnection, HttpConnection { - - private SessionInputBuffer inbuffer = null; - private SessionOutputBuffer outbuffer = null; - private int maxHeaderCount; - // store CoreConnectionPNames.MAX_LINE_LENGTH for performance - private int maxLineLength; - - private final EntitySerializer entityserializer; - - private HttpMessageWriter requestWriter = null; - private HttpConnectionMetricsImpl metrics = null; - private volatile boolean open; - private Socket socket = null; - - public AndroidHttpClientConnection() { - this.entityserializer = new EntitySerializer( - new StrictContentLengthStrategy()); - } - - /** - * Bind socket and set HttpParams to AndroidHttpClientConnection - * @param socket outgoing socket - * @param params HttpParams - * @throws IOException - */ - public void bind( - final Socket socket, - final HttpParams params) throws IOException { - if (socket == null) { - throw new IllegalArgumentException("Socket may not be null"); - } - if (params == null) { - throw new IllegalArgumentException("HTTP parameters may not be null"); - } - assertNotOpen(); - socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params)); - socket.setSoTimeout(HttpConnectionParams.getSoTimeout(params)); - - int linger = HttpConnectionParams.getLinger(params); - if (linger >= 0) { - socket.setSoLinger(linger > 0, linger); - } - this.socket = socket; - - int buffersize = HttpConnectionParams.getSocketBufferSize(params); - this.inbuffer = new SocketInputBuffer(socket, buffersize, params); - this.outbuffer = new SocketOutputBuffer(socket, buffersize, params); - - maxHeaderCount = params.getIntParameter( - CoreConnectionPNames.MAX_HEADER_COUNT, -1); - maxLineLength = params.getIntParameter( - CoreConnectionPNames.MAX_LINE_LENGTH, -1); - - this.requestWriter = new HttpRequestWriter(outbuffer, null, params); - - this.metrics = new HttpConnectionMetricsImpl( - inbuffer.getMetrics(), - outbuffer.getMetrics()); - - this.open = true; - } - - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(); - buffer.append(getClass().getSimpleName()).append("["); - if (isOpen()) { - buffer.append(getRemotePort()); - } else { - buffer.append("closed"); - } - buffer.append("]"); - return buffer.toString(); - } - - - private void assertNotOpen() { - if (this.open) { - throw new IllegalStateException("Connection is already open"); - } - } - - private void assertOpen() { - if (!this.open) { - throw new IllegalStateException("Connection is not open"); - } - } - - public boolean isOpen() { - // to make this method useful, we want to check if the socket is connected - return (this.open && this.socket != null && this.socket.isConnected()); - } - - public InetAddress getLocalAddress() { - if (this.socket != null) { - return this.socket.getLocalAddress(); - } else { - return null; - } - } - - public int getLocalPort() { - if (this.socket != null) { - return this.socket.getLocalPort(); - } else { - return -1; - } - } - - public InetAddress getRemoteAddress() { - if (this.socket != null) { - return this.socket.getInetAddress(); - } else { - return null; - } - } - - public int getRemotePort() { - if (this.socket != null) { - return this.socket.getPort(); - } else { - return -1; - } - } - - public void setSocketTimeout(int timeout) { - assertOpen(); - if (this.socket != null) { - try { - this.socket.setSoTimeout(timeout); - } catch (SocketException ignore) { - // It is not quite clear from the original documentation if there are any - // other legitimate cases for a socket exception to be thrown when setting - // SO_TIMEOUT besides the socket being already closed - } - } - } - - public int getSocketTimeout() { - if (this.socket != null) { - try { - return this.socket.getSoTimeout(); - } catch (SocketException ignore) { - return -1; - } - } else { - return -1; - } - } - - public void shutdown() throws IOException { - this.open = false; - Socket tmpsocket = this.socket; - if (tmpsocket != null) { - tmpsocket.close(); - } - } - - public void close() throws IOException { - if (!this.open) { - return; - } - this.open = false; - doFlush(); - try { - try { - this.socket.shutdownOutput(); - } catch (IOException ignore) { - } - try { - this.socket.shutdownInput(); - } catch (IOException ignore) { - } - } catch (UnsupportedOperationException ignore) { - // if one isn't supported, the other one isn't either - } - this.socket.close(); - } - - /** - * Sends the request line and all headers over the connection. - * @param request the request whose headers to send. - * @throws HttpException - * @throws IOException - */ - public void sendRequestHeader(final HttpRequest request) - throws HttpException, IOException { - if (request == null) { - throw new IllegalArgumentException("HTTP request may not be null"); - } - assertOpen(); - this.requestWriter.write(request); - this.metrics.incrementRequestCount(); - } - - /** - * Sends the request entity over the connection. - * @param request the request whose entity to send. - * @throws HttpException - * @throws IOException - */ - public void sendRequestEntity(final HttpEntityEnclosingRequest request) - throws HttpException, IOException { - if (request == null) { - throw new IllegalArgumentException("HTTP request may not be null"); - } - assertOpen(); - if (request.getEntity() == null) { - return; - } - this.entityserializer.serialize( - this.outbuffer, - request, - request.getEntity()); - } - - protected void doFlush() throws IOException { - this.outbuffer.flush(); - } - - public void flush() throws IOException { - assertOpen(); - doFlush(); - } - - /** - * Parses the response headers and adds them to the - * given {@code headers} object, and returns the response StatusLine - * @param headers store parsed header to headers. - * @throws IOException - * @return StatusLine - * @see HttpClientConnection#receiveResponseHeader() - */ - public StatusLine parseResponseHeader(Headers headers) - throws IOException, ParseException { - assertOpen(); - - CharArrayBuffer current = new CharArrayBuffer(64); - - if (inbuffer.readLine(current) == -1) { - throw new NoHttpResponseException("The target server failed to respond"); - } - - // Create the status line from the status string - StatusLine statusline = BasicLineParser.DEFAULT.parseStatusLine( - current, new ParserCursor(0, current.length())); - - if (HttpLog.LOGV) HttpLog.v("read: " + statusline); - int statusCode = statusline.getStatusCode(); - - // Parse header body - CharArrayBuffer previous = null; - int headerNumber = 0; - while(true) { - if (current == null) { - current = new CharArrayBuffer(64); - } else { - // This must be he buffer used to parse the status - current.clear(); - } - int l = inbuffer.readLine(current); - if (l == -1 || current.length() < 1) { - break; - } - // Parse the header name and value - // Check for folded headers first - // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 - // discussion on folded headers - char first = current.charAt(0); - if ((first == ' ' || first == '\t') && previous != null) { - // we have continuation folded header - // so append value - int start = 0; - int length = current.length(); - while (start < length) { - char ch = current.charAt(start); - if (ch != ' ' && ch != '\t') { - break; - } - start++; - } - if (maxLineLength > 0 && - previous.length() + 1 + current.length() - start > - maxLineLength) { - throw new IOException("Maximum line length limit exceeded"); - } - previous.append(' '); - previous.append(current, start, current.length() - start); - } else { - if (previous != null) { - headers.parseHeader(previous); - } - headerNumber++; - previous = current; - current = null; - } - if (maxHeaderCount > 0 && headerNumber >= maxHeaderCount) { - throw new IOException("Maximum header count exceeded"); - } - } - - if (previous != null) { - headers.parseHeader(previous); - } - - if (statusCode >= 200) { - this.metrics.incrementResponseCount(); - } - return statusline; - } - - /** - * Return the next response entity. - * @param headers contains values for parsing entity - * @see HttpClientConnection#receiveResponseEntity(HttpResponse response) - */ - public HttpEntity receiveResponseEntity(final Headers headers) { - assertOpen(); - BasicHttpEntity entity = new BasicHttpEntity(); - - long len = determineLength(headers); - if (len == ContentLengthStrategy.CHUNKED) { - entity.setChunked(true); - entity.setContentLength(-1); - entity.setContent(new ChunkedInputStream(inbuffer)); - } else if (len == ContentLengthStrategy.IDENTITY) { - entity.setChunked(false); - entity.setContentLength(-1); - entity.setContent(new IdentityInputStream(inbuffer)); - } else { - entity.setChunked(false); - entity.setContentLength(len); - entity.setContent(new ContentLengthInputStream(inbuffer, len)); - } - - String contentTypeHeader = headers.getContentType(); - if (contentTypeHeader != null) { - entity.setContentType(contentTypeHeader); - } - String contentEncodingHeader = headers.getContentEncoding(); - if (contentEncodingHeader != null) { - entity.setContentEncoding(contentEncodingHeader); - } - - return entity; - } - - private long determineLength(final Headers headers) { - long transferEncoding = headers.getTransferEncoding(); - // We use Transfer-Encoding if present and ignore Content-Length. - // RFC2616, 4.4 item number 3 - if (transferEncoding < Headers.NO_TRANSFER_ENCODING) { - return transferEncoding; - } else { - long contentlen = headers.getContentLength(); - if (contentlen > Headers.NO_CONTENT_LENGTH) { - return contentlen; - } else { - return ContentLengthStrategy.IDENTITY; - } - } - } - - /** - * Checks whether this connection has gone down. - * Network connections may get closed during some time of inactivity - * for several reasons. The next time a read is attempted on such a - * connection it will throw an IOException. - * This method tries to alleviate this inconvenience by trying to - * find out if a connection is still usable. Implementations may do - * that by attempting a read with a very small timeout. Thus this - * method may block for a small amount of time before returning a result. - * It is therefore an <i>expensive</i> operation. - * - * @return <code>true</code> if attempts to use this connection are - * likely to succeed, or <code>false</code> if they are likely - * to fail and this connection should be closed - */ - public boolean isStale() { - assertOpen(); - try { - this.inbuffer.isDataAvailable(1); - return false; - } catch (IOException ex) { - return true; - } - } - - /** - * Returns a collection of connection metrcis - * @return HttpConnectionMetrics - */ - public HttpConnectionMetrics getMetrics() { - return this.metrics; - } -} diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java deleted file mode 100644 index b7f7368..0000000 --- a/core/java/android/net/http/CertificateChainValidator.java +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.os.SystemClock; - -import java.io.IOException; - -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.security.GeneralSecurityException; -import java.security.KeyStore; - -import java.util.Arrays; -import java.util.Date; -import java.util.Enumeration; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import org.apache.http.HttpHost; - -import org.bouncycastle.asn1.x509.X509Name; - -/** - * Class responsible for all server certificate validation functionality - * - * {@hide} - */ -class CertificateChainValidator { - - private static long sTotal = 0; - private static long sTotalReused = 0; - - /** - * The singleton instance of the certificate chain validator - */ - private static CertificateChainValidator sInstance; - - /** - * Default trust manager (used to perform CA certificate validation) - */ - private X509TrustManager mDefaultTrustManager; - - /** - * @return The singleton instance of the certificator chain validator - */ - public static CertificateChainValidator getInstance() { - if (sInstance == null) { - sInstance = new CertificateChainValidator(); - } - - return sInstance; - } - - /** - * Creates a new certificate chain validator. This is a pivate constructor. - * If you need a Certificate chain validator, call getInstance(). - */ - private CertificateChainValidator() { - try { - TrustManagerFactory trustManagerFactory - = TrustManagerFactory.getInstance("X509"); - trustManagerFactory.init((KeyStore)null); - TrustManager[] trustManagers = - trustManagerFactory.getTrustManagers(); - if (trustManagers != null && trustManagers.length > 0) { - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509TrustManager) { - mDefaultTrustManager = (X509TrustManager)(trustManager); - break; - } - } - } - } catch (Exception exc) { - if (HttpLog.LOGV) { - HttpLog.v("CertificateChainValidator():" + - " failed to initialize the trust manager"); - } - } - } - - /** - * Performs the handshake and server certificates validation - * @param sslSocket The secure connection socket - * @param domain The website domain - * @return An SSL error object if there is an error and null otherwise - */ - public SslError doHandshakeAndValidateServerCertificates( - HttpsConnection connection, SSLSocket sslSocket, String domain) - throws SSLHandshakeException, IOException { - - ++sTotal; - - SSLContext sslContext = HttpsConnection.getContext(); - if (sslContext == null) { - closeSocketThrowException(sslSocket, "SSL context is null"); - } - - X509Certificate[] serverCertificates = null; - - long sessionBeforeHandshakeLastAccessedTime = 0; - byte[] sessionBeforeHandshakeId = null; - - SSLSession sessionAfterHandshake = null; - - synchronized(sslContext) { - // get SSL session before the handshake - SSLSession sessionBeforeHandshake = - getSSLSession(sslContext, connection.getHost()); - if (sessionBeforeHandshake != null) { - sessionBeforeHandshakeLastAccessedTime = - sessionBeforeHandshake.getLastAccessedTime(); - - sessionBeforeHandshakeId = - sessionBeforeHandshake.getId(); - } - - // start handshake, close the socket if we fail - try { - sslSocket.setUseClientMode(true); - sslSocket.startHandshake(); - } catch (IOException e) { - closeSocketThrowException( - sslSocket, e.getMessage(), - "failed to perform SSL handshake"); - } - - // retrieve the chain of the server peer certificates - Certificate[] peerCertificates = - sslSocket.getSession().getPeerCertificates(); - - if (peerCertificates == null || peerCertificates.length <= 0) { - closeSocketThrowException( - sslSocket, "failed to retrieve peer certificates"); - } else { - serverCertificates = - new X509Certificate[peerCertificates.length]; - for (int i = 0; i < peerCertificates.length; ++i) { - serverCertificates[i] = - (X509Certificate)(peerCertificates[i]); - } - - // update the SSL certificate associated with the connection - if (connection != null) { - if (serverCertificates[0] != null) { - connection.setCertificate( - new SslCertificate(serverCertificates[0])); - } - } - } - - // get SSL session after the handshake - sessionAfterHandshake = - getSSLSession(sslContext, connection.getHost()); - } - - if (sessionBeforeHandshakeLastAccessedTime != 0 && - sessionAfterHandshake != null && - Arrays.equals( - sessionBeforeHandshakeId, sessionAfterHandshake.getId()) && - sessionBeforeHandshakeLastAccessedTime < - sessionAfterHandshake.getLastAccessedTime()) { - - if (HttpLog.LOGV) { - HttpLog.v("SSL session was reused: total reused: " - + sTotalReused - + " out of total of: " + sTotal); - - ++sTotalReused; - } - - // no errors!!! - return null; - } - - // check if the first certificate in the chain is for this site - X509Certificate currCertificate = serverCertificates[0]; - if (currCertificate == null) { - closeSocketThrowException( - sslSocket, "certificate for this site is null"); - } else { - if (!DomainNameChecker.match(currCertificate, domain)) { - String errorMessage = "certificate not for this host: " + domain; - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - sslSocket.getSession().invalidate(); - return new SslError( - SslError.SSL_IDMISMATCH, currCertificate); - } - } - - // - // first, we validate the chain using the standard validation - // solution; if we do not find any errors, we are done; if we - // fail the standard validation, we re-validate again below, - // this time trying to retrieve any individual errors we can - // report back to the user. - // - try { - synchronized (mDefaultTrustManager) { - mDefaultTrustManager.checkServerTrusted( - serverCertificates, "RSA"); - - // no errors!!! - return null; - } - } catch (CertificateException e) { - if (HttpLog.LOGV) { - HttpLog.v( - "failed to pre-validate the certificate chain, error: " + - e.getMessage()); - } - } - - sslSocket.getSession().invalidate(); - - SslError error = null; - - // we check the root certificate separately from the rest of the - // chain; this is because we need to know what certificate in - // the chain resulted in an error if any - currCertificate = - serverCertificates[serverCertificates.length - 1]; - if (currCertificate == null) { - closeSocketThrowException( - sslSocket, "root certificate is null"); - } - - // check if the last certificate in the chain (root) is trusted - X509Certificate[] rootCertificateChain = { currCertificate }; - try { - synchronized (mDefaultTrustManager) { - mDefaultTrustManager.checkServerTrusted( - rootCertificateChain, "RSA"); - } - } catch (CertificateExpiredException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "root certificate has expired"; - } - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - error = new SslError( - SslError.SSL_EXPIRED, currCertificate); - } catch (CertificateNotYetValidException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "root certificate not valid yet"; - } - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - error = new SslError( - SslError.SSL_NOTYETVALID, currCertificate); - } catch (CertificateException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "root certificate not trusted"; - } - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - return new SslError( - SslError.SSL_UNTRUSTED, currCertificate); - } - - // Then go through the certificate chain checking that each - // certificate trusts the next and that each certificate is - // within its valid date range. Walk the chain in the order - // from the CA to the end-user - X509Certificate prevCertificate = - serverCertificates[serverCertificates.length - 1]; - - for (int i = serverCertificates.length - 2; i >= 0; --i) { - currCertificate = serverCertificates[i]; - - // if a certificate is null, we cannot verify the chain - if (currCertificate == null) { - closeSocketThrowException( - sslSocket, "null certificate in the chain"); - } - - // verify if trusted by chain - if (!prevCertificate.getSubjectDN().equals( - currCertificate.getIssuerDN())) { - String errorMessage = "not trusted by chain"; - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - return new SslError( - SslError.SSL_UNTRUSTED, currCertificate); - } - - try { - currCertificate.verify(prevCertificate.getPublicKey()); - } catch (GeneralSecurityException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "not trusted by chain"; - } - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - return new SslError( - SslError.SSL_UNTRUSTED, currCertificate); - } - - // verify if the dates are valid - try { - currCertificate.checkValidity(); - } catch (CertificateExpiredException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "certificate expired"; - } - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - if (error == null || - error.getPrimaryError() < SslError.SSL_EXPIRED) { - error = new SslError( - SslError.SSL_EXPIRED, currCertificate); - } - } catch (CertificateNotYetValidException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "certificate not valid yet"; - } - - if (HttpLog.LOGV) { - HttpLog.v(errorMessage); - } - - if (error == null || - error.getPrimaryError() < SslError.SSL_NOTYETVALID) { - error = new SslError( - SslError.SSL_NOTYETVALID, currCertificate); - } - } - - prevCertificate = currCertificate; - } - - // if we do not have an error to report back to the user, throw - // an exception (a generic error will be reported instead) - if (error == null) { - closeSocketThrowException( - sslSocket, - "failed to pre-validate the certificate chain due to a non-standard error"); - } - - return error; - } - - private void closeSocketThrowException( - SSLSocket socket, String errorMessage, String defaultErrorMessage) - throws SSLHandshakeException, IOException { - closeSocketThrowException( - socket, errorMessage != null ? errorMessage : defaultErrorMessage); - } - - private void closeSocketThrowException(SSLSocket socket, String errorMessage) - throws SSLHandshakeException, IOException { - if (HttpLog.LOGV) { - HttpLog.v("validation error: " + errorMessage); - } - - if (socket != null) { - SSLSession session = socket.getSession(); - if (session != null) { - session.invalidate(); - } - - socket.close(); - } - - throw new SSLHandshakeException(errorMessage); - } - - /** - * @param sslContext The SSL context shared accross all the SSL sessions - * @param host The host associated with the session - * @return A suitable SSL session from the SSL context - */ - private SSLSession getSSLSession(SSLContext sslContext, HttpHost host) { - if (sslContext != null && host != null) { - Enumeration en = sslContext.getClientSessionContext().getIds(); - while (en.hasMoreElements()) { - byte[] id = (byte[]) en.nextElement(); - if (id != null) { - SSLSession session = - sslContext.getClientSessionContext().getSession(id); - if (session.isValid() && - host.getHostName().equals(session.getPeerHost()) && - host.getPort() == session.getPeerPort()) { - return session; - } - } - } - } - - return null; - } -} diff --git a/core/java/android/net/http/CertificateValidatorCache.java b/core/java/android/net/http/CertificateValidatorCache.java deleted file mode 100644 index 54a1dbe..0000000 --- a/core/java/android/net/http/CertificateValidatorCache.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.os.SystemClock; - -import android.security.Sha1MessageDigest; - -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.security.cert.CertPath; -import java.security.GeneralSecurityException; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Random; - - -/** - * Validator cache used to speed-up certificate chain validation. The idea is - * to keep each secure domain name associated with a cryptographically secure - * hash of the certificate chain successfully used to validate the domain. If - * we establish connection with the domain more than once and each time receive - * the same list of certificates, we do not have to re-validate. - * - * {@hide} - */ -class CertificateValidatorCache { - - // TODO: debug only! - public static long mSave = 0; - public static long mCost = 0; - // TODO: debug only! - - /** - * The cache-entry lifetime in milliseconds (here, 10 minutes) - */ - private static final long CACHE_ENTRY_LIFETIME = 10 * 60 * 1000; - - /** - * The certificate factory - */ - private static CertificateFactory sCertificateFactory; - - /** - * The certificate validator cache map (domain to a cache entry) - */ - private HashMap<Integer, CacheEntry> mCacheMap; - - /** - * Random salt - */ - private int mBigScrew; - - /** - * @param certificate The array of server certificates to compute a - * secure hash from - * @return The secure hash computed from server certificates - */ - public static byte[] secureHash(Certificate[] certificates) { - byte[] secureHash = null; - - // TODO: debug only! - long beg = SystemClock.uptimeMillis(); - // TODO: debug only! - - if (certificates != null && certificates.length != 0) { - byte[] encodedCertPath = null; - try { - synchronized (CertificateValidatorCache.class) { - if (sCertificateFactory == null) { - try { - sCertificateFactory = - CertificateFactory.getInstance("X.509"); - } catch(GeneralSecurityException e) { - if (HttpLog.LOGV) { - HttpLog.v("CertificateValidatorCache:" + - " failed to create the certificate factory"); - } - } - } - } - - CertPath certPath = - sCertificateFactory.generateCertPath(Arrays.asList(certificates)); - if (certPath != null) { - encodedCertPath = certPath.getEncoded(); - if (encodedCertPath != null) { - Sha1MessageDigest messageDigest = - new Sha1MessageDigest(); - secureHash = messageDigest.digest(encodedCertPath); - } - } - } catch (GeneralSecurityException e) {} - } - - // TODO: debug only! - long end = SystemClock.uptimeMillis(); - mCost += (end - beg); - // TODO: debug only! - - return secureHash; - } - - /** - * Creates a new certificate-validator cache - */ - public CertificateValidatorCache() { - Random random = new Random(); - mBigScrew = random.nextInt(); - - mCacheMap = new HashMap<Integer, CacheEntry>(); - } - - /** - * @param domain The domain to check against - * @param secureHash The secure hash to check against - * @return True iff there is a valid (not expired) cache entry - * associated with the domain and the secure hash - */ - public boolean has(String domain, byte[] secureHash) { - boolean rval = false; - - if (domain != null && domain.length() != 0) { - if (secureHash != null && secureHash.length != 0) { - CacheEntry cacheEntry = (CacheEntry)mCacheMap.get( - new Integer(mBigScrew ^ domain.hashCode())); - if (cacheEntry != null) { - if (!cacheEntry.expired()) { - rval = cacheEntry.has(domain, secureHash); - // TODO: debug only! - if (rval) { - mSave += cacheEntry.mSave; - } - // TODO: debug only! - } else { - mCacheMap.remove(cacheEntry); - } - } - } - } - - return rval; - } - - /** - * Adds the (domain, secureHash) tuple to the cache - * @param domain The domain to be added to the cache - * @param secureHash The secure hash to be added to the cache - * @return True iff succeeds - */ - public boolean put(String domain, byte[] secureHash, long save) { - if (domain != null && domain.length() != 0) { - if (secureHash != null && secureHash.length != 0) { - mCacheMap.put( - new Integer(mBigScrew ^ domain.hashCode()), - new CacheEntry(domain, secureHash, save)); - - return true; - } - } - - return false; - } - - /** - * Certificate-validator cache entry. We have one per domain - */ - private class CacheEntry { - - /** - * The hash associated with this cache entry - */ - private byte[] mHash; - - /** - * The time associated with this cache entry - */ - private long mTime; - - // TODO: debug only! - public long mSave; - // TODO: debug only! - - /** - * The host associated with this cache entry - */ - private String mDomain; - - /** - * Creates a new certificate-validator cache entry - * @param domain The domain to be associated with this cache entry - * @param secureHash The secure hash to be associated with this cache - * entry - */ - public CacheEntry(String domain, byte[] secureHash, long save) { - mDomain = domain; - mHash = secureHash; - // TODO: debug only! - mSave = save; - // TODO: debug only! - mTime = SystemClock.uptimeMillis(); - } - - /** - * @return True iff the cache item has expired - */ - public boolean expired() { - return CACHE_ENTRY_LIFETIME < SystemClock.uptimeMillis() - mTime; - } - - /** - * @param domain The domain to check - * @param secureHash The secure hash to check - * @return True iff the given domain and hash match those associated - * with this entry - */ - public boolean has(String domain, byte[] secureHash) { - if (domain != null && 0 < domain.length()) { - if (!mDomain.equals(domain)) { - return false; - } - } - - int hashLength = secureHash.length; - if (secureHash != null && 0 < hashLength) { - if (hashLength == mHash.length) { - for (int i = 0; i < hashLength; ++i) { - if (secureHash[i] != mHash[i]) { - return false; - } - } - return true; - } - } - - return false; - } - } -}; diff --git a/core/java/android/net/http/CharArrayBuffers.java b/core/java/android/net/http/CharArrayBuffers.java deleted file mode 100644 index 77d45f6..0000000 --- a/core/java/android/net/http/CharArrayBuffers.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import org.apache.http.util.CharArrayBuffer; -import org.apache.http.protocol.HTTP; - -/** - * Utility methods for working on CharArrayBuffers. - * - * {@hide} - */ -class CharArrayBuffers { - - static final char uppercaseAddon = 'a' - 'A'; - - /** - * Returns true if the buffer contains the given string. Ignores leading - * whitespace and case. - * - * @param buffer to search - * @param beginIndex index at which we should start - * @param str to search for - */ - static boolean containsIgnoreCaseTrimmed(CharArrayBuffer buffer, - int beginIndex, final String str) { - int len = buffer.length(); - char[] chars = buffer.buffer(); - while (beginIndex < len && HTTP.isWhitespace(chars[beginIndex])) { - beginIndex++; - } - int size = str.length(); - boolean ok = len >= beginIndex + size; - for (int j=0; ok && (j<size); j++) { - char a = chars[beginIndex+j]; - char b = str.charAt(j); - if (a != b) { - a = toLower(a); - b = toLower(b); - ok = a == b; - } - } - return ok; - } - - /** - * Returns index of first occurence ch. Lower cases characters leading up - * to first occurrence of ch. - */ - static int setLowercaseIndexOf(CharArrayBuffer buffer, final int ch) { - - int beginIndex = 0; - int endIndex = buffer.length(); - char[] chars = buffer.buffer(); - - for (int i = beginIndex; i < endIndex; i++) { - char current = chars[i]; - if (current == ch) { - return i; - } else if (current >= 'A' && current <= 'Z'){ - // make lower case - current += uppercaseAddon; - chars[i] = current; - } - } - return -1; - } - - private static char toLower(char c) { - if (c >= 'A' && c <= 'Z'){ - c += uppercaseAddon; - } - return c; - } -} diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java deleted file mode 100644 index 563634f..0000000 --- a/core/java/android/net/http/Connection.java +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.content.Context; -import android.os.SystemClock; - -import java.io.IOException; -import java.net.UnknownHostException; -import java.util.ListIterator; -import java.util.LinkedList; - -import javax.net.ssl.SSLHandshakeException; - -import org.apache.http.ConnectionReuseStrategy; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpVersion; -import org.apache.http.ParseException; -import org.apache.http.ProtocolVersion; -import org.apache.http.protocol.ExecutionContext; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.BasicHttpContext; - -/** - * {@hide} - */ -abstract class Connection { - - /** - * Allow a TCP connection 60 idle seconds before erroring out - */ - static final int SOCKET_TIMEOUT = 60000; - - private static final int SEND = 0; - private static final int READ = 1; - private static final int DRAIN = 2; - private static final int DONE = 3; - private static final String[] states = {"SEND", "READ", "DRAIN", "DONE"}; - - Context mContext; - - /** The low level connection */ - protected AndroidHttpClientConnection mHttpClientConnection = null; - - /** - * The server SSL certificate associated with this connection - * (null if the connection is not secure) - * It would be nice to store the whole certificate chain, but - * we want to keep things as light-weight as possible - */ - protected SslCertificate mCertificate = null; - - /** - * The host this connection is connected to. If using proxy, - * this is set to the proxy address - */ - HttpHost mHost; - - /** true if the connection can be reused for sending more requests */ - private boolean mCanPersist; - - /** context required by ConnectionReuseStrategy. */ - private HttpContext mHttpContext; - - /** set when cancelled */ - private static int STATE_NORMAL = 0; - private static int STATE_CANCEL_REQUESTED = 1; - private int mActive = STATE_NORMAL; - - /** The number of times to try to re-connect (if connect fails). */ - private final static int RETRY_REQUEST_LIMIT = 2; - - private static final int MIN_PIPE = 2; - private static final int MAX_PIPE = 3; - - /** - * Doesn't seem to exist anymore in the new HTTP client, so copied here. - */ - private static final String HTTP_CONNECTION = "http.connection"; - - RequestQueue.ConnectionManager mConnectionManager; - RequestFeeder mRequestFeeder; - - /** - * Buffer for feeding response blocks to webkit. One block per - * connection reduces memory churn. - */ - private byte[] mBuf; - - protected Connection(Context context, HttpHost host, - RequestQueue.ConnectionManager connectionManager, - RequestFeeder requestFeeder) { - mContext = context; - mHost = host; - mConnectionManager = connectionManager; - mRequestFeeder = requestFeeder; - - mCanPersist = false; - mHttpContext = new BasicHttpContext(null); - } - - HttpHost getHost() { - return mHost; - } - - /** - * connection factory: returns an HTTP or HTTPS connection as - * necessary - */ - static Connection getConnection( - Context context, HttpHost host, - RequestQueue.ConnectionManager connectionManager, - RequestFeeder requestFeeder) { - - if (host.getSchemeName().equals("http")) { - return new HttpConnection(context, host, connectionManager, - requestFeeder); - } - - // Otherwise, default to https - return new HttpsConnection(context, host, connectionManager, - requestFeeder); - } - - /** - * @return The server SSL certificate associated with this - * connection (null if the connection is not secure) - */ - /* package */ SslCertificate getCertificate() { - return mCertificate; - } - - /** - * Close current network connection - * Note: this runs in non-network thread - */ - void cancel() { - mActive = STATE_CANCEL_REQUESTED; - closeConnection(); - if (HttpLog.LOGV) HttpLog.v( - "Connection.cancel(): connection closed " + mHost); - } - - /** - * Process requests in queue - * pipelines requests - */ - void processRequests(Request firstRequest) { - Request req = null; - boolean empty; - int error = EventHandler.OK; - Exception exception = null; - - LinkedList<Request> pipe = new LinkedList<Request>(); - - int minPipe = MIN_PIPE, maxPipe = MAX_PIPE; - int state = SEND; - - while (state != DONE) { - if (HttpLog.LOGV) HttpLog.v( - states[state] + " pipe " + pipe.size()); - - /* If a request was cancelled, give other cancel requests - some time to go through so we don't uselessly restart - connections */ - if (mActive == STATE_CANCEL_REQUESTED) { - try { - Thread.sleep(100); - } catch (InterruptedException x) { /* ignore */ } - mActive = STATE_NORMAL; - } - - switch (state) { - case SEND: { - if (pipe.size() == maxPipe) { - state = READ; - break; - } - /* get a request */ - if (firstRequest == null) { - req = mRequestFeeder.getRequest(mHost); - } else { - req = firstRequest; - firstRequest = null; - } - if (req == null) { - state = DRAIN; - break; - } - req.setConnection(this); - - /* Don't work on cancelled requests. */ - if (req.mCancelled) { - if (HttpLog.LOGV) HttpLog.v( - "processRequests(): skipping cancelled request " - + req); - req.complete(); - break; - } - - if (mHttpClientConnection == null || - !mHttpClientConnection.isOpen()) { - /* If this call fails, the address is bad or - the net is down. Punt for now. - - FIXME: blow out entire queue here on - connection failure if net up? */ - - if (!openHttpConnection(req)) { - state = DONE; - break; - } - } - - try { - /* FIXME: don't increment failure count if old - connection? There should not be a penalty for - attempting to reuse an old connection */ - req.sendRequest(mHttpClientConnection); - } catch (HttpException e) { - exception = e; - error = EventHandler.ERROR; - } catch (IOException e) { - exception = e; - error = EventHandler.ERROR_IO; - } catch (IllegalStateException e) { - exception = e; - error = EventHandler.ERROR_IO; - } - if (exception != null) { - if (httpFailure(req, error, exception) && - !req.mCancelled) { - /* retry request if not permanent failure - or cancelled */ - pipe.addLast(req); - } - exception = null; - state = (clearPipe(pipe) || - !mConnectionManager.isNetworkConnected()) ? - DONE : SEND; - minPipe = maxPipe = 1; - break; - } - - pipe.addLast(req); - if (!mCanPersist) state = READ; - break; - - } - case DRAIN: - case READ: { - empty = !mRequestFeeder.haveRequest(mHost); - int pipeSize = pipe.size(); - if (state != DRAIN && pipeSize < minPipe && - !empty && mCanPersist) { - state = SEND; - break; - } else if (pipeSize == 0) { - /* Done if no other work to do */ - state = empty ? DONE : SEND; - break; - } - - req = (Request)pipe.removeFirst(); - if (HttpLog.LOGV) HttpLog.v( - "processRequests() reading " + req); - - try { - req.readResponse(mHttpClientConnection); - } catch (ParseException e) { - exception = e; - error = EventHandler.ERROR_IO; - } catch (IOException e) { - exception = e; - error = EventHandler.ERROR_IO; - } catch (IllegalStateException e) { - exception = e; - error = EventHandler.ERROR_IO; - } - if (exception != null) { - if (httpFailure(req, error, exception) && - !req.mCancelled) { - /* retry request if not permanent failure - or cancelled */ - req.reset(); - pipe.addFirst(req); - } - exception = null; - mCanPersist = false; - } - if (!mCanPersist) { - if (HttpLog.LOGV) HttpLog.v( - "processRequests(): no persist, closing " + - mHost); - - closeConnection(); - - mHttpContext.removeAttribute(HTTP_CONNECTION); - clearPipe(pipe); - minPipe = maxPipe = 1; - /* If network active continue to service this queue */ - state = mConnectionManager.isNetworkConnected() ? - SEND : DONE; - } - break; - } - } - } - } - - /** - * After a send/receive failure, any pipelined requests must be - * cleared back to the mRequest queue - * @return true if mRequests is empty after pipe cleared - */ - private boolean clearPipe(LinkedList<Request> pipe) { - boolean empty = true; - if (HttpLog.LOGV) HttpLog.v( - "Connection.clearPipe(): clearing pipe " + pipe.size()); - synchronized (mRequestFeeder) { - Request tReq; - while (!pipe.isEmpty()) { - tReq = (Request)pipe.removeLast(); - if (HttpLog.LOGV) HttpLog.v( - "clearPipe() adding back " + mHost + " " + tReq); - mRequestFeeder.requeueRequest(tReq); - empty = false; - } - if (empty) empty = mRequestFeeder.haveRequest(mHost); - } - return empty; - } - - /** - * @return true on success - */ - private boolean openHttpConnection(Request req) { - - long now = SystemClock.uptimeMillis(); - int error = EventHandler.OK; - Exception exception = null; - - try { - // reset the certificate to null before opening a connection - mCertificate = null; - mHttpClientConnection = openConnection(req); - if (mHttpClientConnection != null) { - mHttpClientConnection.setSocketTimeout(SOCKET_TIMEOUT); - mHttpContext.setAttribute(HTTP_CONNECTION, - mHttpClientConnection); - } else { - // we tried to do SSL tunneling, failed, - // and need to drop the request; - // we have already informed the handler - req.mFailCount = RETRY_REQUEST_LIMIT; - return false; - } - } catch (UnknownHostException e) { - if (HttpLog.LOGV) HttpLog.v("Failed to open connection"); - error = EventHandler.ERROR_LOOKUP; - exception = e; - } catch (IllegalArgumentException e) { - if (HttpLog.LOGV) HttpLog.v("Illegal argument exception"); - error = EventHandler.ERROR_CONNECT; - req.mFailCount = RETRY_REQUEST_LIMIT; - exception = e; - } catch (SSLConnectionClosedByUserException e) { - // hack: if we have an SSL connection failure, - // we don't want to reconnect - req.mFailCount = RETRY_REQUEST_LIMIT; - // no error message - return false; - } catch (SSLHandshakeException e) { - // hack: if we have an SSL connection failure, - // we don't want to reconnect - req.mFailCount = RETRY_REQUEST_LIMIT; - if (HttpLog.LOGV) HttpLog.v( - "SSL exception performing handshake"); - error = EventHandler.ERROR_FAILED_SSL_HANDSHAKE; - exception = e; - } catch (IOException e) { - error = EventHandler.ERROR_CONNECT; - exception = e; - } - - if (HttpLog.LOGV) { - long now2 = SystemClock.uptimeMillis(); - HttpLog.v("Connection.openHttpConnection() " + - (now2 - now) + " " + mHost); - } - - if (error == EventHandler.OK) { - return true; - } else { - if (mConnectionManager.isNetworkConnected() == false || - req.mFailCount < RETRY_REQUEST_LIMIT) { - // requeue - mRequestFeeder.requeueRequest(req); - req.mFailCount++; - } else { - httpFailure(req, error, exception); - } - return error == EventHandler.OK; - } - } - - /** - * Helper. Calls the mEventHandler's error() method only if - * request failed permanently. Increments mFailcount on failure. - * - * Increments failcount only if the network is believed to be - * connected - * - * @return true if request can be retried (less than - * RETRY_REQUEST_LIMIT failures have occurred). - */ - private boolean httpFailure(Request req, int errorId, Exception e) { - boolean ret = true; - boolean networkConnected = mConnectionManager.isNetworkConnected(); - - // e.printStackTrace(); - if (HttpLog.LOGV) HttpLog.v( - "httpFailure() ******* " + e + " count " + req.mFailCount + - " networkConnected " + networkConnected + " " + mHost + " " + req.getUri()); - - if (networkConnected && ++req.mFailCount >= RETRY_REQUEST_LIMIT) { - ret = false; - String error; - if (errorId < 0) { - error = mContext.getText( - EventHandler.errorStringResources[-errorId]).toString(); - } else { - Throwable cause = e.getCause(); - error = cause != null ? cause.toString() : e.getMessage(); - } - req.mEventHandler.error(errorId, error); - req.complete(); - } - - closeConnection(); - mHttpContext.removeAttribute(HTTP_CONNECTION); - - return ret; - } - - HttpContext getHttpContext() { - return mHttpContext; - } - - /** - * Use same logic as ConnectionReuseStrategy - * @see ConnectionReuseStrategy - */ - private boolean keepAlive(HttpEntity entity, - ProtocolVersion ver, int connType, final HttpContext context) { - org.apache.http.HttpConnection conn = (org.apache.http.HttpConnection) - context.getAttribute(ExecutionContext.HTTP_CONNECTION); - - if (conn != null && !conn.isOpen()) - return false; - // do NOT check for stale connection, that is an expensive operation - - if (entity != null) { - if (entity.getContentLength() < 0) { - if (!entity.isChunked() || ver.lessEquals(HttpVersion.HTTP_1_0)) { - // if the content length is not known and is not chunk - // encoded, the connection cannot be reused - return false; - } - } - } - // Check for 'Connection' directive - if (connType == Headers.CONN_CLOSE) { - return false; - } else if (connType == Headers.CONN_KEEP_ALIVE) { - return true; - } - // Resorting to protocol version default close connection policy - return !ver.lessEquals(HttpVersion.HTTP_1_0); - } - - void setCanPersist(HttpEntity entity, ProtocolVersion ver, int connType) { - mCanPersist = keepAlive(entity, ver, connType, mHttpContext); - } - - void setCanPersist(boolean canPersist) { - mCanPersist = canPersist; - } - - boolean getCanPersist() { - return mCanPersist; - } - - /** typically http or https... set by subclass */ - abstract String getScheme(); - abstract void closeConnection(); - abstract AndroidHttpClientConnection openConnection(Request req) throws IOException; - - /** - * Prints request queue to log, for debugging. - * returns request count - */ - public synchronized String toString() { - return mHost.toString(); - } - - byte[] getBuf() { - if (mBuf == null) mBuf = new byte[8192]; - return mBuf; - } - -} diff --git a/core/java/android/net/http/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java deleted file mode 100644 index 8e759e2..0000000 --- a/core/java/android/net/http/ConnectionThread.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.content.Context; -import android.os.SystemClock; - -import org.apache.http.HttpHost; - -import java.lang.Thread; - -/** - * {@hide} - */ -class ConnectionThread extends Thread { - - static final int WAIT_TIMEOUT = 5000; - static final int WAIT_TICK = 1000; - - // Performance probe - long mStartThreadTime; - long mCurrentThreadTime; - - private boolean mWaiting; - private volatile boolean mRunning = true; - private Context mContext; - private RequestQueue.ConnectionManager mConnectionManager; - private RequestFeeder mRequestFeeder; - - private int mId; - Connection mConnection; - - ConnectionThread(Context context, - int id, - RequestQueue.ConnectionManager connectionManager, - RequestFeeder requestFeeder) { - super(); - mContext = context; - setName("http" + id); - mId = id; - mConnectionManager = connectionManager; - mRequestFeeder = requestFeeder; - } - - void requestStop() { - synchronized (mRequestFeeder) { - mRunning = false; - mRequestFeeder.notify(); - } - } - - /** - * Loop until app shutdown. Runs connections in priority - * order. - */ - public void run() { - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE); - - mStartThreadTime = -1; - mCurrentThreadTime = SystemClock.currentThreadTimeMillis(); - - while (mRunning) { - Request request; - - /* Get a request to process */ - request = mRequestFeeder.getRequest(); - - /* wait for work */ - if (request == null) { - synchronized(mRequestFeeder) { - if (HttpLog.LOGV) HttpLog.v("ConnectionThread: Waiting for work"); - mWaiting = true; - try { - if (mStartThreadTime != -1) { - mCurrentThreadTime = SystemClock - .currentThreadTimeMillis(); - } - mRequestFeeder.wait(); - } catch (InterruptedException e) { - } - mWaiting = false; - } - } else { - if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " + - request.mHost + " " + request ); - - HttpHost proxy = mConnectionManager.getProxyHost(); - - HttpHost host; - if (false) { - // Allow https proxy - host = proxy == null ? request.mHost : proxy; - } else { - // Disallow https proxy -- tmob proxy server - // serves a request loop for https reqs - host = (proxy == null || - request.mHost.getSchemeName().equals("https")) ? - request.mHost : proxy; - } - mConnection = mConnectionManager.getConnection(mContext, host); - mConnection.processRequests(request); - if (mConnection.getCanPersist()) { - if (!mConnectionManager.recycleConnection(host, - mConnection)) { - mConnection.closeConnection(); - } - } else { - mConnection.closeConnection(); - } - mConnection = null; - } - - } - } - - public synchronized String toString() { - String con = mConnection == null ? "" : mConnection.toString(); - String active = mWaiting ? "w" : "a"; - return "cid " + mId + " " + active + " " + con; - } - -} diff --git a/core/java/android/net/http/DomainNameChecker.java b/core/java/android/net/http/DomainNameChecker.java deleted file mode 100644 index e4c8009..0000000 --- a/core/java/android/net/http/DomainNameChecker.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import org.bouncycastle.asn1.x509.X509Name; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateParsingException; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; -import java.util.Vector; - -/** - * Implements basic domain-name validation as specified by RFC2818. - * - * {@hide} - */ -public class DomainNameChecker { - private static Pattern QUICK_IP_PATTERN; - static { - try { - QUICK_IP_PATTERN = Pattern.compile("^[a-f0-9\\.:]+$"); - } catch (PatternSyntaxException e) {} - } - - private static final int ALT_DNS_NAME = 2; - private static final int ALT_IPA_NAME = 7; - - /** - * Checks the site certificate against the domain name of the site being visited - * @param certificate The certificate to check - * @param thisDomain The domain name of the site being visited - * @return True iff if there is a domain match as specified by RFC2818 - */ - public static boolean match(X509Certificate certificate, String thisDomain) { - if (certificate == null || thisDomain == null || thisDomain.length() == 0) { - return false; - } - - thisDomain = thisDomain.toLowerCase(); - if (!isIpAddress(thisDomain)) { - return matchDns(certificate, thisDomain); - } else { - return matchIpAddress(certificate, thisDomain); - } - } - - /** - * @return True iff the domain name is specified as an IP address - */ - private static boolean isIpAddress(String domain) { - boolean rval = (domain != null && domain.length() != 0); - if (rval) { - try { - // do a quick-dirty IP match first to avoid DNS lookup - rval = QUICK_IP_PATTERN.matcher(domain).matches(); - if (rval) { - rval = domain.equals( - InetAddress.getByName(domain).getHostAddress()); - } - } catch (UnknownHostException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "unknown host exception"; - } - - if (HttpLog.LOGV) { - HttpLog.v("DomainNameChecker.isIpAddress(): " + errorMessage); - } - - rval = false; - } - } - - return rval; - } - - /** - * Checks the site certificate against the IP domain name of the site being visited - * @param certificate The certificate to check - * @param thisDomain The DNS domain name of the site being visited - * @return True iff if there is a domain match as specified by RFC2818 - */ - private static boolean matchIpAddress(X509Certificate certificate, String thisDomain) { - if (HttpLog.LOGV) { - HttpLog.v("DomainNameChecker.matchIpAddress(): this domain: " + thisDomain); - } - - try { - Collection subjectAltNames = certificate.getSubjectAlternativeNames(); - if (subjectAltNames != null) { - Iterator i = subjectAltNames.iterator(); - while (i.hasNext()) { - List altNameEntry = (List)(i.next()); - if (altNameEntry != null && 2 <= altNameEntry.size()) { - Integer altNameType = (Integer)(altNameEntry.get(0)); - if (altNameType != null) { - if (altNameType.intValue() == ALT_IPA_NAME) { - String altName = (String)(altNameEntry.get(1)); - if (altName != null) { - if (HttpLog.LOGV) { - HttpLog.v("alternative IP: " + altName); - } - if (thisDomain.equalsIgnoreCase(altName)) { - return true; - } - } - } - } - } - } - } - } catch (CertificateParsingException e) {} - - return false; - } - - /** - * Checks the site certificate against the DNS domain name of the site being visited - * @param certificate The certificate to check - * @param thisDomain The DNS domain name of the site being visited - * @return True iff if there is a domain match as specified by RFC2818 - */ - private static boolean matchDns(X509Certificate certificate, String thisDomain) { - boolean hasDns = false; - try { - Collection subjectAltNames = certificate.getSubjectAlternativeNames(); - if (subjectAltNames != null) { - Iterator i = subjectAltNames.iterator(); - while (i.hasNext()) { - List altNameEntry = (List)(i.next()); - if (altNameEntry != null && 2 <= altNameEntry.size()) { - Integer altNameType = (Integer)(altNameEntry.get(0)); - if (altNameType != null) { - if (altNameType.intValue() == ALT_DNS_NAME) { - hasDns = true; - String altName = (String)(altNameEntry.get(1)); - if (altName != null) { - if (matchDns(thisDomain, altName)) { - return true; - } - } - } - } - } - } - } - } catch (CertificateParsingException e) { - // one way we can get here is if an alternative name starts with - // '*' character, which is contrary to one interpretation of the - // spec (a valid DNS name must start with a letter); there is no - // good way around this, and in order to be compatible we proceed - // to check the common name (ie, ignore alternative names) - if (HttpLog.LOGV) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "failed to parse certificate"; - } - - if (HttpLog.LOGV) { - HttpLog.v("DomainNameChecker.matchDns(): " + errorMessage); - } - } - } - - if (!hasDns) { - X509Name xName = new X509Name(certificate.getSubjectDN().getName()); - Vector val = xName.getValues(); - Vector oid = xName.getOIDs(); - for (int i = 0; i < oid.size(); i++) { - if (oid.elementAt(i).equals(X509Name.CN)) { - return matchDns(thisDomain, (String)(val.elementAt(i))); - } - } - } - - return false; - } - - /** - * @param thisDomain The domain name of the site being visited - * @param thatDomain The domain name from the certificate - * @return True iff thisDomain matches thatDomain as specified by RFC2818 - */ - private static boolean matchDns(String thisDomain, String thatDomain) { - if (HttpLog.LOGV) { - HttpLog.v("DomainNameChecker.matchDns():" + - " this domain: " + thisDomain + - " that domain: " + thatDomain); - } - - if (thisDomain == null || thisDomain.length() == 0 || - thatDomain == null || thatDomain.length() == 0) { - return false; - } - - thatDomain = thatDomain.toLowerCase(); - - // (a) domain name strings are equal, ignoring case: X matches X - boolean rval = thisDomain.equals(thatDomain); - if (!rval) { - String[] thisDomainTokens = thisDomain.split("\\."); - String[] thatDomainTokens = thatDomain.split("\\."); - - int thisDomainTokensNum = thisDomainTokens.length; - int thatDomainTokensNum = thatDomainTokens.length; - - // (b) OR thatHost is a '.'-suffix of thisHost: Z.Y.X matches X - if (thisDomainTokensNum >= thatDomainTokensNum) { - for (int i = thatDomainTokensNum - 1; i >= 0; --i) { - rval = thisDomainTokens[i].equals(thatDomainTokens[i]); - if (!rval) { - // (c) OR we have a special *-match: - // Z.Y.X matches *.Y.X but does not match *.X - rval = (i == 0 && thisDomainTokensNum == thatDomainTokensNum); - if (rval) { - rval = thatDomainTokens[0].equals("*"); - if (!rval) { - // (d) OR we have a *-component match: - // f*.com matches foo.com but not bar.com - rval = domainTokenMatch( - thisDomainTokens[0], thatDomainTokens[0]); - } - } - - break; - } - } - } - } - - return rval; - } - - /** - * @param thisDomainToken The domain token from the current domain name - * @param thatDomainToken The domain token from the certificate - * @return True iff thisDomainToken matches thatDomainToken, using the - * wildcard match as specified by RFC2818-3.1. For example, f*.com must - * match foo.com but not bar.com - */ - private static boolean domainTokenMatch(String thisDomainToken, String thatDomainToken) { - if (thisDomainToken != null && thatDomainToken != null) { - int starIndex = thatDomainToken.indexOf('*'); - if (starIndex >= 0) { - if (thatDomainToken.length() - 1 <= thisDomainToken.length()) { - String prefix = thatDomainToken.substring(0, starIndex); - String suffix = thatDomainToken.substring(starIndex + 1); - - return thisDomainToken.startsWith(prefix) && thisDomainToken.endsWith(suffix); - } - } - } - - return false; - } -} diff --git a/core/java/android/net/http/EventHandler.java b/core/java/android/net/http/EventHandler.java deleted file mode 100644 index 830d1f1..0000000 --- a/core/java/android/net/http/EventHandler.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - - -/** - * Callbacks in this interface are made as an HTTP request is - * processed. The normal order of callbacks is status(), headers(), - * then multiple data() then endData(). handleSslErrorRequest(), if - * there is an SSL certificate error. error() can occur anywhere - * in the transaction. - * - * {@hide} - */ - -public interface EventHandler { - - /** - * Error codes used in the error() callback. Positive error codes - * are reserved for codes sent by http servers. Negative error - * codes are connection/parsing failures, etc. - */ - - /** Success */ - public static final int OK = 0; - /** Generic error */ - public static final int ERROR = -1; - /** Server or proxy hostname lookup failed */ - public static final int ERROR_LOOKUP = -2; - /** Unsupported authentication scheme (ie, not basic or digest) */ - public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3; - /** User authentication failed on server */ - public static final int ERROR_AUTH = -4; - /** User authentication failed on proxy */ - public static final int ERROR_PROXYAUTH = -5; - /** Could not connect to server */ - public static final int ERROR_CONNECT = -6; - /** Failed to write to or read from server */ - public static final int ERROR_IO = -7; - /** Connection timed out */ - public static final int ERROR_TIMEOUT = -8; - /** Too many redirects */ - public static final int ERROR_REDIRECT_LOOP = -9; - /** Unsupported URI scheme (ie, not http, https, etc) */ - public static final int ERROR_UNSUPPORTED_SCHEME = -10; - /** Failed to perform SSL handshake */ - public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; - /** Bad URL */ - public static final int ERROR_BAD_URL = -12; - /** Generic file error for file:/// loads */ - public static final int FILE_ERROR = -13; - /** File not found error for file:/// loads */ - public static final int FILE_NOT_FOUND_ERROR = -14; - /** Too many requests queued */ - public static final int TOO_MANY_REQUESTS_ERROR = -15; - - final static int[] errorStringResources = { - com.android.internal.R.string.httpErrorOk, - com.android.internal.R.string.httpError, - com.android.internal.R.string.httpErrorLookup, - com.android.internal.R.string.httpErrorUnsupportedAuthScheme, - com.android.internal.R.string.httpErrorAuth, - com.android.internal.R.string.httpErrorProxyAuth, - com.android.internal.R.string.httpErrorConnect, - com.android.internal.R.string.httpErrorIO, - com.android.internal.R.string.httpErrorTimeout, - com.android.internal.R.string.httpErrorRedirectLoop, - com.android.internal.R.string.httpErrorUnsupportedScheme, - com.android.internal.R.string.httpErrorFailedSslHandshake, - com.android.internal.R.string.httpErrorBadUrl, - com.android.internal.R.string.httpErrorFile, - com.android.internal.R.string.httpErrorFileNotFound, - com.android.internal.R.string.httpErrorTooManyRequests - }; - - /** - * Called after status line has been sucessfully processed. - * @param major_version HTTP version advertised by server. major - * is the part before the "." - * @param minor_version HTTP version advertised by server. minor - * is the part after the "." - * @param code HTTP Status code. See RFC 2616. - * @param reason_phrase Textual explanation sent by server - */ - public void status(int major_version, - int minor_version, - int code, - String reason_phrase); - - /** - * Called after all headers are successfully processed. - */ - public void headers(Headers headers); - - /** - * An array containing all or part of the http body as read from - * the server. - * @param data A byte array containing the content - * @param len The length of valid content in data - * - * Note: chunked and compressed encodings are handled within - * android.net.http. Decoded data is passed through this - * interface. - */ - public void data(byte[] data, int len); - - /** - * Called when the document is completely read. No more data() - * callbacks will be made after this call - */ - public void endData(); - - /** - * SSL certificate callback called every time a resource is - * loaded via a secure connection - */ - public void certificate(SslCertificate certificate); - - /** - * There was trouble. - * @param id One of the error codes defined below - * @param description of error - */ - public void error(int id, String description); - - /** - * SSL certificate error callback. Handles SSL error(s) on the way - * up to the user. The callback has to make sure that restartConnection() is called, - * otherwise the connection will be suspended indefinitely. - */ - public void handleSslErrorRequest(SslError error); - -} diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java deleted file mode 100644 index b0923d1..0000000 --- a/core/java/android/net/http/Headers.java +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.util.Config; -import android.util.Log; - -import java.util.ArrayList; - -import org.apache.http.HeaderElement; -import org.apache.http.entity.ContentLengthStrategy; -import org.apache.http.message.BasicHeaderValueParser; -import org.apache.http.message.ParserCursor; -import org.apache.http.protocol.HTTP; -import org.apache.http.util.CharArrayBuffer; - -/** - * Manages received headers - * - * {@hide} - */ -public final class Headers { - private static final String LOGTAG = "Http"; - - // header parsing constant - /** - * indicate HTTP 1.0 connection close after the response - */ - public final static int CONN_CLOSE = 1; - /** - * indicate HTTP 1.1 connection keep alive - */ - public final static int CONN_KEEP_ALIVE = 2; - - // initial values. - public final static int NO_CONN_TYPE = 0; - public final static long NO_TRANSFER_ENCODING = 0; - public final static long NO_CONTENT_LENGTH = -1; - - // header strings - public final static String TRANSFER_ENCODING = "transfer-encoding"; - public final static String CONTENT_LEN = "content-length"; - public final static String CONTENT_TYPE = "content-type"; - public final static String CONTENT_ENCODING = "content-encoding"; - public final static String CONN_DIRECTIVE = "connection"; - - public final static String LOCATION = "location"; - public final static String PROXY_CONNECTION = "proxy-connection"; - - public final static String WWW_AUTHENTICATE = "www-authenticate"; - public final static String PROXY_AUTHENTICATE = "proxy-authenticate"; - public final static String CONTENT_DISPOSITION = "content-disposition"; - public final static String ACCEPT_RANGES = "accept-ranges"; - public final static String EXPIRES = "expires"; - public final static String CACHE_CONTROL = "cache-control"; - public final static String LAST_MODIFIED = "last-modified"; - public final static String ETAG = "etag"; - public final static String SET_COOKIE = "set-cookie"; - public final static String PRAGMA = "pragma"; - public final static String REFRESH = "refresh"; - - // following hash are generated by String.hashCode() - private final static int HASH_TRANSFER_ENCODING = 1274458357; - private final static int HASH_CONTENT_LEN = -1132779846; - private final static int HASH_CONTENT_TYPE = 785670158; - private final static int HASH_CONTENT_ENCODING = 2095084583; - private final static int HASH_CONN_DIRECTIVE = -775651618; - private final static int HASH_LOCATION = 1901043637; - private final static int HASH_PROXY_CONNECTION = 285929373; - private final static int HASH_WWW_AUTHENTICATE = -243037365; - private final static int HASH_PROXY_AUTHENTICATE = -301767724; - private final static int HASH_CONTENT_DISPOSITION = -1267267485; - private final static int HASH_ACCEPT_RANGES = 1397189435; - private final static int HASH_EXPIRES = -1309235404; - private final static int HASH_CACHE_CONTROL = -208775662; - private final static int HASH_LAST_MODIFIED = 150043680; - private final static int HASH_ETAG = 3123477; - private final static int HASH_SET_COOKIE = 1237214767; - private final static int HASH_PRAGMA = -980228804; - private final static int HASH_REFRESH = 1085444827; - - // keep any headers that require direct access in a presized - // string array - private final static int IDX_TRANSFER_ENCODING = 0; - private final static int IDX_CONTENT_LEN = 1; - private final static int IDX_CONTENT_TYPE = 2; - private final static int IDX_CONTENT_ENCODING = 3; - private final static int IDX_CONN_DIRECTIVE = 4; - private final static int IDX_LOCATION = 5; - private final static int IDX_PROXY_CONNECTION = 6; - private final static int IDX_WWW_AUTHENTICATE = 7; - private final static int IDX_PROXY_AUTHENTICATE = 8; - private final static int IDX_CONTENT_DISPOSITION = 9; - private final static int IDX_ACCEPT_RANGES = 10; - private final static int IDX_EXPIRES = 11; - private final static int IDX_CACHE_CONTROL = 12; - private final static int IDX_LAST_MODIFIED = 13; - private final static int IDX_ETAG = 14; - private final static int IDX_SET_COOKIE = 15; - private final static int IDX_PRAGMA = 16; - private final static int IDX_REFRESH = 17; - - private final static int HEADER_COUNT = 18; - - /* parsed values */ - private long transferEncoding; - private long contentLength; // Content length of the incoming data - private int connectionType; - private ArrayList<String> cookies = new ArrayList<String>(2); - - private String[] mHeaders = new String[HEADER_COUNT]; - private final static String[] sHeaderNames = { - TRANSFER_ENCODING, - CONTENT_LEN, - CONTENT_TYPE, - CONTENT_ENCODING, - CONN_DIRECTIVE, - LOCATION, - PROXY_CONNECTION, - WWW_AUTHENTICATE, - PROXY_AUTHENTICATE, - CONTENT_DISPOSITION, - ACCEPT_RANGES, - EXPIRES, - CACHE_CONTROL, - LAST_MODIFIED, - ETAG, - SET_COOKIE, - PRAGMA, - REFRESH - }; - - // Catch-all for headers not explicitly handled - private ArrayList<String> mExtraHeaderNames = new ArrayList<String>(4); - private ArrayList<String> mExtraHeaderValues = new ArrayList<String>(4); - - public Headers() { - transferEncoding = NO_TRANSFER_ENCODING; - contentLength = NO_CONTENT_LENGTH; - connectionType = NO_CONN_TYPE; - } - - public void parseHeader(CharArrayBuffer buffer) { - int pos = CharArrayBuffers.setLowercaseIndexOf(buffer, ':'); - if (pos == -1) { - return; - } - String name = buffer.substringTrimmed(0, pos); - if (name.length() == 0) { - return; - } - pos++; - - String val = buffer.substringTrimmed(pos, buffer.length()); - if (HttpLog.LOGV) { - HttpLog.v("hdr " + buffer.length() + " " + buffer); - } - - switch (name.hashCode()) { - case HASH_TRANSFER_ENCODING: - if (name.equals(TRANSFER_ENCODING)) { - mHeaders[IDX_TRANSFER_ENCODING] = val; - HeaderElement[] encodings = BasicHeaderValueParser.DEFAULT - .parseElements(buffer, new ParserCursor(pos, - buffer.length())); - // The chunked encoding must be the last one applied RFC2616, - // 14.41 - int len = encodings.length; - if (HTTP.IDENTITY_CODING.equalsIgnoreCase(val)) { - transferEncoding = ContentLengthStrategy.IDENTITY; - } else if ((len > 0) - && (HTTP.CHUNK_CODING - .equalsIgnoreCase(encodings[len - 1].getName()))) { - transferEncoding = ContentLengthStrategy.CHUNKED; - } else { - transferEncoding = ContentLengthStrategy.IDENTITY; - } - } - break; - case HASH_CONTENT_LEN: - if (name.equals(CONTENT_LEN)) { - mHeaders[IDX_CONTENT_LEN] = val; - try { - contentLength = Long.parseLong(val); - } catch (NumberFormatException e) { - if (Config.LOGV) { - Log.v(LOGTAG, "Headers.headers(): error parsing" - + " content length: " + buffer.toString()); - } - } - } - break; - case HASH_CONTENT_TYPE: - if (name.equals(CONTENT_TYPE)) { - mHeaders[IDX_CONTENT_TYPE] = val; - } - break; - case HASH_CONTENT_ENCODING: - if (name.equals(CONTENT_ENCODING)) { - mHeaders[IDX_CONTENT_ENCODING] = val; - } - break; - case HASH_CONN_DIRECTIVE: - if (name.equals(CONN_DIRECTIVE)) { - mHeaders[IDX_CONN_DIRECTIVE] = val; - setConnectionType(buffer, pos); - } - break; - case HASH_LOCATION: - if (name.equals(LOCATION)) { - mHeaders[IDX_LOCATION] = val; - } - break; - case HASH_PROXY_CONNECTION: - if (name.equals(PROXY_CONNECTION)) { - mHeaders[IDX_PROXY_CONNECTION] = val; - setConnectionType(buffer, pos); - } - break; - case HASH_WWW_AUTHENTICATE: - if (name.equals(WWW_AUTHENTICATE)) { - mHeaders[IDX_WWW_AUTHENTICATE] = val; - } - break; - case HASH_PROXY_AUTHENTICATE: - if (name.equals(PROXY_AUTHENTICATE)) { - mHeaders[IDX_PROXY_AUTHENTICATE] = val; - } - break; - case HASH_CONTENT_DISPOSITION: - if (name.equals(CONTENT_DISPOSITION)) { - mHeaders[IDX_CONTENT_DISPOSITION] = val; - } - break; - case HASH_ACCEPT_RANGES: - if (name.equals(ACCEPT_RANGES)) { - mHeaders[IDX_ACCEPT_RANGES] = val; - } - break; - case HASH_EXPIRES: - if (name.equals(EXPIRES)) { - mHeaders[IDX_EXPIRES] = val; - } - break; - case HASH_CACHE_CONTROL: - if (name.equals(CACHE_CONTROL)) { - mHeaders[IDX_CACHE_CONTROL] = val; - } - break; - case HASH_LAST_MODIFIED: - if (name.equals(LAST_MODIFIED)) { - mHeaders[IDX_LAST_MODIFIED] = val; - } - break; - case HASH_ETAG: - if (name.equals(ETAG)) { - mHeaders[IDX_ETAG] = val; - } - break; - case HASH_SET_COOKIE: - if (name.equals(SET_COOKIE)) { - mHeaders[IDX_SET_COOKIE] = val; - cookies.add(val); - } - break; - case HASH_PRAGMA: - if (name.equals(PRAGMA)) { - mHeaders[IDX_PRAGMA] = val; - } - break; - case HASH_REFRESH: - if (name.equals(REFRESH)) { - mHeaders[IDX_REFRESH] = val; - } - break; - default: - mExtraHeaderNames.add(name); - mExtraHeaderValues.add(val); - } - } - - public long getTransferEncoding() { - return transferEncoding; - } - - public long getContentLength() { - return contentLength; - } - - public int getConnectionType() { - return connectionType; - } - - public String getContentType() { - return mHeaders[IDX_CONTENT_TYPE]; - } - - public String getContentEncoding() { - return mHeaders[IDX_CONTENT_ENCODING]; - } - - public String getLocation() { - return mHeaders[IDX_LOCATION]; - } - - public String getWwwAuthenticate() { - return mHeaders[IDX_WWW_AUTHENTICATE]; - } - - public String getProxyAuthenticate() { - return mHeaders[IDX_PROXY_AUTHENTICATE]; - } - - public String getContentDisposition() { - return mHeaders[IDX_CONTENT_DISPOSITION]; - } - - public String getAcceptRanges() { - return mHeaders[IDX_ACCEPT_RANGES]; - } - - public String getExpires() { - return mHeaders[IDX_EXPIRES]; - } - - public String getCacheControl() { - return mHeaders[IDX_CACHE_CONTROL]; - } - - public String getLastModified() { - return mHeaders[IDX_LAST_MODIFIED]; - } - - public String getEtag() { - return mHeaders[IDX_ETAG]; - } - - public ArrayList<String> getSetCookie() { - return this.cookies; - } - - public String getPragma() { - return mHeaders[IDX_PRAGMA]; - } - - public String getRefresh() { - return mHeaders[IDX_REFRESH]; - } - - public void setContentLength(long value) { - this.contentLength = value; - } - - public void setContentType(String value) { - mHeaders[IDX_CONTENT_TYPE] = value; - } - - public void setContentEncoding(String value) { - mHeaders[IDX_CONTENT_ENCODING] = value; - } - - public void setLocation(String value) { - mHeaders[IDX_LOCATION] = value; - } - - public void setWwwAuthenticate(String value) { - mHeaders[IDX_WWW_AUTHENTICATE] = value; - } - - public void setProxyAuthenticate(String value) { - mHeaders[IDX_PROXY_AUTHENTICATE] = value; - } - - public void setContentDisposition(String value) { - mHeaders[IDX_CONTENT_DISPOSITION] = value; - } - - public void setAcceptRanges(String value) { - mHeaders[IDX_ACCEPT_RANGES] = value; - } - - public void setExpires(String value) { - mHeaders[IDX_EXPIRES] = value; - } - - public void setCacheControl(String value) { - mHeaders[IDX_CACHE_CONTROL] = value; - } - - public void setLastModified(String value) { - mHeaders[IDX_LAST_MODIFIED] = value; - } - - public void setEtag(String value) { - mHeaders[IDX_ETAG] = value; - } - - public interface HeaderCallback { - public void header(String name, String value); - } - - /** - * Reports all non-null headers to the callback - */ - public void getHeaders(HeaderCallback hcb) { - for (int i = 0; i < HEADER_COUNT; i++) { - String h = mHeaders[i]; - if (h != null) { - hcb.header(sHeaderNames[i], h); - } - } - int extraLen = mExtraHeaderNames.size(); - for (int i = 0; i < extraLen; i++) { - if (Config.LOGV) { - HttpLog.v("Headers.getHeaders() extra: " + i + " " + - mExtraHeaderNames.get(i) + " " + mExtraHeaderValues.get(i)); - } - hcb.header(mExtraHeaderNames.get(i), - mExtraHeaderValues.get(i)); - } - - } - - private void setConnectionType(CharArrayBuffer buffer, int pos) { - if (CharArrayBuffers.containsIgnoreCaseTrimmed( - buffer, pos, HTTP.CONN_CLOSE)) { - connectionType = CONN_CLOSE; - } else if (CharArrayBuffers.containsIgnoreCaseTrimmed( - buffer, pos, HTTP.CONN_KEEP_ALIVE)) { - connectionType = CONN_KEEP_ALIVE; - } - } -} diff --git a/core/java/android/net/http/HttpAuthHeader.java b/core/java/android/net/http/HttpAuthHeader.java deleted file mode 100644 index d41284c..0000000 --- a/core/java/android/net/http/HttpAuthHeader.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -/** - * HttpAuthHeader: a class to store HTTP authentication-header parameters. - * For more information, see: RFC 2617: HTTP Authentication. - * - * {@hide} - */ -public class HttpAuthHeader { - /** - * Possible HTTP-authentication header tokens to search for: - */ - public final static String BASIC_TOKEN = "Basic"; - public final static String DIGEST_TOKEN = "Digest"; - - private final static String REALM_TOKEN = "realm"; - private final static String NONCE_TOKEN = "nonce"; - private final static String STALE_TOKEN = "stale"; - private final static String OPAQUE_TOKEN = "opaque"; - private final static String QOP_TOKEN = "qop"; - private final static String ALGORITHM_TOKEN = "algorithm"; - - /** - * An authentication scheme. We currently support two different schemes: - * HttpAuthHeader.BASIC - basic, and - * HttpAuthHeader.DIGEST - digest (algorithm=MD5, QOP="auth"). - */ - private int mScheme; - - public static final int UNKNOWN = 0; - public static final int BASIC = 1; - public static final int DIGEST = 2; - - /** - * A flag, indicating that the previous request from the client was - * rejected because the nonce value was stale. If stale is TRUE - * (case-insensitive), the client may wish to simply retry the request - * with a new encrypted response, without reprompting the user for a - * new username and password. - */ - private boolean mStale; - - /** - * A string to be displayed to users so they know which username and - * password to use. - */ - private String mRealm; - - /** - * A server-specified data string which should be uniquely generated - * each time a 401 response is made. - */ - private String mNonce; - - /** - * A string of data, specified by the server, which should be returned - * by the client unchanged in the Authorization header of subsequent - * requests with URIs in the same protection space. - */ - private String mOpaque; - - /** - * This directive is optional, but is made so only for backward - * compatibility with RFC 2069 [6]; it SHOULD be used by all - * implementations compliant with this version of the Digest scheme. - * If present, it is a quoted string of one or more tokens indicating - * the "quality of protection" values supported by the server. The - * value "auth" indicates authentication; the value "auth-int" - * indicates authentication with integrity protection. - */ - private String mQop; - - /** - * A string indicating a pair of algorithms used to produce the digest - * and a checksum. If this is not present it is assumed to be "MD5". - */ - private String mAlgorithm; - - /** - * Is this authentication request a proxy authentication request? - */ - private boolean mIsProxy; - - /** - * Username string we get from the user. - */ - private String mUsername; - - /** - * Password string we get from the user. - */ - private String mPassword; - - /** - * Creates a new HTTP-authentication header object from the - * input header string. - * The header string is assumed to contain parameters of at - * most one authentication-scheme (ensured by the caller). - */ - public HttpAuthHeader(String header) { - if (header != null) { - parseHeader(header); - } - } - - /** - * @return True iff this is a proxy authentication header. - */ - public boolean isProxy() { - return mIsProxy; - } - - /** - * Marks this header as a proxy authentication header. - */ - public void setProxy() { - mIsProxy = true; - } - - /** - * @return The username string. - */ - public String getUsername() { - return mUsername; - } - - /** - * Sets the username string. - */ - public void setUsername(String username) { - mUsername = username; - } - - /** - * @return The password string. - */ - public String getPassword() { - return mPassword; - } - - /** - * Sets the password string. - */ - public void setPassword(String password) { - mPassword = password; - } - - /** - * @return True iff this is the BASIC-authentication request. - */ - public boolean isBasic () { - return mScheme == BASIC; - } - - /** - * @return True iff this is the DIGEST-authentication request. - */ - public boolean isDigest() { - return mScheme == DIGEST; - } - - /** - * @return The authentication scheme requested. We currently - * support two schemes: - * HttpAuthHeader.BASIC - basic, and - * HttpAuthHeader.DIGEST - digest (algorithm=MD5, QOP="auth"). - */ - public int getScheme() { - return mScheme; - } - - /** - * @return True if indicating that the previous request from - * the client was rejected because the nonce value was stale. - */ - public boolean getStale() { - return mStale; - } - - /** - * @return The realm value or null if there is none. - */ - public String getRealm() { - return mRealm; - } - - /** - * @return The nonce value or null if there is none. - */ - public String getNonce() { - return mNonce; - } - - /** - * @return The opaque value or null if there is none. - */ - public String getOpaque() { - return mOpaque; - } - - /** - * @return The QOP ("quality-of_protection") value or null if - * there is none. The QOP value is always lower-case. - */ - public String getQop() { - return mQop; - } - - /** - * @return The name of the algorithm used or null if there is - * none. By default, MD5 is used. - */ - public String getAlgorithm() { - return mAlgorithm; - } - - /** - * @return True iff the authentication scheme requested by the - * server is supported; currently supported schemes: - * BASIC, - * DIGEST (only algorithm="md5", no qop or qop="auth). - */ - public boolean isSupportedScheme() { - // it is a good idea to enforce non-null realms! - if (mRealm != null) { - if (mScheme == BASIC) { - return true; - } else { - if (mScheme == DIGEST) { - return - mAlgorithm.equals("md5") && - (mQop == null || mQop.equals("auth")); - } - } - } - - return false; - } - - /** - * Parses the header scheme name and then scheme parameters if - * the scheme is supported. - */ - private void parseHeader(String header) { - if (HttpLog.LOGV) { - HttpLog.v("HttpAuthHeader.parseHeader(): header: " + header); - } - - if (header != null) { - String parameters = parseScheme(header); - if (parameters != null) { - // if we have a supported scheme - if (mScheme != UNKNOWN) { - parseParameters(parameters); - } - } - } - } - - /** - * Parses the authentication scheme name. If we have a Digest - * scheme, sets the algorithm value to the default of MD5. - * @return The authentication scheme parameters string to be - * parsed later (if the scheme is supported) or null if failed - * to parse the scheme (the header value is null?). - */ - private String parseScheme(String header) { - if (header != null) { - int i = header.indexOf(' '); - if (i >= 0) { - String scheme = header.substring(0, i).trim(); - if (scheme.equalsIgnoreCase(DIGEST_TOKEN)) { - mScheme = DIGEST; - - // md5 is the default algorithm!!! - mAlgorithm = "md5"; - } else { - if (scheme.equalsIgnoreCase(BASIC_TOKEN)) { - mScheme = BASIC; - } - } - - return header.substring(i + 1); - } - } - - return null; - } - - /** - * Parses a comma-separated list of authentification scheme - * parameters. - */ - private void parseParameters(String parameters) { - if (HttpLog.LOGV) { - HttpLog.v("HttpAuthHeader.parseParameters():" + - " parameters: " + parameters); - } - - if (parameters != null) { - int i; - do { - i = parameters.indexOf(','); - if (i < 0) { - // have only one parameter - parseParameter(parameters); - } else { - parseParameter(parameters.substring(0, i)); - parameters = parameters.substring(i + 1); - } - } while (i >= 0); - } - } - - /** - * Parses a single authentication scheme parameter. The parameter - * string is expected to follow the format: PARAMETER=VALUE. - */ - private void parseParameter(String parameter) { - if (parameter != null) { - // here, we are looking for the 1st occurence of '=' only!!! - int i = parameter.indexOf('='); - if (i >= 0) { - String token = parameter.substring(0, i).trim(); - String value = - trimDoubleQuotesIfAny(parameter.substring(i + 1).trim()); - - if (HttpLog.LOGV) { - HttpLog.v("HttpAuthHeader.parseParameter():" + - " token: " + token + - " value: " + value); - } - - if (token.equalsIgnoreCase(REALM_TOKEN)) { - mRealm = value; - } else { - if (mScheme == DIGEST) { - parseParameter(token, value); - } - } - } - } - } - - /** - * If the token is a known parameter name, parses and initializes - * the token value. - */ - private void parseParameter(String token, String value) { - if (token != null && value != null) { - if (token.equalsIgnoreCase(NONCE_TOKEN)) { - mNonce = value; - return; - } - - if (token.equalsIgnoreCase(STALE_TOKEN)) { - parseStale(value); - return; - } - - if (token.equalsIgnoreCase(OPAQUE_TOKEN)) { - mOpaque = value; - return; - } - - if (token.equalsIgnoreCase(QOP_TOKEN)) { - mQop = value.toLowerCase(); - return; - } - - if (token.equalsIgnoreCase(ALGORITHM_TOKEN)) { - mAlgorithm = value.toLowerCase(); - return; - } - } - } - - /** - * Parses and initializes the 'stale' paramer value. Any value - * different from case-insensitive "true" is considered "false". - */ - private void parseStale(String value) { - if (value != null) { - if (value.equalsIgnoreCase("true")) { - mStale = true; - } - } - } - - /** - * Trims double-quotes around a parameter value if there are any. - * @return The string value without the outermost pair of double- - * quotes or null if the original value is null. - */ - static private String trimDoubleQuotesIfAny(String value) { - if (value != null) { - int len = value.length(); - if (len > 2 && - value.charAt(0) == '\"' && value.charAt(len - 1) == '\"') { - return value.substring(1, len - 1); - } - } - - return value; - } -} diff --git a/core/java/android/net/http/HttpConnection.java b/core/java/android/net/http/HttpConnection.java deleted file mode 100644 index 8b12d0b..0000000 --- a/core/java/android/net/http/HttpConnection.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.content.Context; - -import java.net.Socket; -import java.io.IOException; - -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpHost; -import org.apache.http.impl.DefaultHttpClientConnection; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; - -/** - * A requestConnection connecting to a normal (non secure) http server - * - * {@hide} - */ -class HttpConnection extends Connection { - - HttpConnection(Context context, HttpHost host, - RequestQueue.ConnectionManager connectionManager, - RequestFeeder requestFeeder) { - super(context, host, connectionManager, requestFeeder); - } - - /** - * Opens the connection to a http server - * - * @return the opened low level connection - * @throws IOException if the connection fails for any reason. - */ - @Override - AndroidHttpClientConnection openConnection(Request req) throws IOException { - - // Update the certificate info (connection not secure - set to null) - EventHandler eventHandler = req.getEventHandler(); - mCertificate = null; - eventHandler.certificate(mCertificate); - - AndroidHttpClientConnection conn = new AndroidHttpClientConnection(); - BasicHttpParams params = new BasicHttpParams(); - Socket sock = new Socket(mHost.getHostName(), mHost.getPort()); - params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192); - conn.bind(sock, params); - return conn; - } - - /** - * Closes the low level connection. - * - * If an exception is thrown then it is assumed that the - * connection will have been closed (to the extent possible) - * anyway and the caller does not need to take any further action. - * - */ - void closeConnection() { - try { - if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) { - mHttpClientConnection.close(); - } - } catch (IOException e) { - if (HttpLog.LOGV) HttpLog.v( - "closeConnection(): failed closing connection " + - mHost); - e.printStackTrace(); - } - } - - /** - * Restart a secure connection suspended waiting for user interaction. - */ - void restartConnection(boolean abort) { - // not required for plain http connections - } - - String getScheme() { - return "http"; - } -} diff --git a/core/java/android/net/http/HttpLog.java b/core/java/android/net/http/HttpLog.java deleted file mode 100644 index 30bf647..0000000 --- a/core/java/android/net/http/HttpLog.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * package-level logging flag - */ - -package android.net.http; - -import android.os.SystemClock; - -import android.util.Log; -import android.util.Config; - -/** - * {@hide} - */ -class HttpLog { - private final static String LOGTAG = "http"; - - private static final boolean DEBUG = false; - static final boolean LOGV = DEBUG ? Config.LOGD : Config.LOGV; - - static void v(String logMe) { - Log.v(LOGTAG, SystemClock.uptimeMillis() + " " + Thread.currentThread().getName() + " " + logMe); - } - - static void e(String logMe) { - Log.e(LOGTAG, logMe); - } -} diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java deleted file mode 100644 index fe02d3e..0000000 --- a/core/java/android/net/http/HttpsConnection.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.content.Context; - -import junit.framework.Assert; - -import java.io.IOException; - -import java.security.cert.X509Certificate; - -import java.net.Socket; -import java.net.InetSocketAddress; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.apache.http.Header; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.ParseException; -import org.apache.http.ProtocolVersion; -import org.apache.http.StatusLine; -import org.apache.http.impl.DefaultHttpClientConnection; -import org.apache.http.message.BasicHttpRequest; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpConnectionParams; - -/** - * Simple exception we throw if the SSL connection is closed by the user. - * - * {@hide} - */ -class SSLConnectionClosedByUserException extends SSLException { - - public SSLConnectionClosedByUserException(String reason) { - super(reason); - } -} - -/** - * A Connection connecting to a secure http server or tunneling through - * a http proxy server to a https server. - */ -class HttpsConnection extends Connection { - - /** - * SSL context - */ - private static SSLContext mSslContext = null; - - /** - * SSL socket factory - */ - private static SSLSocketFactory mSslSocketFactory = null; - - static { - // initialize the socket factory - try { - mSslContext = SSLContext.getInstance("TLS"); - if (mSslContext != null) { - // here, trust managers is a single trust-all manager - TrustManager[] trustManagers = new TrustManager[] { - new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted( - X509Certificate[] certs, String authType) { - } - - public void checkServerTrusted( - X509Certificate[] certs, String authType) { - } - } - }; - - mSslContext.init(null, trustManagers, null); - mSslSocketFactory = mSslContext.getSocketFactory(); - } - } catch (Exception t) { - if (HttpLog.LOGV) { - HttpLog.v("HttpsConnection: failed to initialize the socket factory"); - } - } - } - - /** - * @return The shared SSL context. - */ - /*package*/ static SSLContext getContext() { - return mSslContext; - } - - /** - * Object to wait on when suspending the SSL connection - */ - private Object mSuspendLock = new Object(); - - /** - * True if the connection is suspended pending the result of asking the - * user about an error. - */ - private boolean mSuspended = false; - - /** - * True if the connection attempt should be aborted due to an ssl - * error. - */ - private boolean mAborted = false; - - /** - * Contructor for a https connection. - */ - HttpsConnection(Context context, HttpHost host, - RequestQueue.ConnectionManager connectionManager, - RequestFeeder requestFeeder) { - super(context, host, connectionManager, requestFeeder); - } - - /** - * Sets the server SSL certificate associated with this - * connection. - * @param certificate The SSL certificate - */ - /* package */ void setCertificate(SslCertificate certificate) { - mCertificate = certificate; - } - - /** - * Opens the connection to a http server or proxy. - * - * @return the opened low level connection - * @throws IOException if the connection fails for any reason. - */ - @Override - AndroidHttpClientConnection openConnection(Request req) throws IOException { - SSLSocket sslSock = null; - - HttpHost proxyHost = mConnectionManager.getProxyHost(); - if (proxyHost != null) { - // If we have a proxy set, we first send a CONNECT request - // to the proxy; if the proxy returns 200 OK, we negotiate - // a secure connection to the target server via the proxy. - // If the request fails, we drop it, but provide the event - // handler with the response status and headers. The event - // handler is then responsible for cancelling the load or - // issueing a new request. - AndroidHttpClientConnection proxyConnection = null; - Socket proxySock = null; - try { - proxySock = new Socket - (proxyHost.getHostName(), proxyHost.getPort()); - - proxySock.setSoTimeout(60 * 1000); - - proxyConnection = new AndroidHttpClientConnection(); - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSocketBufferSize(params, 8192); - - proxyConnection.bind(proxySock, params); - } catch(IOException e) { - if (proxyConnection != null) { - proxyConnection.close(); - } - - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = - "failed to establish a connection to the proxy"; - } - - throw new IOException(errorMessage); - } - - StatusLine statusLine = null; - int statusCode = 0; - Headers headers = new Headers(); - try { - BasicHttpRequest proxyReq = new BasicHttpRequest - ("CONNECT", mHost.toHostString()); - - // add all 'proxy' headers from the original request - for (Header h : req.mHttpRequest.getAllHeaders()) { - String headerName = h.getName().toLowerCase(); - if (headerName.startsWith("proxy") || headerName.equals("keep-alive")) { - proxyReq.addHeader(h); - } - } - - proxyConnection.sendRequestHeader(proxyReq); - proxyConnection.flush(); - - // it is possible to receive informational status - // codes prior to receiving actual headers; - // all those status codes are smaller than OK 200 - // a loop is a standard way of dealing with them - do { - statusLine = proxyConnection.parseResponseHeader(headers); - statusCode = statusLine.getStatusCode(); - } while (statusCode < HttpStatus.SC_OK); - } catch (ParseException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = - "failed to send a CONNECT request"; - } - - throw new IOException(errorMessage); - } catch (HttpException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = - "failed to send a CONNECT request"; - } - - throw new IOException(errorMessage); - } catch (IOException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = - "failed to send a CONNECT request"; - } - - throw new IOException(errorMessage); - } - - if (statusCode == HttpStatus.SC_OK) { - try { - synchronized (mSslSocketFactory) { - sslSock = (SSLSocket) mSslSocketFactory.createSocket( - proxySock, mHost.getHostName(), mHost.getPort(), true); - } - } catch(IOException e) { - if (sslSock != null) { - sslSock.close(); - } - - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = - "failed to create an SSL socket"; - } - throw new IOException(errorMessage); - } - } else { - // if the code is not OK, inform the event handler - ProtocolVersion version = statusLine.getProtocolVersion(); - - req.mEventHandler.status(version.getMajor(), - version.getMinor(), - statusCode, - statusLine.getReasonPhrase()); - req.mEventHandler.headers(headers); - req.mEventHandler.endData(); - - proxyConnection.close(); - - // here, we return null to indicate that the original - // request needs to be dropped - return null; - } - } else { - // if we do not have a proxy, we simply connect to the host - try { - synchronized (mSslSocketFactory) { - sslSock = (SSLSocket) mSslSocketFactory.createSocket(); - - sslSock.setSoTimeout(SOCKET_TIMEOUT); - sslSock.connect(new InetSocketAddress(mHost.getHostName(), - mHost.getPort())); - - } - } catch(IOException e) { - if (sslSock != null) { - sslSock.close(); - } - - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "failed to create an SSL socket"; - } - - throw new IOException(errorMessage); - } - } - - // do handshake and validate server certificates - SslError error = CertificateChainValidator.getInstance(). - doHandshakeAndValidateServerCertificates(this, sslSock, mHost.getHostName()); - - EventHandler eventHandler = req.getEventHandler(); - - // Update the certificate info (to be consistent, it is better to do it - // here, before we start handling SSL errors, if any) - eventHandler.certificate(mCertificate); - - // Inform the user if there is a problem - if (error != null) { - // handleSslErrorRequest may immediately unsuspend if it wants to - // allow the certificate anyway. - // So we mark the connection as suspended, call handleSslErrorRequest - // then check if we're still suspended and only wait if we actually - // need to. - synchronized (mSuspendLock) { - mSuspended = true; - } - // don't hold the lock while calling out to the event handler - eventHandler.handleSslErrorRequest(error); - synchronized (mSuspendLock) { - if (mSuspended) { - try { - // Put a limit on how long we are waiting; if the timeout - // expires (which should never happen unless you choose - // to ignore the SSL error dialog for a very long time), - // we wake up the thread and abort the request. This is - // to prevent us from stalling the network if things go - // very bad. - mSuspendLock.wait(10 * 60 * 1000); - if (mSuspended) { - // mSuspended is true if we have not had a chance to - // restart the connection yet (ie, the wait timeout - // has expired) - mSuspended = false; - mAborted = true; - if (HttpLog.LOGV) { - HttpLog.v("HttpsConnection.openConnection():" + - " SSL timeout expired and request was cancelled!!!"); - } - } - } catch (InterruptedException e) { - // ignore - } - } - if (mAborted) { - // The user decided not to use this unverified connection - // so close it immediately. - sslSock.close(); - throw new SSLConnectionClosedByUserException("connection closed by the user"); - } - } - } - - // All went well, we have an open, verified connection. - AndroidHttpClientConnection conn = new AndroidHttpClientConnection(); - BasicHttpParams params = new BasicHttpParams(); - params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192); - conn.bind(sslSock, params); - return conn; - } - - /** - * Closes the low level connection. - * - * If an exception is thrown then it is assumed that the connection will - * have been closed (to the extent possible) anyway and the caller does not - * need to take any further action. - * - */ - @Override - void closeConnection() { - // if the connection has been suspended due to an SSL error - if (mSuspended) { - // wake up the network thread - restartConnection(false); - } - - try { - if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) { - mHttpClientConnection.close(); - } - } catch (IOException e) { - if (HttpLog.LOGV) - HttpLog.v("HttpsConnection.closeConnection():" + - " failed closing connection " + mHost); - e.printStackTrace(); - } - } - - /** - * Restart a secure connection suspended waiting for user interaction. - */ - void restartConnection(boolean proceed) { - if (HttpLog.LOGV) { - HttpLog.v("HttpsConnection.restartConnection():" + - " proceed: " + proceed); - } - - synchronized (mSuspendLock) { - if (mSuspended) { - mSuspended = false; - mAborted = !proceed; - mSuspendLock.notify(); - } - } - } - - @Override - String getScheme() { - return "https"; - } -} diff --git a/core/java/android/net/http/IdleCache.java b/core/java/android/net/http/IdleCache.java deleted file mode 100644 index fda6009..0000000 --- a/core/java/android/net/http/IdleCache.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Hangs onto idle live connections for a little while - */ - -package android.net.http; - -import org.apache.http.HttpHost; - -import android.os.SystemClock; - -/** - * {@hide} - */ -class IdleCache { - - class Entry { - HttpHost mHost; - Connection mConnection; - long mTimeout; - }; - - private final static int IDLE_CACHE_MAX = 8; - - /* Allow five consecutive empty queue checks before shutdown */ - private final static int EMPTY_CHECK_MAX = 5; - - /* six second timeout for connections */ - private final static int TIMEOUT = 6 * 1000; - private final static int CHECK_INTERVAL = 2 * 1000; - private Entry[] mEntries = new Entry[IDLE_CACHE_MAX]; - - private int mCount = 0; - - private IdleReaper mThread = null; - - /* stats */ - private int mCached = 0; - private int mReused = 0; - - IdleCache() { - for (int i = 0; i < IDLE_CACHE_MAX; i++) { - mEntries[i] = new Entry(); - } - } - - /** - * Caches connection, if there is room. - * @return true if connection cached - */ - synchronized boolean cacheConnection( - HttpHost host, Connection connection) { - - boolean ret = false; - - if (HttpLog.LOGV) { - HttpLog.v("IdleCache size " + mCount + " host " + host); - } - - if (mCount < IDLE_CACHE_MAX) { - long time = SystemClock.uptimeMillis(); - for (int i = 0; i < IDLE_CACHE_MAX; i++) { - Entry entry = mEntries[i]; - if (entry.mHost == null) { - entry.mHost = host; - entry.mConnection = connection; - entry.mTimeout = time + TIMEOUT; - mCount++; - if (HttpLog.LOGV) mCached++; - ret = true; - if (mThread == null) { - mThread = new IdleReaper(); - mThread.start(); - } - break; - } - } - } - return ret; - } - - synchronized Connection getConnection(HttpHost host) { - Connection ret = null; - - if (mCount > 0) { - for (int i = 0; i < IDLE_CACHE_MAX; i++) { - Entry entry = mEntries[i]; - HttpHost eHost = entry.mHost; - if (eHost != null && eHost.equals(host)) { - ret = entry.mConnection; - entry.mHost = null; - entry.mConnection = null; - mCount--; - if (HttpLog.LOGV) mReused++; - break; - } - } - } - return ret; - } - - synchronized void clear() { - for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) { - Entry entry = mEntries[i]; - if (entry.mHost != null) { - entry.mHost = null; - entry.mConnection.closeConnection(); - entry.mConnection = null; - mCount--; - } - } - } - - private synchronized void clearIdle() { - if (mCount > 0) { - long time = SystemClock.uptimeMillis(); - for (int i = 0; i < IDLE_CACHE_MAX; i++) { - Entry entry = mEntries[i]; - if (entry.mHost != null && time > entry.mTimeout) { - entry.mHost = null; - entry.mConnection.closeConnection(); - entry.mConnection = null; - mCount--; - } - } - } - } - - private class IdleReaper extends Thread { - - public void run() { - int check = 0; - - setName("IdleReaper"); - android.os.Process.setThreadPriority( - android.os.Process.THREAD_PRIORITY_BACKGROUND); - synchronized (IdleCache.this) { - while (check < EMPTY_CHECK_MAX) { - try { - IdleCache.this.wait(CHECK_INTERVAL); - } catch (InterruptedException ex) { - } - if (mCount == 0) { - check++; - } else { - check = 0; - clearIdle(); - } - } - mThread = null; - } - if (HttpLog.LOGV) { - HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached + - " reused " + mReused); - mCached = 0; - mReused = 0; - } - } - } -} diff --git a/core/java/android/net/http/LoggingEventHandler.java b/core/java/android/net/http/LoggingEventHandler.java deleted file mode 100644 index 1b18651..0000000 --- a/core/java/android/net/http/LoggingEventHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A test EventHandler: Logs everything received - */ - -package android.net.http; - -import android.net.http.Headers; - -/** - * {@hide} - */ -public class LoggingEventHandler implements EventHandler { - - public void requestSent() { - HttpLog.v("LoggingEventHandler:requestSent()"); - } - - public void status(int major_version, - int minor_version, - int code, /* Status-Code value */ - String reason_phrase) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler:status() major: " + major_version + - " minor: " + minor_version + - " code: " + code + - " reason: " + reason_phrase); - } - } - - public void headers(Headers headers) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler:headers()"); - HttpLog.v(headers.toString()); - } - } - - public void locationChanged(String newLocation, boolean permanent) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler: locationChanged() " + newLocation + - " permanent " + permanent); - } - } - - public void data(byte[] data, int len) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler: data() " + len + " bytes"); - } - // HttpLog.v(new String(data, 0, len)); - } - public void endData() { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler: endData() called"); - } - } - - public void certificate(SslCertificate certificate) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler: certificate(): " + certificate); - } - } - - public void error(int id, String description) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler: error() called Id:" + id + - " description " + description); - } - } - - public void handleSslErrorRequest(SslError error) { - if (HttpLog.LOGV) { - HttpLog.v("LoggingEventHandler: handleSslErrorRequest():" + error); - } - } -} diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java deleted file mode 100644 index df4fff0..0000000 --- a/core/java/android/net/http/Request.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import java.io.EOFException; -import java.io.InputStream; -import java.io.IOException; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.zip.GZIPInputStream; - -import org.apache.http.entity.InputStreamEntity; -import org.apache.http.Header; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.ParseException; -import org.apache.http.ProtocolVersion; - -import org.apache.http.StatusLine; -import org.apache.http.message.BasicHttpRequest; -import org.apache.http.message.BasicHttpEntityEnclosingRequest; -import org.apache.http.protocol.RequestContent; - -/** - * Represents an HTTP request for a given host. - * - * {@hide} - */ - -class Request { - - /** The eventhandler to call as the request progresses */ - EventHandler mEventHandler; - - private Connection mConnection; - - /** The Apache http request */ - BasicHttpRequest mHttpRequest; - - /** The path component of this request */ - String mPath; - - /** Host serving this request */ - HttpHost mHost; - - /** Set if I'm using a proxy server */ - HttpHost mProxyHost; - - /** True if request is .html, .js, .css */ - boolean mHighPriority; - - /** True if request has been cancelled */ - volatile boolean mCancelled = false; - - int mFailCount = 0; - - private InputStream mBodyProvider; - private int mBodyLength; - - private final static String HOST_HEADER = "Host"; - private final static String ACCEPT_ENCODING_HEADER = "Accept-Encoding"; - private final static String CONTENT_LENGTH_HEADER = "content-length"; - - /* Used to synchronize waitUntilComplete() requests */ - private final Object mClientResource = new Object(); - - /** - * Processor used to set content-length and transfer-encoding - * headers. - */ - private static RequestContent requestContentProcessor = - new RequestContent(); - - /** - * Instantiates a new Request. - * @param method GET/POST/PUT - * @param host The server that will handle this request - * @param path path part of URI - * @param bodyProvider InputStream providing HTTP body, null if none - * @param bodyLength length of body, must be 0 if bodyProvider is null - * @param eventHandler request will make progress callbacks on - * this interface - * @param headers reqeust headers - * @param highPriority true for .html, css, .cs - */ - Request(String method, HttpHost host, HttpHost proxyHost, String path, - InputStream bodyProvider, int bodyLength, - EventHandler eventHandler, - Map<String, String> headers, boolean highPriority) { - mEventHandler = eventHandler; - mHost = host; - mProxyHost = proxyHost; - mPath = path; - mHighPriority = highPriority; - mBodyProvider = bodyProvider; - mBodyLength = bodyLength; - - if (bodyProvider == null) { - mHttpRequest = new BasicHttpRequest(method, getUri()); - } else { - mHttpRequest = new BasicHttpEntityEnclosingRequest( - method, getUri()); - setBodyProvider(bodyProvider, bodyLength); - } - addHeader(HOST_HEADER, getHostPort()); - - /* FIXME: if webcore will make the root document a - high-priority request, we can ask for gzip encoding only on - high priority reqs (saving the trouble for images, etc) */ - addHeader(ACCEPT_ENCODING_HEADER, "gzip"); - addHeaders(headers); - } - - /** - * @param connection Request served by this connection - */ - void setConnection(Connection connection) { - mConnection = connection; - } - - /* package */ EventHandler getEventHandler() { - return mEventHandler; - } - - /** - * Add header represented by given pair to request. Header will - * be formatted in request as "name: value\r\n". - * @param name of header - * @param value of header - */ - void addHeader(String name, String value) { - if (name == null) { - String damage = "Null http header name"; - HttpLog.e(damage); - throw new NullPointerException(damage); - } - if (value == null || value.length() == 0) { - String damage = "Null or empty value for header \"" + name + "\""; - HttpLog.e(damage); - throw new RuntimeException(damage); - } - mHttpRequest.addHeader(name, value); - } - - /** - * Add all headers in given map to this request. This is a helper - * method: it calls addHeader for each pair in the map. - */ - void addHeaders(Map<String, String> headers) { - if (headers == null) { - return; - } - - Entry<String, String> entry; - Iterator<Entry<String, String>> i = headers.entrySet().iterator(); - while (i.hasNext()) { - entry = i.next(); - addHeader(entry.getKey(), entry.getValue()); - } - } - - /** - * Send the request line and headers - */ - void sendRequest(AndroidHttpClientConnection httpClientConnection) - throws HttpException, IOException { - - if (mCancelled) return; // don't send cancelled requests - - if (HttpLog.LOGV) { - HttpLog.v("Request.sendRequest() " + mHost.getSchemeName() + "://" + getHostPort()); - // HttpLog.v(mHttpRequest.getRequestLine().toString()); - if (false) { - Iterator i = mHttpRequest.headerIterator(); - while (i.hasNext()) { - Header header = (Header)i.next(); - HttpLog.v(header.getName() + ": " + header.getValue()); - } - } - } - - requestContentProcessor.process(mHttpRequest, - mConnection.getHttpContext()); - httpClientConnection.sendRequestHeader(mHttpRequest); - if (mHttpRequest instanceof HttpEntityEnclosingRequest) { - httpClientConnection.sendRequestEntity( - (HttpEntityEnclosingRequest) mHttpRequest); - } - - if (HttpLog.LOGV) { - HttpLog.v("Request.requestSent() " + mHost.getSchemeName() + "://" + getHostPort() + mPath); - } - } - - - /** - * Receive a single http response. - * - * @param httpClientConnection the request to receive the response for. - */ - void readResponse(AndroidHttpClientConnection httpClientConnection) - throws IOException, ParseException { - - if (mCancelled) return; // don't send cancelled requests - - StatusLine statusLine = null; - boolean hasBody = false; - boolean reuse = false; - httpClientConnection.flush(); - int statusCode = 0; - - Headers header = new Headers(); - do { - statusLine = httpClientConnection.parseResponseHeader(header); - statusCode = statusLine.getStatusCode(); - } while (statusCode < HttpStatus.SC_OK); - if (HttpLog.LOGV) HttpLog.v( - "Request.readResponseStatus() " + - statusLine.toString().length() + " " + statusLine); - - ProtocolVersion v = statusLine.getProtocolVersion(); - mEventHandler.status(v.getMajor(), v.getMinor(), - statusCode, statusLine.getReasonPhrase()); - mEventHandler.headers(header); - HttpEntity entity = null; - hasBody = canResponseHaveBody(mHttpRequest, statusCode); - - if (hasBody) - entity = httpClientConnection.receiveResponseEntity(header); - - if (entity != null) { - InputStream is = entity.getContent(); - - // process gzip content encoding - Header contentEncoding = entity.getContentEncoding(); - InputStream nis = null; - try { - if (contentEncoding != null && - contentEncoding.getValue().equals("gzip")) { - nis = new GZIPInputStream(is); - } else { - nis = is; - } - - /* accumulate enough data to make it worth pushing it - * up the stack */ - byte[] buf = mConnection.getBuf(); - int len = 0; - int count = 0; - int lowWater = buf.length / 2; - while (len != -1) { - len = nis.read(buf, count, buf.length - count); - if (len != -1) { - count += len; - } - if (len == -1 || count >= lowWater) { - if (HttpLog.LOGV) HttpLog.v("Request.readResponse() " + count); - mEventHandler.data(buf, count); - count = 0; - } - } - } catch (EOFException e) { - /* InflaterInputStream throws an EOFException when the - server truncates gzipped content. Handle this case - as we do truncated non-gzipped content: no error */ - if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e); - } catch(IOException e) { - // don't throw if we have a non-OK status code - if (statusCode == HttpStatus.SC_OK) { - throw e; - } - } finally { - if (nis != null) { - nis.close(); - } - } - } - mConnection.setCanPersist(entity, statusLine.getProtocolVersion(), - header.getConnectionType()); - mEventHandler.endData(); - complete(); - - if (HttpLog.LOGV) HttpLog.v("Request.readResponse(): done " + - mHost.getSchemeName() + "://" + getHostPort() + mPath); - } - - /** - * Data will not be sent to or received from server after cancel() - * call. Does not close connection--use close() below for that. - * - * Called by RequestHandle from non-network thread - */ - void cancel() { - if (HttpLog.LOGV) { - HttpLog.v("Request.cancel(): " + getUri()); - } - mCancelled = true; - if (mConnection != null) { - mConnection.cancel(); - } - } - - String getHostPort() { - String myScheme = mHost.getSchemeName(); - int myPort = mHost.getPort(); - - // Only send port when we must... many servers can't deal with it - if (myPort != 80 && myScheme.equals("http") || - myPort != 443 && myScheme.equals("https")) { - return mHost.toHostString(); - } else { - return mHost.getHostName(); - } - } - - String getUri() { - if (mProxyHost == null || - mHost.getSchemeName().equals("https")) { - return mPath; - } - return mHost.getSchemeName() + "://" + getHostPort() + mPath; - } - - /** - * for debugging - */ - public String toString() { - return (mHighPriority ? "P*" : "") + mPath; - } - - - /** - * If this request has been sent once and failed, it must be reset - * before it can be sent again. - */ - void reset() { - /* clear content-length header */ - mHttpRequest.removeHeaders(CONTENT_LENGTH_HEADER); - - if (mBodyProvider != null) { - try { - mBodyProvider.reset(); - } catch (IOException ex) { - if (HttpLog.LOGV) HttpLog.v( - "failed to reset body provider " + - getUri()); - } - setBodyProvider(mBodyProvider, mBodyLength); - } - } - - /** - * Pause thread request completes. Used for synchronous requests, - * and testing - */ - void waitUntilComplete() { - synchronized (mClientResource) { - try { - if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete()"); - mClientResource.wait(); - if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete() done waiting"); - } catch (InterruptedException e) { - } - } - } - - void complete() { - synchronized (mClientResource) { - mClientResource.notifyAll(); - } - } - - /** - * Decide whether a response comes with an entity. - * The implementation in this class is based on RFC 2616. - * Unknown methods and response codes are supposed to - * indicate responses with an entity. - * <br/> - * Derived executors can override this method to handle - * methods and response codes not specified in RFC 2616. - * - * @param request the request, to obtain the executed method - * @param response the response, to obtain the status code - */ - - private static boolean canResponseHaveBody(final HttpRequest request, - final int status) { - - if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) { - return false; - } - return status >= HttpStatus.SC_OK - && status != HttpStatus.SC_NO_CONTENT - && status != HttpStatus.SC_NOT_MODIFIED - && status != HttpStatus.SC_RESET_CONTENT; - } - - /** - * Supply an InputStream that provides the body of a request. It's - * not great that the caller must also provide the length of the data - * returned by that InputStream, but the client needs to know up - * front, and I'm not sure how to get this out of the InputStream - * itself without a costly readthrough. I'm not sure skip() would - * do what we want. If you know a better way, please let me know. - */ - private void setBodyProvider(InputStream bodyProvider, int bodyLength) { - if (!bodyProvider.markSupported()) { - throw new IllegalArgumentException( - "bodyProvider must support mark()"); - } - // Mark beginning of stream - bodyProvider.mark(Integer.MAX_VALUE); - - ((BasicHttpEntityEnclosingRequest)mHttpRequest).setEntity( - new InputStreamEntity(bodyProvider, bodyLength)); - } - - - /** - * Handles SSL error(s) on the way down from the user (the user - * has already provided their feedback). - */ - public void handleSslErrorResponse(boolean proceed) { - HttpsConnection connection = (HttpsConnection)(mConnection); - if (connection != null) { - connection.restartConnection(proceed); - } - } - - /** - * Helper: calls error() on eventhandler with appropriate message - * This should not be called before the mConnection is set. - */ - void error(int errorId, int resourceId) { - mEventHandler.error( - errorId, - mConnection.mContext.getText( - resourceId).toString()); - } - -} diff --git a/core/java/android/net/http/RequestFeeder.java b/core/java/android/net/http/RequestFeeder.java deleted file mode 100644 index 34ca267..0000000 --- a/core/java/android/net/http/RequestFeeder.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Supplies Requests to a Connection - */ - -package android.net.http; - -import org.apache.http.HttpHost; - -/** - * {@hide} - */ -interface RequestFeeder { - - Request getRequest(); - Request getRequest(HttpHost host); - - /** - * @return true if a request for this host is available - */ - boolean haveRequest(HttpHost host); - - /** - * Put request back on head of queue - */ - void requeueRequest(Request request); -} diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java deleted file mode 100644 index c4ee5b0..0000000 --- a/core/java/android/net/http/RequestHandle.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.net.ParseException; -import android.net.WebAddress; -import android.security.Md5MessageDigest; -import junit.framework.Assert; -import android.webkit.CookieManager; - -import org.apache.commons.codec.binary.Base64; - -import java.io.InputStream; -import java.lang.Math; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -/** - * RequestHandle: handles a request session that may include multiple - * redirects, HTTP authentication requests, etc. - * - * {@hide} - */ -public class RequestHandle { - - private String mUrl; - private WebAddress mUri; - private String mMethod; - private Map<String, String> mHeaders; - - private RequestQueue mRequestQueue; - - private Request mRequest; - - private InputStream mBodyProvider; - private int mBodyLength; - - private int mRedirectCount = 0; - - private final static String AUTHORIZATION_HEADER = "Authorization"; - private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization"; - - public final static int MAX_REDIRECT_COUNT = 16; - - /** - * Creates a new request session. - */ - public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri, - String method, Map<String, String> headers, - InputStream bodyProvider, int bodyLength, Request request) { - - if (headers == null) { - headers = new HashMap<String, String>(); - } - mHeaders = headers; - mBodyProvider = bodyProvider; - mBodyLength = bodyLength; - mMethod = method == null? "GET" : method; - - mUrl = url; - mUri = uri; - - mRequestQueue = requestQueue; - - mRequest = request; - } - - /** - * Cancels this request - */ - public void cancel() { - if (mRequest != null) { - mRequest.cancel(); - } - } - - /** - * Handles SSL error(s) on the way down from the user (the user - * has already provided their feedback). - */ - public void handleSslErrorResponse(boolean proceed) { - if (mRequest != null) { - mRequest.handleSslErrorResponse(proceed); - } - } - - /** - * @return true if we've hit the max redirect count - */ - public boolean isRedirectMax() { - return mRedirectCount >= MAX_REDIRECT_COUNT; - } - - public int getRedirectCount() { - return mRedirectCount; - } - - public void setRedirectCount(int count) { - mRedirectCount = count; - } - - /** - * Create and queue a redirect request. - * - * @param redirectTo URL to redirect to - * @param statusCode HTTP status code returned from original request - * @param cacheHeaders Cache header for redirect URL - * @return true if setup succeeds, false otherwise (redirect loop - * count exceeded, body provider unable to rewind on 307 redirect) - */ - public boolean setupRedirect(String redirectTo, int statusCode, - Map<String, String> cacheHeaders) { - if (HttpLog.LOGV) { - HttpLog.v("RequestHandle.setupRedirect(): redirectCount " + - mRedirectCount); - } - - // be careful and remove authentication headers, if any - mHeaders.remove(AUTHORIZATION_HEADER); - mHeaders.remove(PROXY_AUTHORIZATION_HEADER); - - if (++mRedirectCount == MAX_REDIRECT_COUNT) { - // Way too many redirects -- fail out - if (HttpLog.LOGV) HttpLog.v( - "RequestHandle.setupRedirect(): too many redirects " + - mRequest); - mRequest.error(EventHandler.ERROR_REDIRECT_LOOP, - com.android.internal.R.string.httpErrorRedirectLoop); - return false; - } - - if (mUrl.startsWith("https:") && redirectTo.startsWith("http:")) { - // implement http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3 - if (HttpLog.LOGV) { - HttpLog.v("blowing away the referer on an https -> http redirect"); - } - mHeaders.remove("Referer"); - } - - mUrl = redirectTo; - try { - mUri = new WebAddress(mUrl); - } catch (ParseException e) { - e.printStackTrace(); - } - - // update the "cookie" header based on the redirected url - mHeaders.remove("cookie"); - String cookie = CookieManager.getInstance().getCookie(mUri); - if (cookie != null && cookie.length() > 0) { - mHeaders.put("cookie", cookie); - } - - if ((statusCode == 302 || statusCode == 303) && mMethod.equals("POST")) { - if (HttpLog.LOGV) { - HttpLog.v("replacing POST with GET on redirect to " + redirectTo); - } - mMethod = "GET"; - } - /* Only repost content on a 307. If 307, reset the body - provider so we can replay the body */ - if (statusCode == 307) { - try { - if (mBodyProvider != null) mBodyProvider.reset(); - } catch (java.io.IOException ex) { - if (HttpLog.LOGV) { - HttpLog.v("setupAuthResponse() failed to reset body provider"); - } - return false; - } - - } else { - mHeaders.remove("Content-Type"); - mBodyProvider = null; - } - - // Update the cache headers for this URL - mHeaders.putAll(cacheHeaders); - - createAndQueueNewRequest(); - return true; - } - - /** - * Create and queue an HTTP authentication-response (basic) request. - */ - public void setupBasicAuthResponse(boolean isProxy, String username, String password) { - String response = computeBasicAuthResponse(username, password); - if (HttpLog.LOGV) { - HttpLog.v("setupBasicAuthResponse(): response: " + response); - } - mHeaders.put(authorizationHeader(isProxy), "Basic " + response); - setupAuthResponse(); - } - - /** - * Create and queue an HTTP authentication-response (digest) request. - */ - public void setupDigestAuthResponse(boolean isProxy, - String username, - String password, - String realm, - String nonce, - String QOP, - String algorithm, - String opaque) { - - String response = computeDigestAuthResponse( - username, password, realm, nonce, QOP, algorithm, opaque); - if (HttpLog.LOGV) { - HttpLog.v("setupDigestAuthResponse(): response: " + response); - } - mHeaders.put(authorizationHeader(isProxy), "Digest " + response); - setupAuthResponse(); - } - - private void setupAuthResponse() { - try { - if (mBodyProvider != null) mBodyProvider.reset(); - } catch (java.io.IOException ex) { - if (HttpLog.LOGV) { - HttpLog.v("setupAuthResponse() failed to reset body provider"); - } - } - createAndQueueNewRequest(); - } - - /** - * @return HTTP request method (GET, PUT, etc). - */ - public String getMethod() { - return mMethod; - } - - /** - * @return Basic-scheme authentication response: BASE64(username:password). - */ - public static String computeBasicAuthResponse(String username, String password) { - Assert.assertNotNull(username); - Assert.assertNotNull(password); - - // encode username:password to base64 - return new String(Base64.encodeBase64((username + ':' + password).getBytes())); - } - - public void waitUntilComplete() { - mRequest.waitUntilComplete(); - } - - /** - * @return Digest-scheme authentication response. - */ - private String computeDigestAuthResponse(String username, - String password, - String realm, - String nonce, - String QOP, - String algorithm, - String opaque) { - - Assert.assertNotNull(username); - Assert.assertNotNull(password); - Assert.assertNotNull(realm); - - String A1 = username + ":" + realm + ":" + password; - String A2 = mMethod + ":" + mUrl; - - // because we do not preemptively send authorization headers, nc is always 1 - String nc = "000001"; - String cnonce = computeCnonce(); - String digest = computeDigest(A1, A2, nonce, QOP, nc, cnonce); - - String response = ""; - response += "username=" + doubleQuote(username) + ", "; - response += "realm=" + doubleQuote(realm) + ", "; - response += "nonce=" + doubleQuote(nonce) + ", "; - response += "uri=" + doubleQuote(mUrl) + ", "; - response += "response=" + doubleQuote(digest) ; - - if (opaque != null) { - response += ", opaque=" + doubleQuote(opaque); - } - - if (algorithm != null) { - response += ", algorithm=" + algorithm; - } - - if (QOP != null) { - response += ", qop=" + QOP + ", nc=" + nc + ", cnonce=" + doubleQuote(cnonce); - } - - return response; - } - - /** - * @return The right authorization header (dependeing on whether it is a proxy or not). - */ - public static String authorizationHeader(boolean isProxy) { - if (!isProxy) { - return AUTHORIZATION_HEADER; - } else { - return PROXY_AUTHORIZATION_HEADER; - } - } - - /** - * @return Double-quoted MD5 digest. - */ - private String computeDigest( - String A1, String A2, String nonce, String QOP, String nc, String cnonce) { - if (HttpLog.LOGV) { - HttpLog.v("computeDigest(): QOP: " + QOP); - } - - if (QOP == null) { - return KD(H(A1), nonce + ":" + H(A2)); - } else { - if (QOP.equalsIgnoreCase("auth")) { - return KD(H(A1), nonce + ":" + nc + ":" + cnonce + ":" + QOP + ":" + H(A2)); - } - } - - return null; - } - - /** - * @return MD5 hash of concat(secret, ":", data). - */ - private String KD(String secret, String data) { - return H(secret + ":" + data); - } - - /** - * @return MD5 hash of param. - */ - private String H(String param) { - if (param != null) { - Md5MessageDigest md5 = new Md5MessageDigest(); - - byte[] d = md5.digest(param.getBytes()); - if (d != null) { - return bufferToHex(d); - } - } - - return null; - } - - /** - * @return HEX buffer representation. - */ - private String bufferToHex(byte[] buffer) { - final char hexChars[] = - { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; - - if (buffer != null) { - int length = buffer.length; - if (length > 0) { - StringBuilder hex = new StringBuilder(2 * length); - - for (int i = 0; i < length; ++i) { - byte l = (byte) (buffer[i] & 0x0F); - byte h = (byte)((buffer[i] & 0xF0) >> 4); - - hex.append(hexChars[h]); - hex.append(hexChars[l]); - } - - return hex.toString(); - } else { - return ""; - } - } - - return null; - } - - /** - * Computes a random cnonce value based on the current time. - */ - private String computeCnonce() { - Random rand = new Random(); - int nextInt = rand.nextInt(); - nextInt = (nextInt == Integer.MIN_VALUE) ? - Integer.MAX_VALUE : Math.abs(nextInt); - return Integer.toString(nextInt, 16); - } - - /** - * "Double-quotes" the argument. - */ - private String doubleQuote(String param) { - if (param != null) { - return "\"" + param + "\""; - } - - return null; - } - - /** - * Creates and queues new request. - */ - private void createAndQueueNewRequest() { - mRequest = mRequestQueue.queueRequest( - mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler, - mBodyProvider, - mBodyLength, mRequest.mHighPriority).mRequest; - } -} diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java deleted file mode 100644 index 66d5722..0000000 --- a/core/java/android/net/http/RequestQueue.java +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * High level HTTP Interface - * Queues requests as necessary - */ - -package android.net.http; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkConnectivityListener; -import android.net.NetworkInfo; -import android.net.Proxy; -import android.net.WebAddress; -import android.os.Handler; -import android.os.Message; -import android.os.SystemProperties; -import android.text.TextUtils; -import android.util.Log; - -import java.io.InputStream; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.ListIterator; -import java.util.Map; - -import org.apache.http.HttpHost; - -/** - * {@hide} - */ -public class RequestQueue implements RequestFeeder { - - private Context mContext; - - /** - * Requests, indexed by HttpHost (scheme, host, port) - */ - private LinkedHashMap<HttpHost, LinkedList<Request>> mPending; - - /* Support for notifying a client when queue is empty */ - private boolean mClientWaiting = false; - - /** true if connected */ - boolean mNetworkConnected = true; - - private HttpHost mProxyHost = null; - private BroadcastReceiver mProxyChangeReceiver; - - private ActivePool mActivePool; - - /* default simultaneous connection count */ - private static final int CONNECTION_COUNT = 4; - - /** - * This intent broadcast when http is paused or unpaused due to - * net availability toggling - */ - public final static String HTTP_NETWORK_STATE_CHANGED_INTENT = - "android.net.http.NETWORK_STATE"; - public final static String HTTP_NETWORK_STATE_UP = "up"; - - /** - * Listen to platform network state. On a change, - * (1) kick stack on or off as appropriate - * (2) send an intent to my host app telling - * it what I've done - */ - private NetworkStateTracker mNetworkStateTracker; - class NetworkStateTracker { - - final static int EVENT_DATA_STATE_CHANGED = 100; - - Context mContext; - NetworkConnectivityListener mConnectivityListener; - NetworkInfo.State mLastNetworkState = NetworkInfo.State.CONNECTED; - int mCurrentNetworkType; - - NetworkStateTracker(Context context) { - mContext = context; - } - - /** - * register for updates - */ - protected void enable() { - if (mConnectivityListener == null) { - /* - * Initializing the network type is really unnecessary, - * since as soon as we register with the NCL, we'll - * get a CONNECTED event for the active network, and - * we'll configure the HTTP proxy accordingly. However, - * as a fallback in case that doesn't happen for some - * reason, initializing to type WIFI would mean that - * we'd start out without a proxy. This seems better - * than thinking we have a proxy (which is probably - * private to the carrier network and therefore - * unreachable outside of that network) when we really - * shouldn't. - */ - mCurrentNetworkType = ConnectivityManager.TYPE_WIFI; - mConnectivityListener = new NetworkConnectivityListener(); - mConnectivityListener.registerHandler(mHandler, EVENT_DATA_STATE_CHANGED); - mConnectivityListener.startListening(mContext); - } - } - - protected void disable() { - if (mConnectivityListener != null) { - mConnectivityListener.unregisterHandler(mHandler); - mConnectivityListener.stopListening(); - mConnectivityListener = null; - } - } - - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_DATA_STATE_CHANGED: - networkStateChanged(); - break; - } - } - }; - - int getCurrentNetworkType() { - return mCurrentNetworkType; - } - - void networkStateChanged() { - if (mConnectivityListener == null) - return; - - - NetworkConnectivityListener.State connectivityState = mConnectivityListener.getState(); - NetworkInfo info = mConnectivityListener.getNetworkInfo(); - if (info == null) { - /** - * We've been seeing occasional NPEs here. I believe recent changes - * have made this impossible, but in the interest of being totally - * paranoid, check and log this here. - */ - HttpLog.v("NetworkStateTracker: connectivity broadcast" - + " has null network info - ignoring"); - return; - } - NetworkInfo.State state = info.getState(); - - if (HttpLog.LOGV) { - HttpLog.v("NetworkStateTracker " + info.getTypeName() + - " state= " + state + " last= " + mLastNetworkState + - " connectivityState= " + connectivityState.toString()); - } - - boolean newConnection = - state != mLastNetworkState && state == NetworkInfo.State.CONNECTED; - - if (state == NetworkInfo.State.CONNECTED) { - mCurrentNetworkType = info.getType(); - setProxyConfig(); - } - - mLastNetworkState = state; - if (connectivityState == NetworkConnectivityListener.State.NOT_CONNECTED) { - setNetworkState(false); - broadcastState(false); - } else if (newConnection) { - setNetworkState(true); - broadcastState(true); - } - - } - - void broadcastState(boolean connected) { - Intent intent = new Intent(HTTP_NETWORK_STATE_CHANGED_INTENT); - intent.putExtra(HTTP_NETWORK_STATE_UP, connected); - mContext.sendBroadcast(intent); - } - } - - /** - * This class maintains active connection threads - */ - class ActivePool implements ConnectionManager { - /** Threads used to process requests */ - ConnectionThread[] mThreads; - - IdleCache mIdleCache; - - private int mTotalRequest; - private int mTotalConnection; - private int mConnectionCount; - - ActivePool(int connectionCount) { - mIdleCache = new IdleCache(); - mConnectionCount = connectionCount; - mThreads = new ConnectionThread[mConnectionCount]; - - for (int i = 0; i < mConnectionCount; i++) { - mThreads[i] = new ConnectionThread( - mContext, i, this, RequestQueue.this); - } - } - - void startup() { - for (int i = 0; i < mConnectionCount; i++) { - mThreads[i].start(); - } - } - - void shutdown() { - for (int i = 0; i < mConnectionCount; i++) { - mThreads[i].requestStop(); - } - } - - public boolean isNetworkConnected() { - return mNetworkConnected; - } - - void startConnectionThread() { - synchronized (RequestQueue.this) { - RequestQueue.this.notify(); - } - } - - public void startTiming() { - for (int i = 0; i < mConnectionCount; i++) { - mThreads[i].mStartThreadTime = mThreads[i].mCurrentThreadTime; - } - mTotalRequest = 0; - mTotalConnection = 0; - } - - public void stopTiming() { - int totalTime = 0; - for (int i = 0; i < mConnectionCount; i++) { - ConnectionThread rt = mThreads[i]; - totalTime += (rt.mCurrentThreadTime - rt.mStartThreadTime); - rt.mStartThreadTime = -1; - } - Log.d("Http", "Http thread used " + totalTime + " ms " + " for " - + mTotalRequest + " requests and " + mTotalConnection - + " connections"); - } - - void logState() { - StringBuilder dump = new StringBuilder(); - for (int i = 0; i < mConnectionCount; i++) { - dump.append(mThreads[i] + "\n"); - } - HttpLog.v(dump.toString()); - } - - - public HttpHost getProxyHost() { - return mProxyHost; - } - - /** - * Turns off persistence on all live connections - */ - void disablePersistence() { - for (int i = 0; i < mConnectionCount; i++) { - Connection connection = mThreads[i].mConnection; - if (connection != null) connection.setCanPersist(false); - } - mIdleCache.clear(); - } - - /* Linear lookup -- okay for small thread counts. Might use - private HashMap<HttpHost, LinkedList<ConnectionThread>> mActiveMap; - if this turns out to be a hotspot */ - ConnectionThread getThread(HttpHost host) { - synchronized(RequestQueue.this) { - for (int i = 0; i < mThreads.length; i++) { - ConnectionThread ct = mThreads[i]; - Connection connection = ct.mConnection; - if (connection != null && connection.mHost.equals(host)) { - return ct; - } - } - } - return null; - } - - public Connection getConnection(Context context, HttpHost host) { - Connection con = mIdleCache.getConnection(host); - if (con == null) { - mTotalConnection++; - con = Connection.getConnection( - mContext, host, this, RequestQueue.this); - } - return con; - } - public boolean recycleConnection(HttpHost host, Connection connection) { - return mIdleCache.cacheConnection(host, connection); - } - - } - - /** - * A RequestQueue class instance maintains a set of queued - * requests. It orders them, makes the requests against HTTP - * servers, and makes callbacks to supplied eventHandlers as data - * is read. It supports request prioritization, connection reuse - * and pipelining. - * - * @param context application context - */ - public RequestQueue(Context context) { - this(context, CONNECTION_COUNT); - } - - /** - * A RequestQueue class instance maintains a set of queued - * requests. It orders them, makes the requests against HTTP - * servers, and makes callbacks to supplied eventHandlers as data - * is read. It supports request prioritization, connection reuse - * and pipelining. - * - * @param context application context - * @param connectionCount The number of simultaneous connections - */ - public RequestQueue(Context context, int connectionCount) { - mContext = context; - - mPending = new LinkedHashMap<HttpHost, LinkedList<Request>>(32); - - mActivePool = new ActivePool(connectionCount); - mActivePool.startup(); - } - - /** - * Enables data state and proxy tracking - */ - public synchronized void enablePlatformNotifications() { - if (HttpLog.LOGV) HttpLog.v("RequestQueue.enablePlatformNotifications() network"); - - if (mProxyChangeReceiver == null) { - mProxyChangeReceiver = - new BroadcastReceiver() { - @Override - public void onReceive(Context ctx, Intent intent) { - setProxyConfig(); - } - }; - mContext.registerReceiver(mProxyChangeReceiver, - new IntentFilter(Proxy.PROXY_CHANGE_ACTION)); - } - - /* Network state notification is broken on the simulator - don't register for notifications on SIM */ - String device = SystemProperties.get("ro.product.device"); - boolean simulation = TextUtils.isEmpty(device); - - if (!simulation) { - if (mNetworkStateTracker == null) { - mNetworkStateTracker = new NetworkStateTracker(mContext); - } - mNetworkStateTracker.enable(); - } - } - - /** - * If platform notifications have been enabled, call this method - * to disable before destroying RequestQueue - */ - public synchronized void disablePlatformNotifications() { - if (HttpLog.LOGV) HttpLog.v("RequestQueue.disablePlatformNotifications() network"); - - if (mNetworkStateTracker != null) { - mNetworkStateTracker.disable(); - } - - if (mProxyChangeReceiver != null) { - mContext.unregisterReceiver(mProxyChangeReceiver); - mProxyChangeReceiver = null; - } - } - - /** - * Because our IntentReceiver can run within a different thread, - * synchronize setting the proxy - */ - private synchronized void setProxyConfig() { - if (mNetworkStateTracker.getCurrentNetworkType() == ConnectivityManager.TYPE_WIFI) { - mProxyHost = null; - } else { - String host = Proxy.getHost(mContext); - if (HttpLog.LOGV) HttpLog.v("RequestQueue.setProxyConfig " + host); - if (host == null) { - mProxyHost = null; - } else { - mActivePool.disablePersistence(); - mProxyHost = new HttpHost(host, Proxy.getPort(mContext), "http"); - } - } - } - - /** - * used by webkit - * @return proxy host if set, null otherwise - */ - public HttpHost getProxyHost() { - return mProxyHost; - } - - /** - * Queues an HTTP request - * @param url The url to load. - * @param method "GET" or "POST." - * @param headers A hashmap of http headers. - * @param eventHandler The event handler for handling returned - * data. Callbacks will be made on the supplied instance. - * @param bodyProvider InputStream providing HTTP body, null if none - * @param bodyLength length of body, must be 0 if bodyProvider is null - * @param highPriority If true, queues before low priority - * requests if possible - */ - public RequestHandle queueRequest( - String url, String method, - Map<String, String> headers, EventHandler eventHandler, - InputStream bodyProvider, int bodyLength, boolean highPriority) { - WebAddress uri = new WebAddress(url); - return queueRequest(url, uri, method, headers, eventHandler, - bodyProvider, bodyLength, highPriority); - } - - /** - * Queues an HTTP request - * @param url The url to load. - * @param uri The uri of the url to load. - * @param method "GET" or "POST." - * @param headers A hashmap of http headers. - * @param eventHandler The event handler for handling returned - * data. Callbacks will be made on the supplied instance. - * @param bodyProvider InputStream providing HTTP body, null if none - * @param bodyLength length of body, must be 0 if bodyProvider is null - * @param highPriority If true, queues before low priority - * requests if possible - */ - public RequestHandle queueRequest( - String url, WebAddress uri, String method, Map<String, String> headers, - EventHandler eventHandler, - InputStream bodyProvider, int bodyLength, - boolean highPriority) { - - if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri); - - // Ensure there is an eventHandler set - if (eventHandler == null) { - eventHandler = new LoggingEventHandler(); - } - - /* Create and queue request */ - Request req; - HttpHost httpHost = new HttpHost(uri.mHost, uri.mPort, uri.mScheme); - - // set up request - req = new Request(method, httpHost, mProxyHost, uri.mPath, bodyProvider, - bodyLength, eventHandler, headers, highPriority); - - queueRequest(req, highPriority); - - mActivePool.mTotalRequest++; - - // dump(); - mActivePool.startConnectionThread(); - - return new RequestHandle( - this, url, uri, method, headers, bodyProvider, bodyLength, - req); - } - - /** - * Called by the NetworkStateTracker -- updates when network connectivity - * is lost/restored. - * - * If isNetworkConnected is true, start processing requests - */ - public void setNetworkState(boolean isNetworkConnected) { - if (HttpLog.LOGV) HttpLog.v("RequestQueue.setNetworkState() " + isNetworkConnected); - mNetworkConnected = isNetworkConnected; - if (isNetworkConnected) - mActivePool.startConnectionThread(); - } - - /** - * @return true iff there are any non-active requests pending - */ - synchronized boolean requestsPending() { - return !mPending.isEmpty(); - } - - - /** - * debug tool: prints request queue to log - */ - synchronized void dump() { - HttpLog.v("dump()"); - StringBuilder dump = new StringBuilder(); - int count = 0; - Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter; - - // mActivePool.log(dump); - - if (!mPending.isEmpty()) { - iter = mPending.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next(); - String hostName = entry.getKey().getHostName(); - StringBuilder line = new StringBuilder("p" + count++ + " " + hostName + " "); - - LinkedList<Request> reqList = entry.getValue(); - ListIterator reqIter = reqList.listIterator(0); - while (iter.hasNext()) { - Request request = (Request)iter.next(); - line.append(request + " "); - } - dump.append(line); - dump.append("\n"); - } - } - HttpLog.v(dump.toString()); - } - - /* - * RequestFeeder implementation - */ - public synchronized Request getRequest() { - Request ret = null; - - if (mNetworkConnected && !mPending.isEmpty()) { - ret = removeFirst(mPending); - } - if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest() => " + ret); - return ret; - } - - /** - * @return a request for given host if possible - */ - public synchronized Request getRequest(HttpHost host) { - Request ret = null; - - if (mNetworkConnected && mPending.containsKey(host)) { - LinkedList<Request> reqList = mPending.get(host); - ret = reqList.removeFirst(); - if (reqList.isEmpty()) { - mPending.remove(host); - } - } - if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest(" + host + ") => " + ret); - return ret; - } - - /** - * @return true if a request for this host is available - */ - public synchronized boolean haveRequest(HttpHost host) { - return mPending.containsKey(host); - } - - /** - * Put request back on head of queue - */ - public void requeueRequest(Request request) { - queueRequest(request, true); - } - - /** - * This must be called to cleanly shutdown RequestQueue - */ - public void shutdown() { - mActivePool.shutdown(); - } - - protected synchronized void queueRequest(Request request, boolean head) { - HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost; - LinkedList<Request> reqList; - if (mPending.containsKey(host)) { - reqList = mPending.get(host); - } else { - reqList = new LinkedList<Request>(); - mPending.put(host, reqList); - } - if (head) { - reqList.addFirst(request); - } else { - reqList.add(request); - } - } - - - public void startTiming() { - mActivePool.startTiming(); - } - - public void stopTiming() { - mActivePool.stopTiming(); - } - - /* helper */ - private Request removeFirst(LinkedHashMap<HttpHost, LinkedList<Request>> requestQueue) { - Request ret = null; - Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter = requestQueue.entrySet().iterator(); - if (iter.hasNext()) { - Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next(); - LinkedList<Request> reqList = entry.getValue(); - ret = reqList.removeFirst(); - if (reqList.isEmpty()) { - requestQueue.remove(entry.getKey()); - } - } - return ret; - } - - /** - * This interface is exposed to each connection - */ - interface ConnectionManager { - boolean isNetworkConnected(); - HttpHost getProxyHost(); - Connection getConnection(Context context, HttpHost host); - boolean recycleConnection(HttpHost host, Connection connection); - } -} diff --git a/core/java/android/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java deleted file mode 100644 index 46b2bee..0000000 --- a/core/java/android/net/http/SslCertificate.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.os.Bundle; - -import java.text.DateFormat; -import java.util.Vector; - -import java.security.cert.X509Certificate; - -import org.bouncycastle.asn1.DERObjectIdentifier; -import org.bouncycastle.asn1.x509.X509Name; - -/** - * SSL certificate info (certificate details) class - */ -public class SslCertificate { - - /** - * Name of the entity this certificate is issued to - */ - private DName mIssuedTo; - - /** - * Name of the entity this certificate is issued by - */ - private DName mIssuedBy; - - /** - * Not-before date from the validity period - */ - private String mValidNotBefore; - - /** - * Not-after date from the validity period - */ - private String mValidNotAfter; - - /** - * Bundle key names - */ - private static final String ISSUED_TO = "issued-to"; - private static final String ISSUED_BY = "issued-by"; - private static final String VALID_NOT_BEFORE = "valid-not-before"; - private static final String VALID_NOT_AFTER = "valid-not-after"; - - /** - * Saves the certificate state to a bundle - * @param certificate The SSL certificate to store - * @return A bundle with the certificate stored in it or null if fails - */ - public static Bundle saveState(SslCertificate certificate) { - Bundle bundle = null; - - if (certificate != null) { - bundle = new Bundle(); - - bundle.putString(ISSUED_TO, certificate.getIssuedTo().getDName()); - bundle.putString(ISSUED_BY, certificate.getIssuedBy().getDName()); - - bundle.putString(VALID_NOT_BEFORE, certificate.getValidNotBefore()); - bundle.putString(VALID_NOT_AFTER, certificate.getValidNotAfter()); - } - - return bundle; - } - - /** - * Restores the certificate stored in the bundle - * @param bundle The bundle with the certificate state stored in it - * @return The SSL certificate stored in the bundle or null if fails - */ - public static SslCertificate restoreState(Bundle bundle) { - if (bundle != null) { - return new SslCertificate( - bundle.getString(ISSUED_TO), - bundle.getString(ISSUED_BY), - bundle.getString(VALID_NOT_BEFORE), - bundle.getString(VALID_NOT_AFTER)); - } - - return null; - } - - /** - * Creates a new SSL certificate object - * @param issuedTo The entity this certificate is issued to - * @param issuedBy The entity that issued this certificate - * @param validNotBefore The not-before date from the certificate validity period - * @param validNotAfter The not-after date from the certificate validity period - */ - public SslCertificate( - String issuedTo, String issuedBy, String validNotBefore, String validNotAfter) { - mIssuedTo = new DName(issuedTo); - mIssuedBy = new DName(issuedBy); - - mValidNotBefore = validNotBefore; - mValidNotAfter = validNotAfter; - } - - /** - * Creates a new SSL certificate object from an X509 certificate - * @param certificate X509 certificate - */ - public SslCertificate(X509Certificate certificate) { - this(certificate.getSubjectDN().getName(), - certificate.getIssuerDN().getName(), - DateFormat.getInstance().format(certificate.getNotBefore()), - DateFormat.getInstance().format(certificate.getNotAfter())); - } - - /** - * @return Not-before date from the certificate validity period or - * "" if none has been set - */ - public String getValidNotBefore() { - return mValidNotBefore != null ? mValidNotBefore : ""; - } - - /** - * @return Not-after date from the certificate validity period or - * "" if none has been set - */ - public String getValidNotAfter() { - return mValidNotAfter != null ? mValidNotAfter : ""; - } - - /** - * @return Issued-to distinguished name or null if none has been set - */ - public DName getIssuedTo() { - return mIssuedTo; - } - - /** - * @return Issued-by distinguished name or null if none has been set - */ - public DName getIssuedBy() { - return mIssuedBy; - } - - /** - * @return A string representation of this certificate for debugging - */ - public String toString() { - return - "Issued to: " + mIssuedTo.getDName() + ";\n" + - "Issued by: " + mIssuedBy.getDName() + ";\n"; - } - - /** - * A distinguished name helper class: a 3-tuple of: - * - common name (CN), - * - organization (O), - * - organizational unit (OU) - */ - public class DName { - /** - * Distinguished name (normally includes CN, O, and OU names) - */ - private String mDName; - - /** - * Common-name (CN) component of the name - */ - private String mCName; - - /** - * Organization (O) component of the name - */ - private String mOName; - - /** - * Organizational Unit (OU) component of the name - */ - private String mUName; - - /** - * Creates a new distinguished name - * @param dName The distinguished name - */ - public DName(String dName) { - if (dName != null) { - X509Name x509Name = new X509Name(mDName = dName); - - Vector val = x509Name.getValues(); - Vector oid = x509Name.getOIDs(); - - for (int i = 0; i < oid.size(); i++) { - if (oid.elementAt(i).equals(X509Name.CN)) { - mCName = (String) val.elementAt(i); - continue; - } - - if (oid.elementAt(i).equals(X509Name.O)) { - mOName = (String) val.elementAt(i); - continue; - } - - if (oid.elementAt(i).equals(X509Name.OU)) { - mUName = (String) val.elementAt(i); - continue; - } - } - } - } - - /** - * @return The distinguished name (normally includes CN, O, and OU names) - */ - public String getDName() { - return mDName != null ? mDName : ""; - } - - /** - * @return The Common-name (CN) component of this name - */ - public String getCName() { - return mCName != null ? mCName : ""; - } - - /** - * @return The Organization (O) component of this name - */ - public String getOName() { - return mOName != null ? mOName : ""; - } - - /** - * @return The Organizational Unit (OU) component of this name - */ - public String getUName() { - return mUName != null ? mUName : ""; - } - } -} diff --git a/core/java/android/net/http/SslError.java b/core/java/android/net/http/SslError.java deleted file mode 100644 index 2788cb1..0000000 --- a/core/java/android/net/http/SslError.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import java.security.cert.X509Certificate; - -/** - * One or more individual SSL errors and the associated SSL certificate - * - * {@hide} - */ -public class SslError { - - /** - * Individual SSL errors (in the order from the least to the most severe): - */ - - /** - * The certificate is not yet valid - */ - public static final int SSL_NOTYETVALID = 0; - /** - * The certificate has expired - */ - public static final int SSL_EXPIRED = 1; - /** - * Hostname mismatch - */ - public static final int SSL_IDMISMATCH = 2; - /** - * The certificate authority is not trusted - */ - public static final int SSL_UNTRUSTED = 3; - - - /** - * The number of different SSL errors (update if you add a new SSL error!!!) - */ - public static final int SSL_MAX_ERROR = 4; - - /** - * The SSL error set bitfield (each individual error is an bit index; - * multiple individual errors can be OR-ed) - */ - int mErrors; - - /** - * The SSL certificate associated with the error set - */ - SslCertificate mCertificate; - - /** - * Creates a new SSL error set object - * @param error The SSL error - * @param certificate The associated SSL certificate - */ - public SslError(int error, SslCertificate certificate) { - addError(error); - mCertificate = certificate; - } - - /** - * Creates a new SSL error set object - * @param error The SSL error - * @param certificate The associated SSL certificate - */ - public SslError(int error, X509Certificate certificate) { - addError(error); - mCertificate = new SslCertificate(certificate); - } - - /** - * @return The SSL certificate associated with the error set - */ - public SslCertificate getCertificate() { - return mCertificate; - } - - /** - * Adds the SSL error to the error set - * @param error The SSL error to add - * @return True iff the error being added is a known SSL error - */ - public boolean addError(int error) { - boolean rval = (0 <= error && error < SslError.SSL_MAX_ERROR); - if (rval) { - mErrors |= (0x1 << error); - } - - return rval; - } - - /** - * @param error The SSL error to check - * @return True iff the set includes the error - */ - public boolean hasError(int error) { - boolean rval = (0 <= error && error < SslError.SSL_MAX_ERROR); - if (rval) { - rval = ((mErrors & (0x1 << error)) != 0); - } - - return rval; - } - - /** - * @return The primary, most severe, SSL error in the set - */ - public int getPrimaryError() { - if (mErrors != 0) { - // go from the most to the least severe errors - for (int error = SslError.SSL_MAX_ERROR - 1; error >= 0; --error) { - if ((mErrors & (0x1 << error)) != 0) { - return error; - } - } - } - - return 0; - } - - /** - * @return A String representation of this SSL error object - * (used mostly for debugging). - */ - public String toString() { - return "primary error: " + getPrimaryError() + - " certificate: " + getCertificate(); - } -} diff --git a/core/java/android/net/http/Timer.java b/core/java/android/net/http/Timer.java deleted file mode 100644 index cc15a30..0000000 --- a/core/java/android/net/http/Timer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.http; - -import android.os.SystemClock; - -/** - * {@hide} - * Debugging tool - */ -class Timer { - - private long mStart; - private long mLast; - - public Timer() { - mStart = mLast = SystemClock.uptimeMillis(); - } - - public void mark(String message) { - long now = SystemClock.uptimeMillis(); - if (HttpLog.LOGV) { - HttpLog.v(message + " " + (now - mLast) + " total " + (now - mStart)); - } - mLast = now; - } -} diff --git a/core/java/android/net/http/package.html b/core/java/android/net/http/package.html deleted file mode 100755 index a81cbce..0000000 --- a/core/java/android/net/http/package.html +++ /dev/null @@ -1,2 +0,0 @@ -<body> -</body> diff --git a/core/java/android/net/package.html b/core/java/android/net/package.html deleted file mode 100755 index 47c57e6..0000000 --- a/core/java/android/net/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<body> - -Classes that help with network access, beyond the normal java.net.* APIs. - -</body> |