1238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde/* Copyright (c) 2015 The Android Open Source Project 2238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Copyright (C) 2015 Samsung LSI 39439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc. 49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * 59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * All rights reserved. 69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * 79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Redistribution and use in source and binary forms, with or without 89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * modification, are permitted provided that the following conditions are met: 99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * 109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions of source code must retain the above copyright notice, 119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer. 129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * 139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice, 149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer in the documentation 159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * and/or other materials provided with the distribution. 169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * 179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors 189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * may be used to endorse or promote products derived from this software 199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * without specific prior written permission. 209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * 219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * POSSIBILITY OF SUCH DAMAGE. 329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage javax.obex; 359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.IOException; 379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.InputStream; 389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.DataInputStream; 399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.OutputStream; 409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.DataOutputStream; 419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.ByteArrayOutputStream; 429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 43238e0f934f1f47263b384bc745ae0678c777130dCasper Bondeimport android.util.Log; 44238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/** 469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * This class implements the Operation interface for server side connections. 479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * <P> 4805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <STRONG>Request Codes</STRONG> There are four different request codes that 4905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * are in this class. 0x02 is a PUT request that signals that the request is not 5005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * complete and requires an additional OBEX packet. 0x82 is a PUT request that 5105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * says that request is complete. In this case, the server can begin sending the 5205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * response. The 0x03 is a GET request that signals that the request is not 5305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * finished. When the server receives a 0x83, the client is signaling the server 5405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * that it is done with its request. TODO: Extend the ClientOperation and reuse 5505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * the methods defined TODO: in that class. 562e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide 579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic final class ServerOperation implements Operation, BaseStream { 599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 60238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private static final String TAG = "ServerOperation"; 61238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 62238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private static final boolean V = ObexHelper.VDBG; // Verbose debugging 63238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public boolean isAborted; 659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public HeaderSet requestHeader; 679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public HeaderSet replyHeader; 699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public boolean finalBitSet; 719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 723998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private InputStream mInput; 739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private ServerSession mParent; 759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 763998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private int mMaxPacketLength; 772e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly 783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private int mResponseSize; 799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private boolean mClosed; 819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private boolean mGetOperation; 839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private PrivateInputStream mPrivateInput; 859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private PrivateOutputStream mPrivateOutput; 879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 88238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private ObexTransport mTransport; 89238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private boolean mPrivateOutputOpen; 919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private String mExceptionString; 939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private ServerRequestHandler mListener; 959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private boolean mRequestFinished; 979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun private boolean mHasBody; 999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 100fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie private boolean mSendBodyHeader = true; 101238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Assume SRM disabled - needs to be explicit 102238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // enabled by client 103238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private boolean mSrmEnabled = false; 104238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // A latch - when triggered, there is not way back ;-) 105238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private boolean mSrmActive = false; 106238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Set to true when a SRM enable response have been send 107238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private boolean mSrmResponseSent = false; 108238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // keep waiting until final-bit is received in request 109238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // to handle the case where the SRM enable header is in 110238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // a different OBEX packet than the SRMP header. 111238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private boolean mSrmWaitingForRemote = true; 112238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Why should we wait? - currently not exposed to apps. 113238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private boolean mSrmLocalWait = false; 114fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie 1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 1163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun * Creates new ServerOperation 1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param p the parent that created this object 1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param in the input stream to read from 1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param out the output stream to write to 1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param request the initial request that was received from the client 1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param maxSize the max packet size that the client will accept 1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param listen the listener that is responding to the request 1232e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an IO error occurs 1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public ServerOperation(ServerSession p, InputStream in, int request, int maxSize, 1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ServerRequestHandler listen) throws IOException { 1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly isAborted = false; 1293998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mParent = p; 1303998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mInput = in; 1313998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mMaxPacketLength = maxSize; 1323998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mClosed = false; 1333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun requestHeader = new HeaderSet(); 1343998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun replyHeader = new HeaderSet(); 1353998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mPrivateInput = new PrivateInputStream(this); 1363998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mResponseSize = 3; 1373998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mListener = listen; 1383998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mRequestFinished = false; 1393998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mPrivateOutputOpen = false; 1403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mHasBody = false; 141238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde ObexPacket packet; 142238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mTransport = p.getTransport(); 1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Determine if this is a PUT request 1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 147238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((request == ObexHelper.OBEX_OPCODE_PUT) || 148238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde (request == ObexHelper.OBEX_OPCODE_PUT_FINAL)) { 1499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * It is a PUT request. 1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 1523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mGetOperation = false; 15365208317ba9d16486b47ebcaa868c596d424c87fLixin Yue 15465208317ba9d16486b47ebcaa868c596d424c87fLixin Yue /* 15565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue * Determine if the final bit is set 15665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue */ 157238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((request & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) { 15865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue finalBitSet = false; 15965208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } else { 16065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue finalBitSet = true; 16165208317ba9d16486b47ebcaa868c596d424c87fLixin Yue mRequestFinished = true; 16265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } 163238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else if ((request == ObexHelper.OBEX_OPCODE_GET) || 164238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde (request == ObexHelper.OBEX_OPCODE_GET_FINAL)) { 1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * It is a GET request. 1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 1683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mGetOperation = true; 1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 17065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue // For Get request, final bit set is decided by server side logic 1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly finalBitSet = false; 17265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue 173238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (request == ObexHelper.OBEX_OPCODE_GET_FINAL) { 17465208317ba9d16486b47ebcaa868c596d424c87fLixin Yue mRequestFinished = true; 17565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } 1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 17765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue throw new IOException("ServerOperation can not handle such request"); 1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 180238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde packet = ObexPacket.read(request, mInput); 1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Determine if the packet length is larger than this device can receive 1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 185238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) { 1863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null); 187238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Packet received was too large. Length: " 188238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde + packet.mLength + " maxLength: " + ObexHelper.getMaxRxPacketSize(mTransport)); 1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Determine if any headers were sent in the initial request 1939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 194238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (packet.mLength > 3) { 195238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(!handleObexPacket(packet)) { 196238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return; 1979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 198238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (!mHasBody) { 1993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun while ((!mGetOperation) && (!finalBitSet)) { 2003998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 2013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateInput.available() > 0) { 2029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly break; 2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun } 2063998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun } 2079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) { 2093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 2103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateInput.available() > 0) { 2119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly break; 2129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // wait for get request finished !!!! 21665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue while (mGetOperation && !mRequestFinished) { 2173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 2189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 221238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /** 222238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Parse headers and update member variables 223238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @param packet the received obex packet 224238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @return false for failing authentication - and a OBEX_HTTP_UNAUTHORIZED 225238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * response have been send. Else true. 226238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @throws IOException 227238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 228238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private boolean handleObexPacket(ObexPacket packet) throws IOException { 229238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde byte[] body = updateRequestHeaders(packet); 230238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 231238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (body != null) { 232238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mHasBody = true; 233238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 234238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) { 235238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mListener.setConnectionId(ObexHelper 236238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde .convertToLong(requestHeader.mConnectionID)); 237238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else { 238238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mListener.setConnectionId(1); 239238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 240238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 241238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (requestHeader.mAuthResp != null) { 242238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (!mParent.handleAuthResp(requestHeader.mAuthResp)) { 243238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mExceptionString = "Authentication Failed"; 244238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null); 245238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mClosed = true; 246238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestHeader.mAuthResp = null; 247238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return false; 248238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 249238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestHeader.mAuthResp = null; 250238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 251238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 252238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (requestHeader.mAuthChall != null) { 253238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mParent.handleAuthChall(requestHeader); 254238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // send the auhtResp to the client 255238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length]; 256238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0, 257238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde replyHeader.mAuthResp.length); 258238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestHeader.mAuthResp = null; 259238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestHeader.mAuthChall = null; 260238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 261238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 262238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (body != null) { 263238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mPrivateInput.writeBytes(body, 1); 264238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 265238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return true; 266238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 267238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 268238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /** 269238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Update the request header set, and sniff on SRM headers to update local state. 270238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @param data the OBEX packet data 271238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @return any bytes in a body/end-of-body header returned by {@link ObexHelper.updateHeaderSet} 272238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @throws IOException 273238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 274238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private byte[] updateRequestHeaders(ObexPacket packet) throws IOException { 275238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde byte[] body = null; 276238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (packet.mPayload != null) { 277238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde body = ObexHelper.updateHeaderSet(requestHeader, packet.mPayload); 278238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 279238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde Byte srmMode = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE); 280238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mTransport.isSrmSupported() && srmMode != null 281238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde && srmMode == ObexHelper.OBEX_SRM_ENABLE) { 282238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mSrmEnabled = true; 283238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(V) Log.d(TAG,"SRM is now ENABLED (but not active) for this operation"); 284238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 285238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde checkForSrmWait(packet.mHeaderId); 286238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if((!mSrmWaitingForRemote) && (mSrmEnabled)) { 287238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(V) Log.d(TAG,"SRM is now ACTIVE for this operation"); 288238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mSrmActive = true; 289238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 290238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return body; 291238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 292238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 293238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /** 294238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Call this only when a complete request have been received. 295238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * (This is not optimal, but the current design is not really suited to 296238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * the way SRM is specified.) 297238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 298238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private void checkForSrmWait(int headerId){ 299238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (mSrmEnabled && (headerId == ObexHelper.OBEX_OPCODE_GET 300238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde || headerId == ObexHelper.OBEX_OPCODE_GET_FINAL 301238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde || headerId == ObexHelper.OBEX_OPCODE_PUT)) { 302238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde try { 303238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mSrmWaitingForRemote = false; 304238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde Byte srmp = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER); 305238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) { 306238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mSrmWaitingForRemote = true; 307238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Clear the wait header, as the absents of the header when the final bit is set 308238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // indicates don't wait. 309238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null); 310238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 311238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } catch (IOException e) {if(V){Log.w(TAG,"Exception while extracting header",e);}} 312238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 313238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 314238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 3153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public boolean isValidBody() { 3163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun return mHasBody; 3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 32005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Determines if the operation should continue or should wait. If it should 32105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * continue, this method will continue the operation. 3229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param sendEmpty if <code>true</code> then this will continue the 32305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * operation even if no headers will be sent; if <code>false</code> 32405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * then this method will only continue the operation if there are 32505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * headers to send 32605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * @param inStream if<code>true</code> the stream is input stream, otherwise 32705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * output stream 3289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return <code>true</code> if the operation was completed; 32905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>false</code> if no operation took place 3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 3319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream) 3329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throws IOException { 3333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (!mGetOperation) { 3349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (!finalBitSet) { 3359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (sendEmpty) { 3363998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 3379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return true; 3389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 3393998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) { 3403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 3419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return true; 3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 3439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return false; 3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 3479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return false; 3489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 3503998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 3519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return true; 3529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 35605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it 357238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * will wait for a response from the client before ending unless SRM is active. 3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param type the response code to send back to the client 3599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return <code>true</code> if the final bit was not set on the reply; 36005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>false</code> if no reply was received because the operation 361238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * ended, an abort was received, the final bit was set in the 362238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * reply or SRM is active. 3632e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an IO error occurs 3649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 3653998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public synchronized boolean sendReply(int type) throws IOException { 3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ByteArrayOutputStream out = new ByteArrayOutputStream(); 367238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde boolean skipSend = false; 368238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde boolean skipReceive = false; 369238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde boolean srmRespSendPending = false; 3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3713998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun long id = mListener.getConnectionId(); 3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (id == -1) { 3733998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun replyHeader.mConnectionID = null; 3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 3753998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun replyHeader.mConnectionID = ObexHelper.convertToByteArray(id); 3769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 378238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mSrmEnabled && !mSrmResponseSent) { 379238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // As we are not ensured that the SRM enable is in the first OBEX packet 380238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // We must check for each reply. 381238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(V)Log.v(TAG, "mSrmEnabled==true, sending SRM enable response."); 382238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRM_ENABLE); 383238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde srmRespSendPending = true; 384238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 385238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 386238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mSrmEnabled && !mGetOperation && mSrmLocalWait) { 387238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRMP_WAIT); 388238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 389238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 390238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde byte[] headerArray = ObexHelper.createHeader(replyHeader, true); // This clears the headers 3919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int bodyLength = -1; 3929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int orginalBodyLength = -1; 3939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateOutput != null) { 3953998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun bodyLength = mPrivateOutput.size(); 3969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly orginalBodyLength = bodyLength; 3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) { 4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int end = 0; 4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int start = 0; 4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly while (end != headerArray.length) { 4053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength 4063998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun - ObexHelper.BASE_PACKET_LENGTH); 4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (end == -1) { 4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mClosed = true; 4109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateInput != null) { 4123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mPrivateInput.close(); 4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateOutput != null) { 4163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mPrivateOutput.close(); 4179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4183998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("OBEX Packet exceeds max packet size"); 4209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly byte[] sendHeader = new byte[end - start]; 4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length); 4239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4243998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mParent.sendResponse(type, sendHeader); 4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly start = end; 4269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (bodyLength > 0) { 4299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return true; 4309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 4319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return false; 4329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 4359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write(headerArray); 4369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 43865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue // For Get operation: if response code is OBEX_HTTP_OK, then this is the 43965208317ba9d16486b47ebcaa868c596d424c87fLixin Yue // last packet; so set finalBitSet to true. 44065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) { 44165208317ba9d16486b47ebcaa868c596d424c87fLixin Yue finalBitSet = true; 44265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } 44365208317ba9d16486b47ebcaa868c596d424c87fLixin Yue 444238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mSrmActive) { 445238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(!mGetOperation && type == ResponseCodes.OBEX_HTTP_CONTINUE && 446238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mSrmResponseSent == true) { 447238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // we are in the middle of a SRM PUT operation, don't send a continue. 448238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde skipSend = true; 449238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else if(mGetOperation && mRequestFinished == false && mSrmResponseSent == true) { 450238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // We are still receiving the get request, receive, but don't send continue. 451238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde skipSend = true; 452238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else if(mGetOperation && mRequestFinished == true) { 453238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // All done receiving the GET request, send data to the client, without 454238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // expecting a continue. 455238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde skipReceive = true; 456238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 457238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(V)Log.v(TAG, "type==" + type + " skipSend==" + skipSend 458238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde + " skipReceive==" + skipReceive); 459238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 460238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(srmRespSendPending) { 461238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(V)Log.v(TAG, 462238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde "SRM Enabled (srmRespSendPending == true)- sending SRM Enable response"); 463238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mSrmResponseSent = true; 464238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 465238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 4663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) { 4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (bodyLength > 0) { 4689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 4699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Determine if I can send the whole body or just part of 4709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * the body. Remember that there is the 3 bytes for the 4719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * response message and 3 bytes for the header ID and length 4729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 4733998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) { 4743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun bodyLength = mMaxPacketLength - headerArray.length - 6; 4759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun byte[] body = mPrivateOutput.readBytes(bodyLength); 4789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 4809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Since this is a put request if the final bit is set or 4819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * the output stream is closed we need to send the 0x49 4829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * (End of Body) otherwise, we need to send 0x48 (Body) 4839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 4843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if ((finalBitSet) || (mPrivateOutput.isClosed())) { 485fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie if(mSendBodyHeader == true) { 486fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write(0x49); 487fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie bodyLength += 3; 488fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write((byte)(bodyLength >> 8)); 489fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write((byte)bodyLength); 490fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write(body); 491fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie } 4929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 493fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie if(mSendBodyHeader == true) { 4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write(0x48); 495fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie bodyLength += 3; 496fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write((byte)(bodyLength >> 8)); 497fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write((byte)bodyLength); 498fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write(body); 499fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie } 5009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 5029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 5059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) { 506238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mSendBodyHeader) { 507fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write(0x49); 508fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie orginalBodyLength = 3; 509fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write((byte)(orginalBodyLength >> 8)); 510fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie out.write((byte)orginalBodyLength); 511fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie } 5129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 514238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(skipSend == false) { 515238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mResponseSize = 3; 516238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mParent.sendResponse(type, out.toByteArray()); 517238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 5193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (type == ResponseCodes.OBEX_HTTP_CONTINUE) { 5209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 521238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mGetOperation && skipReceive) { 522238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Here we need to check for and handle abort (throw an exception). 523238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Any other signal received should be discarded silently (only on server side) 524238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde checkSrmRemoteAbort(); 5259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 526238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Receive and handle data (only send reply if !skipSend) 527238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Read a complete OBEX Packet 528238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde ObexPacket packet = ObexPacket.read(mInput); 529238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 530238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde int headerId = packet.mHeaderId; 531238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((headerId != ObexHelper.OBEX_OPCODE_PUT) 532238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde && (headerId != ObexHelper.OBEX_OPCODE_PUT_FINAL) 533238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde && (headerId != ObexHelper.OBEX_OPCODE_GET) 534238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde && (headerId != ObexHelper.OBEX_OPCODE_GET_FINAL)) { 535238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 536238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* 537238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Determine if an ABORT was sent as the reply 538238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 539238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (headerId == ObexHelper.OBEX_OPCODE_ABORT) { 540238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde handleRemoteAbort(); 5419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 542238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // TODO:shall we send this if it occurs during SRM? Errata on the subject 543238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null); 544238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mClosed = true; 545238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mExceptionString = "Bad Request Received"; 546238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Bad Request Received"); 5479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 548238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else { 5499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 550238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((headerId == ObexHelper.OBEX_OPCODE_PUT_FINAL)) { 551238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde finalBitSet = true; 552238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else if (headerId == ObexHelper.OBEX_OPCODE_GET_FINAL) { 553238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mRequestFinished = true; 5549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 556238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* 557238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Determine if the packet length is larger than the negotiated packet size 558238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 559238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) { 560238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null); 561238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Packet received was too large"); 5629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 564238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* 565238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Determine if any headers were sent in the initial request 566238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 567238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (packet.mLength > 3 || (mSrmEnabled && packet.mLength == 3)) { 568238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(handleObexPacket(packet) == false) { 569238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return false; 570238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 573238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 5749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return true; 5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 5779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return false; 5789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 5819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 582238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * This method will look for an abort from the peer during a SRM transfer. 583238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * The function will not block if no data has been received from the remote device. 584238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * If data have been received, the function will block while reading the incoming 585238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * OBEX package. 586238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * An Abort request will be handled, and cause an IOException("Abort Received"). 587238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Other messages will be discarded silently as per GOEP specification. 588238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @throws IOException if an abort request have been received. 589238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * TODO: I think this is an error in the specification. If we discard other messages, 590238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * the peer device will most likely stall, as it will not receive the expected 591238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * response for the message... 592238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * I'm not sure how to understand "Receipt of invalid or unexpected SRM or SRMP 593238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * header values shall be ignored by the receiving device." 594238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * If any signal is received during an active SRM transfer it is unexpected regardless 595238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * whether or not it contains SRM/SRMP headers... 596238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 597238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private void checkSrmRemoteAbort() throws IOException { 598238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mInput.available() > 0) { 599238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde ObexPacket packet = ObexPacket.read(mInput); 600238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* 601238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Determine if an ABORT was sent as the reply 602238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 603238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (packet.mHeaderId == ObexHelper.OBEX_OPCODE_ABORT) { 604238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde handleRemoteAbort(); 605238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else { 606238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // TODO: should we throw an exception here anyway? - don't see how to 607238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // ignore SRM/SRMP headers without ignoring the complete signal 608238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // (in this particular case). 609238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde Log.w(TAG, "Received unexpected request from client - discarding...\n" 610238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde + " headerId: " + packet.mHeaderId + " length: " + packet.mLength); 611238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 612238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 613238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 614238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 615238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private void handleRemoteAbort() throws IOException { 616238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* TODO: To increase the speed of the abort operation in SRM, we need 617238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * to be able to flush the L2CAP queue for the PSM in use. 618238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * This could be implemented by introducing a control 619238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * message to be send over the socket, that in the abort case 620238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * could carry a flush command. */ 621238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null); 622238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mClosed = true; 623238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde isAborted = true; 624238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mExceptionString = "Abort Received"; 625238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Abort Received"); 626238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 627238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 628238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /** 62905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Sends an ABORT message to the server. By calling this method, the 6309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * corresponding input and output streams will be closed along with this 6319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * object. 63205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * @throws IOException if the transaction has already ended or if an OBEX 63305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * server called this method 6349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 6359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void abort() throws IOException { 6369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Called from a server"); 6379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 6409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Returns the headers that have been received during the operation. 64105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Modifying the object returned has no effect on the headers that are sent 64205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * or retrieved. 6439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return the headers received during this <code>Operation</code> 6442e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if this <code>Operation</code> has been closed 6459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 6463998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public HeaderSet getReceivedHeader() throws IOException { 6479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 6483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun return requestHeader; 6499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 6529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Specifies the headers that should be sent in the next OBEX message that 6539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * is sent. 6549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param headers the headers to send in the next message 65505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * @throws IOException if this <code>Operation</code> has been closed or the 65605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * transaction has ended and no further messages will be exchanged 6572e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IllegalArgumentException if <code>headers</code> was not created 65805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * by a call to <code>ServerRequestHandler.createHeaderSet()</code> 6599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 6609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void sendHeaders(HeaderSet headers) throws IOException { 6619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 6629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (headers == null) { 6643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun throw new IOException("Headers may not be null"); 6659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int[] headerList = headers.getHeaderList(); 6689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (headerList != null) { 6699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly for (int i = 0; i < headerList.length; i++) { 6703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i])); 6719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 67705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Retrieves the response code retrieved from the server. Response codes are 67805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * defined in the <code>ResponseCodes</code> interface. 6799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return the response code retrieved from the server 6802e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an error occurred in the transport layer during 68105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * the transaction; if this method is called on a 68205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>HeaderSet</code> object created by calling 68305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>createHeaderSet</code> in a <code>ClientSession</code> 68405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * object; if this is called from a server 6859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 6869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public int getResponseCode() throws IOException { 6879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Called from a server"); 6889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 6919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Always returns <code>null</code> 6929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return <code>null</code> 6939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 6949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public String getEncoding() { 6959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return null; 6969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 6999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Returns the type of content that the resource connected to is providing. 7009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * E.g. if the connection is via HTTP, then the value of the content-type 7019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * header field is returned. 7029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return the content type of the resource that the URL references, or 70305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>null</code> if not known 7049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 7059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public String getType() { 7069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly try { 7073998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun return (String)requestHeader.getHeader(HeaderSet.TYPE); 7089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } catch (IOException e) { 7099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return null; 7109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 7149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Returns the length of the content which is being provided. E.g. if the 71505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * connection is via HTTP, then the value of the content-length header field 71605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * is returned. 7179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return the content length of the resource that this connection's URL 71805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * references, or -1 if the content length is not known 7199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 7209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public long getLength() { 7219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly try { 7223998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH); 7239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (temp == null) { 7259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return -1; 7269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 7279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return temp.longValue(); 7289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } catch (IOException e) { 7309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return -1; 7319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public int getMaxPacketSize() { 73565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue return mMaxPacketLength - 6 - getHeaderLength(); 73665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } 73765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue 73865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue public int getHeaderLength() { 73965208317ba9d16486b47ebcaa868c596d424c87fLixin Yue long id = mListener.getConnectionId(); 74065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue if (id == -1) { 74165208317ba9d16486b47ebcaa868c596d424c87fLixin Yue replyHeader.mConnectionID = null; 74265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } else { 74365208317ba9d16486b47ebcaa868c596d424c87fLixin Yue replyHeader.mConnectionID = ObexHelper.convertToByteArray(id); 74465208317ba9d16486b47ebcaa868c596d424c87fLixin Yue } 74565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue 74665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue byte[] headerArray = ObexHelper.createHeader(replyHeader, false); 74765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue 74865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue return headerArray.length; 7499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 7529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Open and return an input stream for a connection. 7539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return an input stream 7542e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an I/O error occurs 7559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 7569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public InputStream openInputStream() throws IOException { 7579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 7583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun return mPrivateInput; 7599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 7629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Open and return a data input stream for a connection. 7639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return an input stream 7642e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an I/O error occurs 7659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 7669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public DataInputStream openDataInputStream() throws IOException { 7679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return new DataInputStream(openInputStream()); 7689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 7719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Open and return an output stream for a connection. 7729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return an output stream 7732e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an I/O error occurs 7749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 7759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public OutputStream openOutputStream() throws IOException { 7769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 7779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateOutputOpen) { 7799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("no more input streams available, stream already opened"); 7803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun } 7819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (!mRequestFinished) { 7839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("no output streams available ,request not finished"); 7843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun } 7859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mPrivateOutput == null) { 78765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize()); 7889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7893998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mPrivateOutputOpen = true; 7903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun return mPrivateOutput; 7919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 7929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 7939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 7949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Open and return a data output stream for a connection. 7959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @return an output stream 7962e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an I/O error occurs 7979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 7989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public DataOutputStream openDataOutputStream() throws IOException { 7999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return new DataOutputStream(openOutputStream()); 8009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 8019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 8029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 8039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Closes the connection and ends the transaction 8042e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if the operation has already ended or is closed 8059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 8069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void close() throws IOException { 8079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 8083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun mClosed = true; 8099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 8109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 8119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 8129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Verifies that the connection is open and no exceptions should be thrown. 8132e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an exception needs to be thrown 8149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 8159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void ensureOpen() throws IOException { 8163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mExceptionString != null) { 8173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun throw new IOException(mExceptionString); 8189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 8193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (mClosed) { 8209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Operation has already ended"); 8219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 8229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 8239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 8249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 82505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Verifies that additional information may be sent. In other words, the 8269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * operation is not done. 8279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * <P> 82805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Included to implement the BaseStream interface only. It does not do 8299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * anything on the server side since the operation of the Operation object 8309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * is not done until after the handler returns from its method. 8312e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if the operation is completed 8329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 8339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void ensureNotDone() throws IOException { 8349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 8359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 8369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 83705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Called when the output or input stream is closed. It does not do anything 83805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * on the server side since the operation of the Operation object is not 83905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * done until after the handler returns from its method. 8409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * @param inStream <code>true</code> if the input stream is closed; 84105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>false</code> if the output stream is closed 8422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an IO error occurs 8439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 8449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void streamClosed(boolean inStream) throws IOException { 8459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 8469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 847fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie 848fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie public void noBodyHeader(){ 849fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie mSendBodyHeader = false; 850fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie } 8519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly} 852