--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/gcfprotocols/http/javasrc.s60/com/nokia/mj/impl/http/HttpConnectionNative.java Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1506 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+package com.nokia.mj.impl.http;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import javax.microedition.io.HttpConnection;
+import com.nokia.mj.impl.gcf.utils.URI;
+import com.nokia.mj.impl.rt.support.Jvm;
+import com.nokia.mj.impl.utils.Logger;
+import com.nokia.mj.impl.gcf.utils.DateUtil;
+import com.nokia.mj.impl.gcf.utils.NativeError;
+import com.nokia.mj.impl.http.BlockingOperation;
+import com.nokia.mj.impl.rt.support.Finalizer;
+import com.nokia.mj.impl.connectionmanager.ConnectionManager;
+import com.nokia.mj.impl.connectionmanager.AccessPoint;
+import com.nokia.mj.impl.rt.support.ApplicationUtils;
+import com.nokia.mj.impl.rt.support.ApplicationInfo;
+import com.nokia.mj.impl.rt.support.ShutdownListener;
+
+/**
+ * An HttpConection class implementing an HTTP 1.1 client connection using the
+ * native symbian http client ap
+ *
+ */
+public class HttpConnectionNative implements HttpConnection,
+ NativeHttpByteSource
+{
+ protected int iMode;
+ protected int iState;
+ protected boolean iClosed;
+ protected URI iUri;
+ protected String iRef;
+ protected String iRequestMethod;
+ protected Hashtable iRequestProperties;
+ protected int iResponseCode;
+ protected String iResponseMessage;
+ protected Hashtable iReplyHeaders;
+ protected Vector iReplyHeaderKeys;
+ protected long iLength;
+ protected DataInputStream iInputStream;
+ protected boolean iInputStreamOpened = false;
+ protected NativeHttpInputStream iNativeHttpInputStream;
+ protected ByteArrayOutputStream iPostedDataStream;
+ protected DataOutputStream iOutputStream;
+ protected boolean iOutputStreamOpened = false;
+ protected char[] iLineBuffer;
+ protected int iLineBufferLength;
+ protected int iLineLength;
+
+ // States
+ protected final static int INVALID_STATE = 0;
+ protected final static int SETUP = 1;
+ protected final static int CONNECTED = 2;
+ protected final static int REQUEST_HEADERS_SENT = 3;
+ protected final static int REQUEST_SENT = 4;
+ protected final static int REPLY_RECEIVED = 5;
+
+ // Character constants
+ protected final static char HASH = '#';
+ protected final static int QUESTION_MARK = 63;
+ protected final static int CR = 13;
+ protected final static int LF = 10;
+ protected final static int SP = 32;
+ protected final static int EOF = -1;
+
+ // Misc. Constants
+ protected final static byte[] CRLF = { CR, LF };
+ protected final static int DEFAULT_LINE_BUFFER_SIZE = 128;
+ protected final static String VERSION_1_1 = "1.1";
+ protected final static String VERSION_1_0 = "1.0";
+ protected final static String NATIVESEPERATOR = ";;";
+ protected final static String DEFAULT_PATH = "/"; // NOI8N
+ protected final static int DEFAULT_PORT = 80;
+ protected final static String PROTOCOL_SUFFIX = "://";
+
+ // 'Well-known' Header names
+ protected final static String CONNECTION = "Connection"; // NOI8N
+ protected final static String CONTENT_ENCODING = "Content-Encoding"; // NOI8N
+ protected final static String CONTENT_LENGTH = "Content-Length"; // NOI8N
+ protected final static String CONTENT_TYPE = "Content-Type"; // NOI8N
+ protected final static String DATE = "Date"; // NOI8N
+ protected final static String HOST = "Host"; // NOI8N
+ protected final static String LAST_MODIFIED = "Last-Modified"; // NOI8N
+ protected final static String EXPIRES = "Expires"; // NOI8N
+ protected final static String TRANSFER_ENCODING = "Transfer-Encoding"; // NOI8N
+ protected final static String USER_AGENT = "User-Agent";
+
+ // 'Well-known' Header values
+ protected final static String UNTRUSTED_1_0 = "UNTRUSTED/1.0";
+
+ // Connection value
+ protected final static String CLOSE = "close"; // NOI8N
+
+ // Http-native handle
+ private static int iNativeHttpSessionHandle = 0;
+
+ protected int iNativeTransactionHande = 0;
+ final BlockingOperation iTransactionBlock;
+
+ // Custom lock for synchronizing all read operations.
+ protected final BlockingOperation iNativeDataReadyForRead;
+
+ private Finalizer iFinalizer;
+ protected ConnectionManager iCmInstance = null;
+ protected AccessPoint iApn = null;
+ private static boolean iIsSessionDeleted = false;
+ private boolean iTrustedSuite = true;
+ private int iRespTimeOut = -1;
+ private int iRetries = 0;
+
+ static
+ {
+ try
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "loading http from HttpConnectionNative.java");
+ Jvm.loadSystemLibrary("javahttp");
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "javahttp loaded");
+ }
+ catch (Exception e)
+ {
+ Logger.ELOG(Logger.ESOCKET, e.toString());
+ }
+ }
+
+ public HttpConnectionNative(int aNativeHttpSessionHandle, String aName,
+ int aMode, boolean aTimeouts, ConnectionManager cm,
+ AccessPoint apnInfo, int aResponseTimeout) throws IOException
+ {
+ Logger.PLOG(Logger.ESOCKET, "New HTTP connection to URL: " + aName);
+ Logger.ILOG(Logger.ESOCKET, "+++++ HttpConnectionNative new, this ="
+ + this);
+
+ int index;
+ iCmInstance = cm;
+ iApn = apnInfo;
+ index = aName.indexOf(HASH);
+ iRespTimeOut = aResponseTimeout; // setting of timeout value for http response.
+ // specific scenario identified in case of java installer.
+
+ // Handle to shared native RHttpSession
+ if (iNativeHttpSessionHandle == 0)
+ {
+ // only one session per application
+ creatHttpSession();
+ }
+
+ if (index != -1)
+ {
+ iRef = aName.substring(index + 1);
+ aName = aName.substring(0, index);
+ }
+
+ iUri = new URI(aName);
+ final String host = iUri.getHost();
+ if (host == null || host.equals(""))
+ {
+ throw new IllegalArgumentException("Invalid url: " + aName);
+ }
+
+ iMode = aMode;
+ iState = SETUP;
+ iRequestMethod = GET;
+ iRequestProperties = new Hashtable();
+ iReplyHeaders = new Hashtable();
+ iReplyHeaderKeys = new Vector();
+ iLength = -1;
+
+ // Blocking operations to allow async native transactions
+ iTransactionBlock = new BlockingOperation();
+ iNativeDataReadyForRead = new BlockingOperation();
+ iNativeDataReadyForRead.setResult(BlockingOperation.BLOCKED);
+ iFinalizer = registerForFinalization();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- HttpConnectionNative new ");
+
+ ApplicationInfo appInfo = ApplicationInfo.getInstance();
+ String runtime = appInfo.getRuntimeType();
+ boolean midpRuntime = true;
+
+ if (runtime == ApplicationInfo.RUNTIME_INSTALLER)
+ {
+ midpRuntime = false;
+ }
+ else
+ {
+ // add the untrusted header for untrusted midlet suite
+ if ((ApplicationInfo.getInstance().getProtectionDomain()
+ .equals(ApplicationInfo.UNIDENTIFIED_THIRD_PARTY_DOMAIN)) == true)
+ {
+ iTrustedSuite = false;
+ iRequestProperties.put(USER_AGENT, UNTRUSTED_1_0);
+ }
+ }
+ // get the default User-Agent headers and add to hashtable
+ final String agent = _getUserAgentHeaderValue(midpRuntime);
+ if (agent != null)
+ {
+ if (iTrustedSuite == false)
+ {
+ String result = agent + ' ' + UNTRUSTED_1_0;
+ iRequestProperties.put(USER_AGENT, result);
+ }
+ else
+ {
+ iRequestProperties.put(USER_AGENT, agent);
+ }
+ }
+ }
+
+ Finalizer registerForFinalization()
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "++HttpConnectionNative::registerForFinalization ");
+ return new Finalizer()
+ {
+ public void finalizeImpl()
+ {
+ doFinalize();
+ }
+ };
+ }
+
+
+ public void doFinalize()
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "++HttpConnectionNative::doFinalize ");
+ try
+ {
+ close();
+ }
+ catch(Exception e)
+ {
+
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "--HttpConnectionNative::doFinalize ");
+ }
+
+ public void creatHttpSession() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "++HttpConnectionNative::creatHttpSession()");
+ int[] retval = new int[2];
+ int handle;
+ int err;
+ if (iApn != null)
+ {
+ handle = _createHttpSession(0, iApn.getType(), iApn.getNapId(),
+ retval);
+ }
+ else
+ {
+ handle = _createHttpSession(0, -1, -1, retval);
+ }
+ iNativeHttpSessionHandle = NativeError.check(handle);
+ if (retval[0] < 0)
+ {
+ throw new IOException(
+ "Unable to open http connection.Creation of Native peer failed.");
+ }
+ if (retval[1] < 0)
+ {
+ // reset connection manager
+ iCmInstance.reset();
+ }
+
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "--HttpConnectionNative::creatHttpSession()");
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized void close() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "++++++++++ close()");
+ if (iClosed)
+ {
+ return;
+ }
+ iClosed = true;
+ if ((iInputStream == null) && (iOutputStream == null)
+ && (iState != SETUP))
+ {
+ if (iNativeHttpInputStream != null)
+ {
+ iNativeHttpInputStream.close();
+ iNativeHttpInputStream = null;
+ }
+ closeConnection();
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "------- close()");
+ return;
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized DataInputStream openDataInputStream()
+ throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openDataInputStream()");
+ // prevents multiple read
+ synchronized (iNativeDataReadyForRead.getLock())
+ {
+ ensureOpen("openDataInputStream");
+ if (iInputStreamOpened)
+ {
+ throwIOException("Input stream is already opened");
+ }
+ ensureResponse();
+ iInputStream = makeDataInputStream();
+ iInputStreamOpened = true;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-
+ // openDataInputStream()" );
+ return iInputStream;
+ }
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized InputStream openInputStream() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openInputStream()" );
+ final InputStream result = openDataInputStream();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- openInputStream()" );
+ return result;
+ }
+
+
+ /**
+ * Please refer to Jsr 118
+ */
+
+ public synchronized DataOutputStream openDataOutputStream()
+ throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openDataOutputStream()"
+ // );
+ ensureOpen("openDataOutputStream");
+ if (iOutputStreamOpened)
+ {
+ throwIOException("Output stream is already opened");
+ }
+ makeDataOutputStream();
+ iOutputStreamOpened = true;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- openDataOutputStream()"
+ // );
+ return iOutputStream;
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized OutputStream openOutputStream() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openOutputStream()" );
+ final OutputStream result = openDataOutputStream();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- openOutputStream()" );
+ return result;
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized String getEncoding()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getEncoding()" );
+ String result = null;
+ try
+ {
+ result = getHeaderField(CONTENT_ENCODING);
+ }
+ catch (IOException ex)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getEncoding() returns
+ // null" );
+ return null;
+ }
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getEncoding()" );
+ return result;
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized long getLength()
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getLength()");
+ try
+ {
+ ensureOpen("getLength");
+ ensureResponse();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getLength() : " +
+ // iLength);
+ return iLength;
+ }
+ catch (IOException ex)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getLength() set -1
+ // IOException: "+ ex.toString() );
+ return -1;
+ }
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized String getType()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getType()" );
+ String result = null;
+ try
+ {
+ result = getHeaderField(CONTENT_TYPE);
+ }
+ catch (IOException ex)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getType() returns
+ // null" );
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getType() NULL");
+ return null;
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getType()" + result);
+ return result;
+ }
+
+ // HttpConnection interface implementation
+
+ public synchronized long getDate() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getDate()" );
+ final long result = getHeaderFieldDate(DATE, 0);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getDate()" );
+ return result;
+ }
+
+ public synchronized long getExpiration() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getExpiration()" );
+ final long result = getHeaderFieldDate(EXPIRES, 0);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getExpiration()" );
+ return result;
+ }
+
+ public String getFile()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getFile()" );
+ String result = iUri.getPath();
+ if (result.length() == 0)
+ result = null;
+ else
+ result = "/" + result;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getFile: " + result );
+ return result;
+ }
+
+ public synchronized String getHeaderField(int aIndex) throws IOException
+ {
+ ensureOpen("getHeaderField");
+ ensureResponse();
+ if (aIndex >= iReplyHeaderKeys.size() || aIndex < 0)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderField(int)
+ // returns null" );
+ return null;
+ }
+ final String result = (String) iReplyHeaders.get(iReplyHeaderKeys
+ .elementAt(aIndex));
+ if (result != null)
+ {
+ int length = result.length();
+ String keys = (String) iReplyHeaderKeys.elementAt(aIndex);
+ if (keys.equalsIgnoreCase("Set-Cookie") == true)
+ {
+ // first cookie is discarded
+ if ((result.charAt(0)) == ',')
+ {
+ throw new IOException(
+ "cookie size too large - hence discarded");
+ }
+
+ // last cookie is discarded
+ if ((result.charAt(length - 2)) == ',')
+ {
+ throw new IOException(
+ "cookie size too large - hence discarded");
+ }
+
+ int index = result.indexOf(", ,", 0);
+ if (index != -1)
+ {
+ throw new IOException(
+ "cookie size too large - hence discarded");
+ }
+ }
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderField(int)" );
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHeaderField(int): " + result);
+ return result;
+ }
+
+ public synchronized String getHeaderField(String aName) throws IOException
+ {
+ ensureOpen("getHeaderField");
+ ensureResponse();
+ if (aName == null)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "--
+ // getHeaderField(String) returns null" );
+ return null;
+ }
+ final String result = (String) iReplyHeaders.get(aName.toLowerCase());
+
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHeaderField(String): "
+ + result);
+ if (result != null)
+ {
+ int length = result.length();
+ if (aName.equalsIgnoreCase("Set-Cookie") == true)
+ {
+ // first cookie is discarded
+ if ((result.charAt(0)) == ',')
+ {
+ throw new IOException(
+ "cookie size too large - hence discarded");
+ }
+
+ // last cookie is discarded
+ if ((result.charAt(length - 2)) == ',')
+ {
+ throw new IOException(
+ "cookie size too large - hence discarded");
+ }
+
+ int index = result.indexOf(", ,", 0);
+ if (index != -1)
+ {
+ throw new IOException(
+ "cookie size too large - hence discarded");
+ }
+ }
+ }
+ return result;
+ }
+
+ public synchronized long getHeaderFieldDate(String aName, long aDfault)
+ throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "+ getHeaderFieldDate(String, long)");
+ String value;
+
+ value = getHeaderField(aName);
+ if (value != null)
+ {
+ final long result = parseDate(value);
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- getHeaderFieldDate(String, long)");
+ return result;
+ }
+ else
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- getHeaderFieldDate(String, long) return aDfault");
+ return aDfault;
+ }
+ }
+
+ public synchronized int getHeaderFieldInt(String aName, int aDfault)
+ throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "+ getHeaderFieldInt(String, int) , name = " + aName
+ + "default = " + aDfault);
+ String value;
+
+ value = getHeaderField(aName);
+ if (value == null)
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- getHeaderFieldInt(String, int) returns aDfault");
+ return aDfault;
+ }
+ else
+ {
+ try
+ {
+ final int result = Integer.parseInt(value);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-
+ // getHeaderFieldInt(String, int)" );
+ return result;
+ }
+ catch (NumberFormatException nfe)
+ {
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderFieldInt (String, int): " + aDfault);
+ return aDfault;
+ }
+ }
+ }
+
+ public synchronized String getHeaderFieldKey(int aIndex) throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHeaderFieldKey(int)"
+ // );
+ ensureOpen("getHeaderFieldKey");
+ ensureResponse();
+ if (aIndex >= iReplyHeaderKeys.size() || aIndex < 0)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-
+ // getHeaderFieldKey(int) returns null" );
+ return null;
+ }
+ final String result = (String) iReplyHeaderKeys.elementAt(aIndex);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderFieldKey(int)"
+ // );
+ return result;
+ }
+
+ public String getHost()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHost()" );
+ final String result = iUri.getHost();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHost()" );
+ return result;
+ }
+
+ public synchronized long getLastModified() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getLastModified()" );
+ final long result = getHeaderFieldDate(LAST_MODIFIED, 0);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getLastModified()" );
+ return result;
+ }
+
+ public int getPort()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getPort()" );
+ final String temp = iUri.getPort();
+ if (temp.length() != 0)
+ {
+ try
+ {
+ final int result = Integer.parseInt(temp);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getPort()" );
+ return result;
+ }
+ catch (NumberFormatException ex)
+ {
+ // do nothing, return default port
+ }
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getPort() returns default port" );
+ return DEFAULT_PORT;
+ }
+
+ public String getProtocol()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getProtocol()" );
+ final String result = iUri.getProtocol();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getProtocol()" );
+ return result;
+ }
+
+ public String getQuery()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getQuery()" );
+ String result = iUri.getQuery();
+ if (result.length() == 0)
+ result = null;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getQuery()" );
+ return result;
+ }
+
+ public String getRef()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "* getRef()" );
+ return iRef;
+ }
+
+ public final String getRequestMethod()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "* getRequestMethod()" );
+ return iRequestMethod;
+ }
+
+ public final String getRequestProperty(String aKey)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+
+ // getRequestProperty(String)" );
+ final String result = (String) iRequestProperties.get(aKey);
+
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-
+ // getRequestProperty(String)" );
+ return result;
+ }
+
+ public synchronized final int getResponseCode() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getResponseCode()");
+ ensureOpen("getResponseCode");
+ ensureResponse();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getResponseCode() : "
+ + iResponseCode);
+ return iResponseCode;
+ }
+
+ public synchronized String getResponseMessage() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getResponseMessage()" );
+ ensureOpen("getResponseMessage");
+ ensureResponse();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getResponseMessage() : "
+ // + iResponseMessage);
+ return iResponseMessage;
+ }
+
+ public String getURL()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getURL()" );
+ final String result = iUri.toString();
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getURL()" );
+ return result;
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized void setRequestMethod(String aMethod)
+ throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ setRequestMethod(String)"
+ // );
+ try
+ {
+ if (aMethod == null)
+ {
+ throw new NullPointerException("Request method is null");
+ }
+ ensureOpen("setRequestMethod");
+ if (iState != SETUP)
+ {
+ throwIOException("setRequestMethod method failed.Connection state is already connected");
+ }
+ if ((GET.equals(aMethod) == false)
+ && (HEAD.equals(aMethod) == false)
+ && (POST.equals(aMethod) == false))
+ {
+ throwIOException("Invalid or Unsupported request method: "
+ + aMethod);
+ }
+ // ignore if an output stream has already been open
+ if (iPostedDataStream == null)
+ iRequestMethod = aMethod;
+ }
+ catch (IOException ex)
+ {
+ Logger.WLOG(Logger.ESOCKET, "setRequestMethod failed", ex);
+ throw ex;
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- setRequestMethod(String)" );
+ return;
+ }
+
+ /**
+ * Please refer to Jsr 118
+ */
+ public synchronized void setRequestProperty(String aKey, String aValue)
+ throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ setRequestProperty( " +
+ // aKey + " , " + aValue );
+ ensureOpen("setRequestProperty");
+ if (iState != SETUP)
+ {
+ throwIOException("setRequestProperty method failed.Connection state is already connected");
+ }
+
+ // ignore if an outputstream has been open
+ if (iPostedDataStream == null)
+ {
+ if (aKey.equals(USER_AGENT) && !iTrustedSuite)
+ {
+ String val = aValue + ' ' + UNTRUSTED_1_0;
+ iRequestProperties.put(aKey, val);
+ }
+ else
+ {
+ iRequestProperties.put(aKey, aValue);
+ }
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- setRequestProperty(String, String)" );
+ return;
+ }
+
+ protected void closeConnection() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "++++++++++++++ Java closeConnection()");
+ if ((iNativeTransactionHande != 0) &&(iNativeHttpSessionHandle!=0))
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "########## Valid handle");
+ _closeTransaction(iNativeTransactionHande);
+ iNativeTransactionHande = 0;
+
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "-------------- Java closeConnection()");
+ }
+
+ protected void addHeader(String aKey, String aValue)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ addHeader to reply enum(
+ // " + aKey + " , " + aValue );
+ // Should check for duplicate keys
+ aKey = aKey.toLowerCase();
+ iReplyHeaders.put(aKey, aValue);
+ iReplyHeaderKeys.addElement(aKey);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- addHeader(String,
+ // String)" );
+ return;
+ }
+
+ protected synchronized void inputStreamClosed() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "++++++ inputStreamClosed()");
+ synchronized (iNativeDataReadyForRead.getLock())
+ {
+ iInputStream = null;
+ iNativeHttpInputStream = null;
+ if (iClosed && (iOutputStream == null))
+ {
+ closeConnection();
+ }
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "-------- inputStreamClosed()");
+ }
+
+
+ protected synchronized void outputStreamFlushed() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ outputStreamFlushed()" );
+ switch (iState)
+ {
+ case SETUP:
+ case CONNECTED:
+ case REQUEST_HEADERS_SENT:
+ ensureResponse();
+
+ default:
+ // No-op
+ ;
+ }
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- outputStreamFlushed()" );
+ }
+
+ protected synchronized void outputStreamClosed() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "++++++++ outputStreamClosed()");
+ iOutputStream = null;
+ iPostedDataStream = null;
+ if (iClosed && iInputStream == null)
+ {
+ closeConnection();
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "-------- outputStreamClosed()");
+ }
+
+ private synchronized void connect() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+++++++ Java connect()");
+ if (iNativeTransactionHande <= 0)
+ {
+ final int handle = _createNativeTransaction(
+ iNativeHttpSessionHandle, iUri.toString(), iRequestMethod);
+ iNativeTransactionHande = NativeError.check(handle);
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-------- connect()");
+ }
+
+ protected void ensureConnected() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureConnected()" );
+ switch (iState)
+ {
+ case SETUP:
+
+ connect();
+ iState = CONNECTED;
+ break;
+
+ default:
+ ;
+ }
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureConnected()" );
+ return;
+ }
+
+ protected void ensureOpen(String aMethodName) throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureOpen()" );
+ if (iClosed)
+ {
+ throwIOException(aMethodName
+ + " method failed.Connection state is already closed");
+ }
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureOpen()" );
+ return;
+ }
+
+ protected void ensureResponse() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureResponse()" );
+ ensureConnected();
+ switch (iState)
+ {
+ case CONNECTED:
+
+ sendRequest();
+ // Fall Through
+ case REQUEST_HEADERS_SENT:
+ case REQUEST_SENT:
+ getResponse();
+ iState = REPLY_RECEIVED;
+ break;
+
+ default:
+ // No-op
+ ;
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureResponse()" );
+ return;
+ }
+
+ protected synchronized void getResponse() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getResponse()");
+
+ boolean flag = true;
+ String[] rawHeaders = _getResponse(iNativeTransactionHande);
+ if (rawHeaders == null || rawHeaders.length == 0)
+ throwIOException("Invalid http response");
+
+ // First element is the Status Line
+ readStatusLine(rawHeaders[0]);
+ readHeaders(rawHeaders);
+ processReplyHeaders();
+ rawHeaders = null;
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getResponse()" );
+ return;
+ }
+
+ protected void readStatusLine(String aStatusLine) throws IOException
+ {
+ // Status-Line = HTTP-Version ;; Status-Code ;; Reason-Phrase
+ Logger.PLOG(Logger.ESOCKET, "HTTP response, status line: "
+ + aStatusLine);
+ // HTTP-Version
+ final int fisrtSepIndex = aStatusLine.indexOf(NATIVESEPERATOR);
+ if (fisrtSepIndex <= 0)
+ {
+ throwIOException("Invalid http response");
+ }
+ String parse = aStatusLine.substring(0, fisrtSepIndex);
+
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, " Server Vesion : " + parse
+ // );
+
+ // Check the server we are connecting to is a http v1.0 or v1.1
+ if (parse.compareTo(VERSION_1_1) != 0
+ && parse.compareTo(VERSION_1_0) != 0)
+ {
+ throwIOException("Invalid http response.Http-version mismatch");
+ }
+
+ // Status Code
+ int nextSepIndex = 0;
+ nextSepIndex = aStatusLine.indexOf(NATIVESEPERATOR, fisrtSepIndex + 2);
+ if (nextSepIndex <= 0)
+ {
+ throwIOException("Invalid http response");
+ }
+ parse = null;
+ parse = aStatusLine.substring(fisrtSepIndex + 2, nextSepIndex);
+ iResponseCode = Integer.parseInt(parse);
+
+ // Reason-Phrase
+
+ iResponseMessage = aStatusLine.substring(nextSepIndex + 2, aStatusLine
+ .length());
+ if (iResponseMessage.length() <= 0)
+ {
+ throwIOException("Invalid http response");
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- readStatusLine(InputStream)" );
+ }
+
+ protected long parseDate(String aDateString)
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ parseDate(String)" );
+ final long result = DateUtil.epocDifference(aDateString);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- parseDate(String)" );
+ return result;
+ }
+
+ protected void processReplyHeaders()
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ processReplyHeaders()" );
+ String value;
+ value = (String) iReplyHeaders.get(CONTENT_LENGTH.toLowerCase());
+ if (value != null)
+ {
+ iLength = Long.parseLong(value);
+ }
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- processReplyHeaders()" );
+ }
+
+ protected void readHeaders(String[] aHeaders) throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ readHeaders()" );
+ // Headers are of the form
+ // valueKey + NATIVESEPERATOR + property
+ String key;
+ String value;
+ String rawHeader = null;
+ final int headersCount = aHeaders.length;
+
+ // First element is status line which we ignore (parsed in
+ // readStatusLine)
+ int sepIndex = -1;
+ for (int ii = 1; ii < headersCount; ++ii)
+ {
+ rawHeader = aHeaders[ii];
+ sepIndex = rawHeader.indexOf(NATIVESEPERATOR);
+ key = rawHeader.substring(0, sepIndex);
+ value = rawHeader.substring(sepIndex + 2, rawHeader.length());
+ addHeader(key, value);
+ rawHeader = null;
+ key = null;
+ value = null;
+ sepIndex = -1;
+ }
+ //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- readHeaders(InputStream)" );
+ }
+
+ protected synchronized void sendRequest() throws IOException
+ {
+ ensureConnected();
+ final int count = iRequestProperties.size();
+ int headerCount = count;
+
+ final Enumeration keyEnum = iRequestProperties.keys();
+ String[] headers = null;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- headerCount: " +
+ // headerCount );
+ if (headerCount > 0)
+ headers = new String[headerCount];
+
+ String valueKey = null;
+ String property = null;
+ String concat = null;
+ boolean untrustedAdded = false;
+ for (int ii = 0; ii < count; ++ii)
+ {
+ valueKey = (String) keyEnum.nextElement();
+ property = getRequestProperty(valueKey);
+ concat = valueKey + NATIVESEPERATOR + property;
+ headers[ii] = concat;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "submit : " + ii + " : "
+ // + concat + "concat length:" + concat.length() );
+ }
+
+ byte[] postData = null;
+ int postDataLength = 0;
+ // Data to be sent native
+ if (iPostedDataStream != null)
+ {
+ postData = iPostedDataStream.toByteArray();
+ postDataLength = postData.length;
+ }
+
+ synchronized (iTransactionBlock.getLock())
+ {
+ // Submit the headers and the data at the same time
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ _submitTransaction
+ // headers count : " + (headers!=null ?headers.length:-1 ) );
+ synchronized (iTransactionBlock)
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "before _submitTransaction ");
+ final int err = _submitTransaction(iNativeTransactionHande,
+ headers, postData, postDataLength,iRespTimeOut);
+
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "-_submitTransaction +err " + err);
+
+ // Clear tempory byte array and headers array
+ postData = null;
+ headers = null;
+ if (err != 0)
+ throwIOException("Unable to connect to server.Symbian os error code: "
+ + err);
+ iState = REQUEST_SENT;
+ waitForTransaction();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- sendRequest _submitTransaction");
+ }
+ }
+ if ((iTransactionBlock.getResult() == -18) &&(iRetries < 2))
+ {
+ iRetries++;
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- sendRequest KErrNotReady erroi, calling recursive sendRequest()");
+ sendRequest();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- sendRequest KErrNotReady erroi, calling recursive sendRequest() returned");
+ }
+ }
+
+ protected void throwIOException(String aMessage) throws IOException
+ {
+ throw new IOException(aMessage);
+ }
+
+ protected void waitForTransaction() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+waitForTransaction");
+
+ iTransactionBlock.waitForCompletion();
+ final int result = iTransactionBlock.getResult();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "waitForTransaction result :"
+ + result);
+ if ((result < 0))
+ {
+ final Integer error = new Integer(result);
+ if ((result == -18))
+ {
+ if (iRetries >=2)
+ {
+ throwIOException(error.toString());
+ }
+ }
+ else
+ {
+ throwIOException(error.toString());
+ }
+
+ }
+
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-waitForTransaction");
+ }
+
+ protected DataInputStream makeDataInputStream() throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> makeDataInputStream()<<<<<<<<<<<<<<<<<<<<<<<");
+ DataInputStream result = null;
+ final String transferEncoding;
+
+ final int bytesTotal = (int) getLength();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "++++++ makeDataInputStream() getLength():" + bytesTotal);
+
+ if (iNativeHttpInputStream == null)
+ iNativeHttpInputStream = new NativeHttpInputStream(this);
+ result = new PlainDataInputStream(iNativeHttpInputStream);
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, " makeDataInputStream()");
+ return result;
+ }
+
+ protected void makeDataOutputStream() throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ makeDataOutputStream()"
+ // );
+ iPostedDataStream = new ByteArrayOutputStream();
+ iOutputStream = new PlainDataOutputStream(iPostedDataStream);
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- makeDataOutputStream()"
+ // );
+ }
+
+ /**
+ * From NativeHttpByteSoure
+ */
+ public void closeByteSource()
+ {
+ }
+
+ /*
+ * Returns the total number of bytes read into the buffer, or -1 if there is
+ * no more data because the end of the stream has been reached.
+ */
+ public synchronized int getBytes(byte[] aBytes, int aLength)
+ throws IOException
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+getBytes()");
+ int result = -1;
+
+ // Prevents multiple read
+ synchronized (iNativeDataReadyForRead.getLock())
+ {
+ synchronized (iNativeDataReadyForRead)
+ {
+ if (iNativeDataReadyForRead.getResult() == BlockingOperation.BLOCKED)
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "+ getBytes()- ReadOperation.waitForCompletion()");
+ iNativeDataReadyForRead.waitForCompletion();
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- getBytes()- ReadOperation.waitForCompletion()");
+ }
+ }
+
+ final int callBackResult = iNativeDataReadyForRead.getResult();
+ if (callBackResult == EOF)
+ return 0; // All data has been read
+ if (callBackResult < 0)
+ throwIOException("Unable to read http response.Symbian os error code: "
+ + result);
+ // Block until data has been read from native
+ iNativeDataReadyForRead.setResult(BlockingOperation.BLOCKED);
+ if (iNativeHttpSessionHandle!=0)
+ {
+ result = _getBytes(iNativeTransactionHande, aBytes, aLength);
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ 2 getBytes()- result "
+ + result);
+ }
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-getBytes() + result "
+ + result);
+ return result;
+ }
+
+ public int available() throws IOException
+ {
+ if ((iClosed == true) && (iInputStream == null)
+ && (iOutputStream == null))
+ {
+ throw new IOException(
+ "Available method failed.Connection is already closed");
+ }
+ return _available(iNativeTransactionHande);
+ }
+
+ /*
+ * Native call back methods
+ */
+ protected void transactionSubmitCallback(int aStatus)
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "+ transactionSubmitCallback Callback");
+ iTransactionBlock.notifyCompleted(aStatus);
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- transactionSubmitCallback Callback");
+ }
+
+ protected void dataReadyForReadCallBack(int aStatus)
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ dataReadyForReadCallBack "
+ + aStatus);
+ iNativeDataReadyForRead.notifyCompleted(aStatus);
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- dataReadyForReadCallBack");
+ }
+
+ /*
+ * Native Calls
+ */
+ private native int _createHttpSession(int a, int aType, int aApn,
+ int[] retval);
+ private native int _createNativeTransaction(int aNativeHttpSessionHandle,
+ String aUri, String aRequestMethod);
+ private native int _submitTransaction(int aNativeTransactionHande,
+ String[] aHeaders, byte[] aPostData, int aPostLength,
+ int aRespTimeOut);
+ private native String[] _getResponse(int aNativeTransactionHande);
+ private native int _getBytes(int aNativeTransactionHande, byte[] aBuffer,
+ int aLength);
+ private native void _closeTransaction(int aNativeTransactionHande);
+ private native int _available(int aNativeTransactionHande);
+ private native String _getUserAgentHeaderValue(boolean aMidpRuntime);
+
+ /*
+ *
+ * class PlainDataInputStream
+ *
+ */
+ protected class PlainDataInputStream extends DataInputStream
+ {
+ public void close() throws IOException
+ {
+ super.close();
+ inputStreamClosed();
+ }
+
+ PlainDataInputStream(InputStream aIs)
+ {
+ super(aIs);
+ }
+ }
+
+ /*
+ *
+ * class PlainDataOutputStream
+ *
+ */
+ protected class PlainDataOutputStream extends DataOutputStream
+ {
+ private boolean iFlushed = false;
+
+ public void close() throws IOException
+ {
+ if (!iFlushed)
+ flush();
+ super.close();
+ outputStreamClosed();
+ }
+
+ public void flush() throws IOException
+ {
+ super.flush();
+ outputStreamFlushed();
+ iFlushed = true;
+ }
+
+ PlainDataOutputStream(OutputStream aOs)
+ {
+ super(aOs);
+ }
+ }
+
+ class NativeHttpInputStream extends InputStream
+ {
+ private NativeHttpByteSource iByteSource;
+ private byte[] iBuffer;
+ private int iOffset;
+ private int iLength;
+ // 6K buffer to read from native http
+ private final static int BUFFER_SIZE = 6144;
+ private boolean iIsClosed;
+
+ NativeHttpInputStream(NativeHttpByteSource aByteSource)
+ {
+ // Bytesource length may be -1 indicating CHUNKED (size unknown)
+ iByteSource = aByteSource;
+ iBuffer = new byte[BUFFER_SIZE];
+ iIsClosed = false;
+ }
+
+ public synchronized void close() throws IOException
+ {
+ iIsClosed = true;
+ iByteSource.closeByteSource();
+ }
+
+ public synchronized int read() throws IOException
+ {
+ final int BYTEPADDER = 0xFF;
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo,"NativeInputStream.read()
+ // iOffset, "+ iOffset + "iLength " + iLength);
+ throwIfClosed();
+
+ if (iOffset == iLength)
+ {
+ // Logger.LOG(Logger.ESOCKET,
+ // Logger.EInfo,"NativeInputStream.read() iOffset == iLength
+ // getBytes: iLength " + iLength );
+ getBytes();
+ }
+
+ // Logger.LOG(Logger.ESOCKET, Logger.EInfo,"NativeInputStream.read()
+ // 2 iOffset, "+ iOffset + " iLength " + iLength);
+ if (iLength > 0)
+ {
+ return iBuffer[iOffset++] & BYTEPADDER;
+ }
+ else
+ {
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "NativeInputStream.read(): return -1 ");
+ return EOF;
+ }
+ }
+
+ public synchronized int read(byte[] aBytes, int aOffset, int aLength)
+ throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET,
+ // Logger.EInfo,"+NativeInputStream.read(,,,) aOffset, "+ aOffset +
+ // "aLength" + aLength);
+
+ throwIfClosed();
+
+ int nBytes = 0;
+ while (nBytes < aLength)
+ {
+ // Logger.LOG(Logger.ESOCKET,
+ // Logger.EInfo,"NativeInputStream.read(,,,) nBytes, "+ nBytes);
+ int count = readInner(aBytes, aOffset + nBytes, aLength
+ - nBytes);
+ // Logger.LOG(Logger.ESOCKET,
+ // Logger.EInfo,"NativeInputStream.read(,,,) count = readInner,
+ // "+ count);
+ if (count < 0)
+ {
+ nBytes = (nBytes == 0) ? -1 : nBytes;
+ break;
+ }
+ nBytes += count;
+ }
+ Logger.LOG(Logger.ESOCKET, Logger.EInfo,
+ "- NativeInputStream.read(,,,) return nBytes, " + nBytes);
+ return nBytes;
+ }
+
+ private int readInner(byte[] aBytes, int aOffset, int aLength)
+ throws IOException
+ {
+ // Logger.LOG(Logger.ESOCKET,
+ // Logger.EInfo,"NativeInputStream.readInner() iOffset: "+ iOffset +
+ // "iLength: " + iLength);
+ if (iOffset == iLength)
+ {
+ getBytes();
+ }
+ if (iLength == 0)
+ {
+ return EOF;
+ }
+
+ int nBytesLeft = iLength - iOffset;
+ // Logger.LOG(Logger.ESOCKET,
+ // Logger.EInfo,"NativeInputStream.readInner() : nBytesLeft "+
+ // nBytesLeft);
+ int nBytesToCopy = aLength > nBytesLeft ? nBytesLeft : aLength;
+ System.arraycopy(iBuffer, iOffset, aBytes, aOffset, nBytesToCopy);
+ iOffset += nBytesToCopy;
+ return nBytesToCopy;
+ }
+
+ private void getBytes() throws IOException
+ {
+ int nBytes = iByteSource.getBytes(iBuffer, iBuffer.length);
+
+ if (nBytes == -1)
+ {
+ throw new IOException();
+ }
+ iLength = nBytes;
+ iOffset = 0;
+ }
+
+
+ /**
+ * Returns the number of bytes that can be read (or skipped over) from
+ * this input stream without blocking by the next caller of a method for
+ * this input stream. The next caller might be the same thread or
+ * another thread.
+ *
+ * @return the number of bytes that can be read from this input stream
+ * without blocking.
+ * @exception IOException
+ * if an I/O error occurs.
+ */
+ public int available() throws IOException
+ {
+ throwIfClosed();
+ return iByteSource.available();
+ }
+
+ private void throwIfClosed() throws IOException
+ {
+ if (iIsClosed)
+ {
+ throw new IOException("Connection is already closed");
+ }
+ }
+ }
+}