Commits

Eric Chou  committed 97e38fd Draft

Bug 799452 - patch 2: Parse PUT request header, r=qdot

  • Participants
  • Parent commits a28241a

Comments (0)

Files changed (4)

File dom/bluetooth/BluetoothOppManager.cpp

 static nsCOMPtr<nsIInputStream> stream = nullptr;
 static uint32_t sSentFileLength = 0;
 static nsString sFileName;
-static uint64_t sFileLength = 0;
+static uint32_t sFileLength = 0;
 static nsString sContentType;
 static int sUpdateProgressCounter = 0;
 
                                            , mAbortFlag(false)
                                            , mReadFileThread(nullptr)
                                            , mPacketLeftLength(0)
+                                           , mReceiving(false)
+                                           , mPutFinal(false)
 {
   // FIXME / Bug 800249:
   //   mConnectedDeviceAddress is Bluetooth address of connected device,
   int receivedLength = aMessage->mSize;
 
   if (mPacketLeftLength > 0) {
-    opCode = ObexRequestCode::Put;
+    opCode = mPutFinal ? ObexRequestCode::PutFinal : ObexRequestCode::Put;
     packetLength = mPacketLeftLength;
   } else {
     opCode = aMessage->mData[0];
           sFileName.AssignLiteral("Unknown");
         }
 
-        rv = mBlob->GetSize(&sFileLength);
+        rv = mBlob->GetType(sContentType);
+        if (NS_FAILED(rv)) {
+          NS_WARNING("Can't get content type");
+          return;
+        }
+
+        uint64_t fileLength;
+        rv = mBlob->GetSize(&fileLength);
         if (NS_FAILED(rv)) {
           NS_WARNING("Can't get file size");
           return;
         }
 
-        rv = mBlob->GetType(sContentType);
-        if (NS_FAILED(rv)) {
-          NS_WARNING("Can't get content type");
+        // Currently we keep the size of files which were sent/received via
+        // Bluetooth not exceed UINT32_MAX because the Length header in OBEX
+        // is only 4-byte long. Although it is possible to transfer a file
+        // larger than UINT32_MAX, it needs to parse another OBEX Header
+        // and I would like to leave it as a feature.
+        if (fileLength <= UINT32_MAX) {
+          NS_WARNING("The file size is too large for now");
+          SendDisconnectRequest();
           return;
         }
 
+        sFileLength = fileLength;
+
         if (NS_FAILED(NS_NewThread(getter_AddRefs(mReadFileThread)))) {
           NS_WARNING("Can't create thread");
           SendDisconnectRequest();
       NS_WARNING("[OPP] Disconnect failed");
     } else {
       mConnected = false;
+      mReceiving = false;
       mLastCommand = 0;
       mBlob = nullptr;
       mReadFileThread = nullptr;
     SendDisconnectRequest();
   } else {
     // Remote request or unknown mLastCommand
+    ObexHeaderSet pktHeaders(opCode);
+
     if (opCode == ObexRequestCode::Connect) {
+      ParseHeaders(&aMessage->mData[7], receivedLength - 7, &pktHeaders);
       ReplyToConnect();
     } else if (opCode == ObexRequestCode::Disconnect) {
+      ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders);
       ReplyToDisconnect();
     } else if (opCode == ObexRequestCode::Put ||
                opCode == ObexRequestCode::PutFinal) {
+      if (!mReceiving) {
+        MOZ_ASSERT(mPacketLeftLength == 0);
+        ParseHeaders(&aMessage->mData[3], receivedLength - 3, &pktHeaders);
+
+        pktHeaders.GetName(sFileName);
+        pktHeaders.GetContentType(sContentType);
+        pktHeaders.GetLength(&sFileLength);
+
+        ReceivingFileConfirmation(mConnectedDeviceAddress, sFileName, sFileLength, sContentType);
+        mReceiving = true;
+      }
+
       /*
        * A PUT request from remote devices may be divided into multiple parts.
        * In other words, one request may need to be received multiple times,
        * so here we keep a variable mPacketLeftLength to indicate if current
        * PUT request is done.
        */
-      bool final = (opCode == ObexRequestCode::PutFinal);
+      mPutFinal = (opCode == ObexRequestCode::PutFinal);
 
       if (mPacketLeftLength == 0) {
-        if (receivedLength < packetLength) {
-          mPacketLeftLength = packetLength - receivedLength;
-        } else {
-          ReplyToPut(final);
-        }
+        NS_ASSERTION(mPacketLeftLength >= receivedLength,
+                     "Invalid packet length");
+        mPacketLeftLength = packetLength - receivedLength;
       } else {
-        NS_ASSERTION(mPacketLeftLength < receivedLength,
+        NS_ASSERTION(mPacketLeftLength >= receivedLength,
                      "Invalid packet length");
+        mPacketLeftLength -= receivedLength;
+      }
 
-        if (mPacketLeftLength <= receivedLength) {
-          ReplyToPut(final);
-          mPacketLeftLength = 0;
-        } else {
-          mPacketLeftLength -= receivedLength;
+      if (mPacketLeftLength == 0) {
+        ReplyToPut(mPutFinal);
+
+        if (mPutFinal) {
+          mReceiving = false;
+          FileTransferComplete(mConnectedDeviceAddress, true, true, sFileName,
+                               sSentFileLength, sContentType);
         }
       }
     }
 }
 
 void
-BluetoothOppManager::OnConnectSuccess()
-{
-}
-
-void
-BluetoothOppManager::OnConnectError()
-{
-}
-
-void
-BluetoothOppManager::OnDisconnect()
-{
-}
-
-void
 BluetoothOppManager::ReceivingFileConfirmation(const nsString& aAddress,
                                                const nsString& aFileName,
                                                uint32_t aFileLength,
     return;
   }
 }
+
+void
+BluetoothOppManager::OnConnectSuccess()
+{
+}
+
+void
+BluetoothOppManager::OnConnectError()
+{
+}
+
+void
+BluetoothOppManager::OnDisconnect()
+{
+}

File dom/bluetooth/BluetoothOppManager.h

   bool mAbortFlag;
   int mPacketLeftLength;
   nsString mConnectedDeviceAddress;
+  bool mReceiving;
+  bool mPutFinal;
 
   nsCOMPtr<nsIDOMBlob> mBlob;
   nsCOMPtr<nsIThread> mReadFileThread;

File dom/bluetooth/ObexBase.cpp

 
   while (ptr - buf < totalLength) {
     ObexHeaderId headerId = (ObexHeaderId)*ptr++;
-    int headerLength = 0;
+    int contentLength = 0;
     uint8_t highByte, lowByte;
 
     // Defined in 2.1 OBEX Headers, IrOBEX 1.2
         // byte sequence, length prefixed with 2 byte unsigned integer.
         highByte = *ptr++;
         lowByte = *ptr++;
-        headerLength = ((int)highByte << 8) | lowByte;
+        contentLength = (((int)highByte << 8) | lowByte) - 3;
         break;
 
       case 0x02:
         // 1 byte quantity
-        headerLength = 1;
+        contentLength = 1;
         break;
 
       case 0x03:
         // 4 byte quantity
-        headerLength = 4;
+        contentLength = 4;
         break;
     }
 
-    // Content
-    uint8_t* headerContent = new uint8_t[headerLength];
-    memcpy(headerContent, ptr, headerLength);
-    retHandlerSet->AddHeader(new ObexHeader(headerId, headerLength, headerContent));
+    // FIXME: This case should be happened when we are receiving header 'Body'
+    // (file body). I will handle this in another bug.
+    if (contentLength + (ptr - buf) > totalLength) {
+      break;
+    }
 
-    ptr += headerLength;
+    uint8_t* content = new uint8_t[contentLength];
+    memcpy(content, ptr, contentLength);
+    retHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, content));
+
+    ptr += contentLength;
   }
 }
 

File dom/bluetooth/ObexBase.h

   {
     mHeaders.AppendElement(aHeader);
   }
+
+  void GetName(nsString& aRetName)
+  {
+    int length = mHeaders.Length();
+
+    for (int i = 0; i < length; ++i) {
+      if (mHeaders[i]->mId == ObexHeaderId::Name) {
+        uint8_t* ptr = mHeaders[i]->mData.get();
+        int nameLength = mHeaders[i]->mDataLength / 2;
+
+        for (int j = 0; j < nameLength; ++j) {
+          PRUnichar c = ((((uint32_t)ptr[j * 2]) << 8) | ptr[j * 2 + 1]);
+          aRetName += c;
+        }
+
+        break;
+      }
+    }
+  }
+
+  void GetContentType(nsString& aRetContentType)
+  {
+    int length = mHeaders.Length();
+
+    for (int i = 0; i < length; ++i) {
+      if (mHeaders[i]->mId == ObexHeaderId::Type) {
+        uint8_t* ptr = mHeaders[i]->mData.get();
+        aRetContentType.AssignASCII((const char*)ptr);
+        break;
+      }
+    }
+  }
+
+  // @return file length, 0 means file length is unknown.
+  void GetLength(uint32_t* aRetLength)
+  {
+    int length = mHeaders.Length();
+    *aRetLength = 0;
+
+    for (int i = 0; i < length; ++i) {
+      if (mHeaders[i]->mId == ObexHeaderId::Length) {
+        uint8_t* ptr = mHeaders[i]->mData.get();
+        *aRetLength = ((uint32_t)ptr[0] << 24) |
+                      ((uint32_t)ptr[1] << 16) |
+                      ((uint32_t)ptr[2] << 8) |
+                      ((uint32_t)ptr[3]);
+        break;
+      }
+    }
+  }
 };
 
 int AppendHeaderName(uint8_t* retBuf, const char* name, int length);