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

This commit is contained in:
Eric Chou 2012-10-17 14:48:52 +08:00
parent 6db58f3fe4
commit 2c2ebffe1b
4 changed files with 137 additions and 45 deletions

View File

@ -27,7 +27,7 @@ static mozilla::RefPtr<BluetoothOppManager> sInstance;
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;
@ -98,6 +98,8 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
, mAbortFlag(false)
, mReadFileThread(nullptr)
, mPacketLeftLength(0)
, mReceiving(false)
, mPutFinal(false)
{
// FIXME / Bug 800249:
// mConnectedDeviceAddress is Bluetooth address of connected device,
@ -222,7 +224,7 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
int receivedLength = aMessage->mSize;
if (mPacketLeftLength > 0) {
opCode = ObexRequestCode::Put;
opCode = mPutFinal ? ObexRequestCode::PutFinal : ObexRequestCode::Put;
packetLength = mPacketLeftLength;
} else {
opCode = aMessage->mData[0];
@ -254,18 +256,32 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
sFileName.AssignLiteral("Unknown");
}
rv = mBlob->GetSize(&sFileLength);
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");
return;
}
uint64_t fileLength;
rv = mBlob->GetSize(&fileLength);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get file size");
return;
}
// 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();
@ -286,6 +302,7 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
NS_WARNING("[OPP] Disconnect failed");
} else {
mConnected = false;
mReceiving = false;
mLastCommand = 0;
mBlob = nullptr;
mReadFileThread = nullptr;
@ -330,35 +347,53 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
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);
}
} else {
NS_ASSERTION(mPacketLeftLength < receivedLength,
NS_ASSERTION(mPacketLeftLength >= receivedLength,
"Invalid packet length");
mPacketLeftLength = packetLength - receivedLength;
} else {
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);
}
}
}
@ -668,21 +703,6 @@ BluetoothOppManager::UpdateProgress(const nsString& aDeviceAddress,
}
}
void
BluetoothOppManager::OnConnectSuccess()
{
}
void
BluetoothOppManager::OnConnectError()
{
}
void
BluetoothOppManager::OnDisconnect()
{
}
void
BluetoothOppManager::ReceivingFileConfirmation(const nsString& aAddress,
const nsString& aFileName,
@ -715,3 +735,18 @@ BluetoothOppManager::ReceivingFileConfirmation(const nsString& aAddress,
return;
}
}
void
BluetoothOppManager::OnConnectSuccess()
{
}
void
BluetoothOppManager::OnConnectError()
{
}
void
BluetoothOppManager::OnDisconnect()
{
}

View File

@ -96,6 +96,8 @@ private:
bool mAbortFlag;
int mPacketLeftLength;
nsString mConnectedDeviceAddress;
bool mReceiving;
bool mPutFinal;
nsCOMPtr<nsIDOMBlob> mBlob;
nsCOMPtr<nsIThread> mReadFileThread;

View File

@ -75,7 +75,7 @@ ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
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
@ -87,26 +87,31 @@ ParseHeaders(uint8_t* buf, int totalLength, ObexHeaderSet* retHandlerSet)
// 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;
}
}

View File

@ -139,6 +139,56 @@ public:
{
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);