const char* Buffer::peekUntilCRLF(string& outLine) { outLine.clear(); const char* crlf = findCRLF(); if(crlf) { assert( crlf < beginWrite()); outLine.append(peek(),crlf); } return crlf; }
std::string getCRLFLine(std::string &string) { std::string ret; std::pair<unsigned long, unsigned long> pos; pos = findCRLF(string); if (pos.first != string.npos) { ret = string.substr(0, pos.first); string = string.substr(pos.second); return ret; } ret = string; string = ""; return ret; }
void HTTPHeaderClear( HTTPHeader_t *inHeader ) { char *nextPackagePtr; size_t chunckheaderLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr; if(inHeader->chunkedData && (uint32_t *)inHeader->chunkedDataBufferPtr){ //chunk data /* Possible to read the header of the next http package */ if(findCRLF( inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen, &nextPackagePtr ) ){ if( nextPackagePtr <= inHeader->chunkedDataBufferPtr + inHeader->extraDataLen ){ //We get some data belongs to next http package inHeader->len = inHeader->extraDataLen - (nextPackagePtr - inHeader->chunkedDataBufferPtr); if(inHeader->len > 512) inHeader->len = 0; else memcpy(inHeader->buf, nextPackagePtr, inHeader->len); } else inHeader->len = 0; } inHeader->extraDataLen = 0; free((uint32_t *)inHeader->chunkedDataBufferPtr); inHeader->chunkedDataBufferPtr = NULL; inHeader->extraDataPtr = NULL; inHeader->chunkedData = false; }else{ /* We get some data belongs to next http package, this only could happen two or more packages are received by SocketReadHTTPHeader */ if( inHeader->extraDataLen > inHeader->contentLength ){ inHeader->len = inHeader->extraDataLen - inHeader->contentLength; memcpy(inHeader->buf, inHeader->extraDataPtr + inHeader->contentLength, inHeader->len); } else inHeader->len = 0; inHeader->extraDataLen = 0; if((uint32_t *)inHeader->extraDataPtr) { free((uint32_t *)inHeader->extraDataPtr); inHeader->extraDataPtr = NULL; } if((uint32_t *)inHeader->otaDataPtr) { free((uint32_t *)inHeader->otaDataPtr); inHeader->otaDataPtr = NULL; } inHeader->dataEndedbyClose = false; } }
nsresult HttpServer::Connection::ConsumeInput(const char*& aBuffer, const char* aEnd) { nsresult rv; while (mState == eRequestLine || mState == eHeaders) { // Consume line-by-line // Check if buffer boundry ended up right between the CR and LF if (!mInputBuffer.IsEmpty() && mInputBuffer.Last() == '\r' && *aBuffer == '\n') { aBuffer++; rv = ConsumeLine(mInputBuffer.BeginReading(), mInputBuffer.Length() - 1); NS_ENSURE_SUCCESS(rv, rv); mInputBuffer.Truncate(); } // Look for a CRLF const char* pos = findCRLF(aBuffer, aEnd); if (!pos) { mInputBuffer.Append(aBuffer, aEnd - aBuffer); aBuffer = aEnd; return NS_OK; } if (!mInputBuffer.IsEmpty()) { mInputBuffer.Append(aBuffer, pos - aBuffer); aBuffer = pos + 2; rv = ConsumeLine(mInputBuffer.BeginReading(), mInputBuffer.Length() - 1); NS_ENSURE_SUCCESS(rv, rv); mInputBuffer.Truncate(); } else { rv = ConsumeLine(aBuffer, pos - aBuffer); NS_ENSURE_SUCCESS(rv, rv); aBuffer = pos + 2; } } if (mState == eBody) { uint32_t size = std::min(mRemainingBodySize, static_cast<uint32_t>(aEnd - aBuffer)); uint32_t written = size; if (mCurrentRequestBody) { rv = mCurrentRequestBody->Write(aBuffer, size, &written); // Since we've given the pipe unlimited size, we should never // end up needing to block. MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK); if (NS_FAILED(rv)) { written = size; mCurrentRequestBody = nullptr; } } aBuffer += written; mRemainingBodySize -= written; if (!mRemainingBodySize) { mCurrentRequestBody->Close(); mCurrentRequestBody = nullptr; mState = eRequestLine; } } return NS_OK; }
OSStatus SocketReadHTTPBody( int inSock, HTTPHeader_t *inHeader ) { OSStatus err = kParamErr; ssize_t readResult; int selectResult; fd_set readSet; const char * value; size_t valueSize; size_t lastChunkLen, chunckheaderLen; char *nextPackagePtr; #ifdef MICO_FLASH_FOR_UPDATE bool writeToFlash = false; #endif require( inHeader, exit ); err = kNotReadableErr; FD_ZERO( &readSet ); FD_SET( inSock, &readSet ); /* Chunked data, return after receive one chunk */ if( inHeader->chunkedData == true ){ /* Move next chunk to chunked data buffer header point */ lastChunkLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr + inHeader->contentLength; if(inHeader->contentLength) lastChunkLen+=2; //Last chunck data has a CRLF tail memmove( inHeader->chunkedDataBufferPtr, inHeader->chunkedDataBufferPtr + lastChunkLen, inHeader->chunkedDataBufferLen - lastChunkLen ); inHeader->extraDataLen -= lastChunkLen; while ( findChunkedDataLength( inHeader->chunkedDataBufferPtr, inHeader->extraDataLen, &inHeader->extraDataPtr ,"%llu", &inHeader->contentLength ) == false){ require_action(inHeader->extraDataLen < inHeader->chunkedDataBufferLen, exit, err=kMalformedErr ); selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require( selectResult >= 1, exit ); readResult = read( inSock, inHeader->extraDataPtr, (size_t)( inHeader->chunkedDataBufferLen - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } chunckheaderLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr; if(inHeader->contentLength == 0){ //This is the last chunk while( findCRLF( inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen, &nextPackagePtr ) == false){ //find CRLF selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require( selectResult >= 1, exit ); readResult = read( inSock, (uint8_t *)( inHeader->extraDataPtr + inHeader->extraDataLen - chunckheaderLen ), 256 - inHeader->extraDataLen ); //Assume chunk trailer length is less than 256 (256 is the min chunk buffer, maybe dangerous if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } err = kNoErr; goto exit; } else{ /* Extend chunked data buffer */ if( inHeader->chunkedDataBufferLen < inHeader->contentLength + chunckheaderLen + 2){ inHeader->chunkedDataBufferLen = inHeader->contentLength + chunckheaderLen + 256; inHeader->chunkedDataBufferPtr = realloc(inHeader->chunkedDataBufferPtr, inHeader->chunkedDataBufferLen); require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); } /* Read chunked data */ while ( inHeader->extraDataLen < inHeader->contentLength + chunckheaderLen + 2 ){ selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require( selectResult >= 1, exit ); readResult = read( inSock, (uint8_t *)( inHeader->extraDataPtr + inHeader->extraDataLen - chunckheaderLen), ( inHeader->contentLength - (inHeader->extraDataLen - chunckheaderLen) + 2 )); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } if( *(inHeader->extraDataPtr + inHeader->contentLength) != '\r' || *(inHeader->extraDataPtr + inHeader->contentLength +1 ) != '\n'){ err = kMalformedErr; goto exit; } } } /* We has extra data but total length is not clear, store them to 1500 bytes buffer return when connection is disconnected by remote server */ if( inHeader->dataEndedbyClose == true){ if(inHeader->contentLength == 0) { //First read body, return using data received by SocketReadHTTPHeader inHeader->contentLength = inHeader->extraDataLen; }else{ selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require( selectResult >= 1, exit ); readResult = read( inSock, (uint8_t*)( inHeader->extraDataPtr ), 1500 ); if( readResult > 0 ) inHeader->contentLength = readResult; else { err = kConnectionErr; goto exit; } } err = kNoErr; goto exit; } /* We has extra data and we has a predefined buffer to store the total extra data return when all data has received*/ while ( inHeader->extraDataLen < inHeader->contentLength ) { selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require( selectResult >= 1, exit ); err = HTTPGetHeaderField( inHeader->buf, inHeader->len, "Content-Type", NULL, NULL, &value, &valueSize, NULL ); require_noerr(err, exit); if( strnicmpx( value, valueSize, kMIMEType_MXCHIP_OTA ) == 0 ){ #ifdef MICO_FLASH_FOR_UPDATE writeToFlash = true; inHeader->otaDataPtr = calloc(OTA_Data_Length_per_read, sizeof(uint8_t)); require_action(inHeader->otaDataPtr, exit, err = kNoMemoryErr); if((inHeader->contentLength - inHeader->extraDataLen)<OTA_Data_Length_per_read){ readResult = read( inSock, (uint8_t*)( inHeader->otaDataPtr ), ( inHeader->contentLength - inHeader->extraDataLen ) ); }else{ readResult = read( inSock, (uint8_t*)( inHeader->otaDataPtr ), OTA_Data_Length_per_read); } if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } err = MicoFlashWrite(MICO_FLASH_FOR_UPDATE, &flashStorageAddress, (uint8_t *)inHeader->otaDataPtr, readResult); require_noerr(err, exit); free(inHeader->otaDataPtr); inHeader->otaDataPtr = 0; #else http_utils_log("OTA flash memory is not existed, !"); err = kUnsupportedErr; #endif }else{ readResult = read( inSock, (uint8_t*)( inHeader->extraDataPtr + inHeader->extraDataLen ), ( inHeader->contentLength - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } } err = kNoErr; exit: if(err != kNoErr) inHeader->len = 0; if(inHeader->otaDataPtr) { free(inHeader->otaDataPtr); inHeader->otaDataPtr = 0; } #ifdef MICO_FLASH_FOR_UPDATE if(writeToFlash == true) MicoFlashFinalize(MICO_FLASH_FOR_UPDATE); #endif return err; }
OSStatus SocketReadHTTPBody( int inSock, HTTPHeader_t *inHeader ) { OSStatus err = kParamErr; ssize_t readResult; int selectResult; fd_set readSet; size_t lastChunkLen, chunckheaderLen; char *nextPackagePtr; struct timeval_t t; size_t readLength; uint32_t pos = 0; t.tv_sec = 5; t.tv_usec = 0; require( inHeader, exit ); err = kNotReadableErr; FD_ZERO( &readSet ); FD_SET( inSock, &readSet ); /* Chunked data without content length */ if( inHeader->chunkedData == true ) { do { /* Find Chunk data length */ while ( findChunkedDataLength( inHeader->chunkedDataBufferPtr, inHeader->extraDataLen, &inHeader->extraDataPtr ,"%llu", &inHeader->contentLength ) == false) { require_action(inHeader->extraDataLen < inHeader->chunkedDataBufferLen, exit, err=kMalformedErr ); selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = read( inSock, inHeader->chunkedDataBufferPtr + inHeader->extraDataLen, (size_t)( inHeader->chunkedDataBufferLen - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } chunckheaderLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr; /* Check the last chunk */ if(inHeader->contentLength == 0) { while( findCRLF( inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen, &nextPackagePtr ) == false) { //find CRLF selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = read( inSock, (uint8_t *)( inHeader->extraDataPtr + inHeader->extraDataLen - chunckheaderLen ), 256 - inHeader->extraDataLen ); //Assume chunk trailer length is less than 256 (256 is the min chunk buffer, maybe dangerous if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } (inHeader->onReceivedDataCallback)(inHeader, inHeader->extraDataLen - readResult, (uint8_t *)inHeader->extraDataPtr, readResult, inHeader->userContext); } err = kNoErr; goto exit; } else { // Read chunk data /* Chunk package already exist, callback, move to buffer's head */ if( inHeader->extraDataLen >= inHeader->contentLength + chunckheaderLen + 2 ) { require_action( *(inHeader->extraDataPtr + inHeader->contentLength ) == '\r' && *(inHeader->extraDataPtr + inHeader->contentLength + 1 ) == '\n', exit, err = kMalformedErr); (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, inHeader->contentLength, inHeader->userContext); pos+=inHeader->contentLength; /* Move next chunk to chunked data buffer header point */ lastChunkLen = inHeader->extraDataPtr - inHeader->chunkedDataBufferPtr + inHeader->contentLength; if(inHeader->contentLength) lastChunkLen += 2; //Last chunck data has a CRLF tail memmove( inHeader->chunkedDataBufferPtr, inHeader->chunkedDataBufferPtr + lastChunkLen, inHeader->chunkedDataBufferLen - lastChunkLen ); inHeader->extraDataLen -= lastChunkLen; } /* Chunck exist without the last LF, generate callback abd recv LF */ /* Callback , read LF */ else if(inHeader->extraDataLen == inHeader->contentLength + chunckheaderLen +1) { //recv CR require_action( *(inHeader->chunkedDataBufferPtr + inHeader->extraDataLen - 1) == '\r' , exit, err = kMalformedErr); (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen-1, inHeader->userContext); pos+=inHeader->extraDataLen - chunckheaderLen-1; selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = read( inSock, (uint8_t *)inHeader->extraDataPtr, 1); if( readResult > 0 ) {} else { err = kConnectionErr; goto exit; } require_action( *(inHeader->extraDataPtr) == '\n', exit, err = kMalformedErr); inHeader->extraDataLen = 0; } else { /* Callback , read , callback , read CRLF */ (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, inHeader->extraDataLen - chunckheaderLen, inHeader->userContext); pos += inHeader->extraDataLen - chunckheaderLen; while ( inHeader->extraDataLen < inHeader->contentLength + chunckheaderLen ) { selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); if( inHeader->contentLength - (inHeader->extraDataLen - chunckheaderLen) > inHeader->chunkedDataBufferLen - chunckheaderLen) //Data needed is greater than valid buffer size readLength = inHeader->chunkedDataBufferLen - chunckheaderLen; else //Data needed is less than valid buffer size readLength = inHeader->contentLength - (inHeader->extraDataLen - chunckheaderLen) ; readResult = read( inSock, (uint8_t *)inHeader->extraDataPtr, readLength); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } (inHeader->onReceivedDataCallback)(inHeader, pos, (uint8_t *)inHeader->extraDataPtr, readResult, inHeader->userContext); pos += readResult; } selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); readResult = read( inSock, (uint8_t *)inHeader->extraDataPtr, 2); if( readResult > 0 ) {} else { err = kConnectionErr; goto exit; } require_action( *(inHeader->extraDataPtr) == '\r' && *(inHeader->extraDataPtr+1 ) == '\n', exit, err = kMalformedErr); inHeader->extraDataLen = 0; } } } while(inHeader->contentLength != 0); } /* We has extra data but total length is not clear, store them to 1500 bytes buffer return when connection is disconnected by remote server */ // if( inHeader->dataEndedbyClose == true){ // if(inHeader->contentLength == 0) { //First read body, return using data received by SocketReadHTTPHeader // inHeader->contentLength = inHeader->extraDataLen; // }else{ // selectResult = select( inSock + 1, &readSet, NULL, NULL, NULL ); // require_action( selectResult >= 1, exit, err = kNotReadableErr ); // readResult = read( inSock, // (uint8_t*)( inHeader->extraDataPtr ), // 1500 ); // if( readResult > 0 ) inHeader->contentLength = readResult; // else { err = kConnectionErr; goto exit; } // } // err = kNoErr; // goto exit; // } while ( inHeader->extraDataLen < inHeader->contentLength ) { selectResult = select( inSock + 1, &readSet, NULL, NULL, &t ); require_action( selectResult >= 1, exit, err = kNotReadableErr ); if(inHeader->isCallbackSupported == true) { /* We has extra data, and we give these data to application by onReceivedDataCallback function */ readLength = inHeader->contentLength - inHeader->extraDataLen > READ_LENGTH? READ_LENGTH:inHeader->contentLength - inHeader->extraDataLen; readResult = read( inSock, (uint8_t*)( inHeader->extraDataPtr), readLength ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } (inHeader->onReceivedDataCallback)(inHeader, inHeader->extraDataLen - readResult, (uint8_t *)inHeader->extraDataPtr, readResult, inHeader->userContext); } else { /* We has extra data and we has a predefined buffer to store the total extra data return when all data has received*/ readResult = read( inSock, (uint8_t*)( inHeader->extraDataPtr + inHeader->extraDataLen ), ( inHeader->contentLength - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else { err = kConnectionErr; goto exit; } } } err = kNoErr; exit: if(err != kNoErr) inHeader->len = 0; return err; }