OSStatus _FTCRespondInComingMessage(int fd, HTTPHeader_t* inHeader, mico_Context_t * const inContext) { OSStatus err = kUnknownErr; const char * value; size_t valueSize; easylink_log_trace(); switch(inHeader->statusCode){ case kStatusAccept: easylink_log("Easylink server accepted!"); err = kNoErr; goto exit; break; case kStatusOK: easylink_log("Easylink server respond status OK!"); err = HTTPGetHeaderField( inHeader->buf, inHeader->len, "Content-Type", NULL, NULL, &value, &valueSize, NULL ); require_noerr(err, exit); if( strnicmpx( value, valueSize, kMIMEType_JSON ) == 0 ){ easylink_log("Receive JSON config data!"); err = ConfigIncommingJsonMessage( inHeader->extraDataPtr, inContext); SocketClose(&fd); inContext->micoStatus.sys_state = eState_Software_Reset; require(inContext->micoStatus.sys_state_change_sem, exit); mico_rtos_set_semaphore(&inContext->micoStatus.sys_state_change_sem); }else if(strnicmpx( value, valueSize, kMIMEType_MXCHIP_OTA ) == 0){ easylink_log("Receive OTA data!"); mico_rtos_lock_mutex(&inContext->flashContentInRam_mutex); memset(&inContext->flashContentInRam.bootTable, 0, sizeof(boot_table_t)); inContext->flashContentInRam.bootTable.length = inHeader->contentLength; inContext->flashContentInRam.bootTable.start_address = UPDATE_START_ADDRESS; inContext->flashContentInRam.bootTable.type = 'A'; inContext->flashContentInRam.bootTable.upgrade_type = 'U'; inContext->flashContentInRam.micoSystemConfig.easyLinkEnable = false; MICOUpdateConfiguration(inContext); mico_rtos_unlock_mutex(&inContext->flashContentInRam_mutex); SocketClose(&fd); inContext->micoStatus.sys_state = eState_Software_Reset; require(inContext->micoStatus.sys_state_change_sem, exit); mico_rtos_set_semaphore(&inContext->micoStatus.sys_state_change_sem); }else{ return kUnsupportedDataErr; } err = kNoErr; goto exit; break; default: goto exit; } exit: return err; }
OSStatus HTTPHeaderMatchMethod( HTTPHeader_t *inHeader, const char *method ) { if( strnicmpx( inHeader->methodPtr, inHeader->methodLen, method ) == 0 ) return kNoErr; return kNotFoundErr; }
static OSStatus onReceivedData(struct _HTTPHeader_t * inHeader, uint32_t inPos, uint8_t * inData, size_t inLen, void * inUserContext ) { OSStatus err = kUnknownErr; const char * value; size_t valueSize; configContext_t *context = (configContext_t *)inUserContext; err = HTTPGetHeaderField( inHeader->buf, inHeader->len, "Content-Type", NULL, NULL, &value, &valueSize, NULL ); if(err == kNoErr && strnicmpx( value, valueSize, kMIMEType_MXCHIP_OTA ) == 0){ config_log("OTA data %d, %d to: %x", inPos, inLen, context->flashStorageAddress); #ifdef MICO_FLASH_FOR_UPDATE if(inPos == 0){ context->flashStorageAddress = UPDATE_START_ADDRESS; mico_rtos_lock_mutex(&Context->flashContentInRam_mutex); //We are write the Flash content, no other write is possiable context->isFlashLocked = true; err = MicoFlashInitialize( MICO_FLASH_FOR_UPDATE ); require_noerr(err, flashErrExit); err = MicoFlashErase(MICO_FLASH_FOR_UPDATE, UPDATE_START_ADDRESS, UPDATE_END_ADDRESS); require_noerr(err, flashErrExit); err = MicoFlashWrite(MICO_FLASH_FOR_UPDATE, &context->flashStorageAddress, (uint8_t *)inData, inLen); require_noerr(err, flashErrExit); }else{ err = MicoFlashWrite(MICO_FLASH_FOR_UPDATE, &context->flashStorageAddress, (uint8_t *)inData, inLen); require_noerr(err, flashErrExit); } #else config_log("OTA storage is not exist"); return kUnsupportedErr; #endif } else if(inHeader->chunkedData == true){ config_log("ChunkedData: %d, %d:", inPos, inLen); for(uint32_t i = 0; i<inLen; i++) printf("%c", inData[i]); printf("\r\n"); } else{ return kUnsupportedErr; } if(err!=kNoErr) config_log("onReceivedData"); return err; #ifdef MICO_FLASH_FOR_UPDATE flashErrExit: MicoFlashFinalize(MICO_FLASH_FOR_UPDATE); mico_rtos_unlock_mutex(&Context->flashContentInRam_mutex); return err; #endif }
int SocketReadHTTPHeader( int inSock, HTTPHeader_t *inHeader ) { int err =0; char * buf; char * dst; char * lim; char * end; size_t len; ssize_t n; const char * value; size_t valueSize; buf = inHeader->buf; dst = buf + inHeader->len; lim = buf + sizeof( inHeader->buf ); for( ;; ) { // If there's data from a previous read, move it to the front to search it first. len = inHeader->extraDataLen; if( len > 0 ) { require_action( len <= (size_t)( lim - dst ), exit, err = kParamErr ); memmove( dst, inHeader->extraDataPtr, len ); inHeader->extraDataLen = 0; } else { //do //{ n = read( inSock, dst, (size_t)( lim - dst ) ); // err = map_socket_value_errno( inSock, n >= 0, n ); //} while( err == EINTR ); if( n > 0 ) len = (size_t) n; else { err = kConnectionErr; goto exit; } //else goto exit; } dst += len; inHeader->len += len; if(findHeader( inHeader, &end )) break ; } inHeader->len = (size_t)( end - buf ); err = HTTPHeaderParse( inHeader ); require_noerr( err, exit ); inHeader->extraDataLen = (size_t)( dst - end ); if(inHeader->extraDataPtr) { free((uint8_t *)inHeader->extraDataPtr); inHeader->extraDataPtr = 0; } if(inHeader->otaDataPtr) { free((uint8_t *)inHeader->otaDataPtr); inHeader->otaDataPtr = 0; } err = HTTPGetHeaderField( inHeader->buf, inHeader->len, "Content-Type", NULL, NULL, &value, &valueSize, NULL ); if(err == kNoErr && strnicmpx( value, valueSize, kMIMEType_MXCHIP_OTA ) == 0){ http_utils_log("Receive OTA data!"); err = PlatformFlashInitialize(); require_noerr(err, exit); err = PlatformFlashWrite(&flashStorageAddress, (uint32_t *)end, inHeader->extraDataLen); require_noerr(err, exit); }else{ inHeader->extraDataPtr = calloc(inHeader->contentLength, sizeof(uint8_t)); require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); memcpy((uint8_t *)inHeader->extraDataPtr, end, inHeader->extraDataLen); err = kNoErr; } exit: return err; }
OSStatus HTTPHeaderParse( HTTPHeader_t *ioHeader ) { OSStatus err; const char * src; const char * end; const char * ptr; char c; const char * value; size_t valueSize; int x; require_action( ioHeader->len < sizeof( ioHeader->buf ), exit, err = kParamErr ); // Reset fields up-front to good defaults to simplify handling of unused fields later. ioHeader->methodPtr = ""; ioHeader->methodLen = 0; ioHeader->urlPtr = ""; ioHeader->urlLen = 0; memset( &ioHeader->url, 0, sizeof( ioHeader->url ) ); ioHeader->protocolPtr = ""; ioHeader->protocolLen = 0; ioHeader->statusCode = -1; ioHeader->reasonPhrasePtr = ""; ioHeader->reasonPhraseLen = 0; ioHeader->channelID = 0; ioHeader->contentLength = 0; ioHeader->persistent = false; // Check for a 4-byte interleaved binary data header (see RFC 2326 section 10.12). It has the following format: // // '$' <1:channelID> <2:dataSize in network byte order> ... followed by dataSize bytes of binary data. src = ioHeader->buf; if( ( ioHeader->len == 4 ) && ( src[ 0 ] == '$' ) ) { const uint8_t * usrc; usrc = (const uint8_t *) src; ioHeader->channelID = usrc[ 1 ]; ioHeader->contentLength = ( usrc[ 2 ] << 8 ) | usrc[ 3 ]; ioHeader->methodPtr = src; ioHeader->methodLen = 1; err = kNoErr; goto exit; } // Parse the start line. This will also determine if it's a request or response. // Requests are in the format <method> <url> <protocol>/<majorVersion>.<minorVersion>, for example: // // GET /abc/xyz.html HTTP/1.1 // GET http://www.host.com/abc/xyz.html HTTP/1.1 // GET http://user:[email protected]/abc/xyz.html HTTP/1.1 // // Responses are in the format <protocol>/<majorVersion>.<minorVersion> <statusCode> <reasonPhrase>, for example: // // HTTP/1.1 404 Not Found ptr = src; end = src + ioHeader->len; for( c = 0; ( ptr < end ) && ( ( c = *ptr ) != ' ' ) && ( c != '/' ); ++ptr ) {} require_action( ptr < end, exit, err = kMalformedErr ); if( c == ' ' ) // Requests have a space after the method. Responses have '/' after the protocol. { ioHeader->methodPtr = src; ioHeader->methodLen = (size_t)( ptr - src ); ++ptr; // Parse the URL. ioHeader->urlPtr = ptr; while( ( ptr < end ) && ( *ptr != ' ' ) ) ++ptr; ioHeader->urlLen = (size_t)( ptr - ioHeader->urlPtr ); require_action( ptr < end, exit, err = kMalformedErr ); ++ptr; err = URLParseComponents( ioHeader->urlPtr, ioHeader->urlPtr + ioHeader->urlLen, &ioHeader->url, NULL ); require_noerr( err, exit ); // Parse the protocol and version. ioHeader->protocolPtr = ptr; while( ( ptr < end ) && ( ( c = *ptr ) != '\r' ) && ( c != '\n' ) ) ++ptr; ioHeader->protocolLen = (size_t)( ptr - ioHeader->protocolPtr ); require_action( ptr < end, exit, err = kMalformedErr ); ++ptr; } else // Response { // Parse the protocol version. ioHeader->protocolPtr = src; for( ++ptr; ( ptr < end ) && ( *ptr != ' ' ); ++ptr ) {} ioHeader->protocolLen = (size_t)( ptr - ioHeader->protocolPtr ); require_action( ptr < end, exit, err = kMalformedErr ); ++ptr; // Parse the status code. x = 0; for( c = 0; ( ptr < end ) && ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr ) x = ( x * 10 ) + ( c - '0' ); ioHeader->statusCode = x; if( c == ' ' ) ++ptr; // Parse the reason phrase. ioHeader->reasonPhrasePtr = ptr; while( ( ptr < end ) && ( ( c = *ptr ) != '\r' ) && ( c != '\n' ) ) ++ptr; ioHeader->reasonPhraseLen = (size_t)( ptr - ioHeader->reasonPhrasePtr ); require_action( ptr < end, exit, err = kMalformedErr ); ++ptr; } // There should at least be a blank line after the start line so make sure there's more data. require_action( ptr < end, exit, err = kMalformedErr ); // Determine persistence. Note: HTTP 1.0 defaults to non-persistent if a Connection header field is not present. err = HTTPGetHeaderField( ioHeader->buf, ioHeader->len, "Connection", NULL, NULL, &value, &valueSize, NULL ); if( err ) ioHeader->persistent = (Boolean)( strnicmpx( ioHeader->protocolPtr, ioHeader->protocolLen, "HTTP/1.0" ) != 0 ); else ioHeader->persistent = (Boolean)( strnicmpx( value, valueSize, "close" ) != 0 ); // Content-Length is such a common field that we get it here during general parsing. HTTPScanFHeaderValue( ioHeader->buf, ioHeader->len, "Content-Length", "%llu", &ioHeader->contentLength ); err = kNoErr; exit: return err; }
OSStatus SocketReadHTTPBody( int inSock, HTTPHeader_t *inHeader ) { OSStatus err = kParamErr; ssize_t readResult; int selectResult; fd_set readSet; const char * value; size_t valueSize; require( inHeader, exit ); err = kNotReadableErr; FD_ZERO( &readSet ); FD_SET( inSock, &readSet ); 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 ){ 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; } //else goto exit; err = PlatformFlashWrite(&flashStorageAddress, (uint32_t *)inHeader->otaDataPtr, readResult); require_noerr(err, exit); free(inHeader->otaDataPtr); inHeader->otaDataPtr = 0; }else{ readResult = read( inSock, (uint8_t*)( inHeader->extraDataPtr + inHeader->extraDataLen ), ( inHeader->contentLength - inHeader->extraDataLen ) ); if( readResult > 0 ) inHeader->extraDataLen += readResult; else if( readResult == 0 ) { err = kConnectionErr; goto exit; } else goto exit; } } err = kNoErr; exit: if(inHeader->otaDataPtr) { free(inHeader->otaDataPtr); inHeader->otaDataPtr = 0; } return err; }
int SocketReadHTTPHeader( int inSock, HTTPHeader_t *inHeader ) { int err =0; char * buf; char * dst; char * lim; char * end; size_t len; ssize_t n; const char * value; size_t valueSize; buf = inHeader->buf; dst = buf + inHeader->len; lim = buf + sizeof( inHeader->buf ); for( ;; ) { if(findHeader( inHeader, &end )) break ; n = read( inSock, dst, (size_t)( lim - dst ) ); if( n > 0 ) len = (size_t) n; else { err = kConnectionErr; goto exit; } dst += len; inHeader->len += len; } inHeader->len = (size_t)( end - buf ); err = HTTPHeaderParse( inHeader ); require_noerr( err, exit ); inHeader->extraDataLen = (size_t)( dst - end ); if(inHeader->extraDataPtr) { free((uint8_t *)inHeader->extraDataPtr); inHeader->extraDataPtr = 0; } if(inHeader->otaDataPtr) { free((uint8_t *)inHeader->otaDataPtr); inHeader->otaDataPtr = 0; } /* For MXCHIP OTA function, store extra data to OTA data temporary */ err = HTTPGetHeaderField( inHeader->buf, inHeader->len, "Content-Type", NULL, NULL, &value, &valueSize, NULL ); if(err == kNoErr && strnicmpx( value, valueSize, kMIMEType_MXCHIP_OTA ) == 0){ #ifdef MICO_FLASH_FOR_UPDATE http_utils_log("Receive OTA data!"); err = MicoFlashInitialize( MICO_FLASH_FOR_UPDATE ); require_noerr(err, exit); err = MicoFlashWrite(MICO_FLASH_FOR_UPDATE, &flashStorageAddress, (uint8_t *)end, inHeader->extraDataLen); require_noerr(err, exit); #else http_utils_log("OTA flash memory is not existed!"); err = kUnsupportedErr; #endif goto exit; } /* For chunked extra data without content length */ if(inHeader->chunkedData == true){ inHeader->chunkedDataBufferLen = (inHeader->extraDataLen > 256)? inHeader->extraDataLen:256; inHeader->chunkedDataBufferPtr = calloc(inHeader->chunkedDataBufferLen, sizeof(uint8_t)); //Make extra data buffer larger than chunk length require_action(inHeader->chunkedDataBufferPtr, exit, err = kNoMemoryErr); memcpy((uint8_t *)inHeader->chunkedDataBufferPtr, end, inHeader->extraDataLen); inHeader->extraDataPtr = inHeader->chunkedDataBufferPtr; return kNoErr; } /* Extra data with content length */ if (inHeader->contentLength != 0){ //Content length >0, create a memory buffer (Content length) and store extra data size_t copyDataLen = (inHeader->contentLength >= inHeader->extraDataLen)? inHeader->contentLength:inHeader->extraDataLen; inHeader->extraDataPtr = calloc(copyDataLen , sizeof(uint8_t)); require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); memcpy((uint8_t *)inHeader->extraDataPtr, end, copyDataLen); err = kNoErr; } /* Extra data without content length, data is ended by conntection close */ else if(inHeader->extraDataLen != 0){ //Content length =0, but extra data length >0, create a memory buffer (1500)and store extra data inHeader->dataEndedbyClose = true; inHeader->extraDataPtr = calloc(1500, sizeof(uint8_t)); require_action(inHeader->extraDataPtr, exit, err = kNoMemoryErr); memcpy((uint8_t *)inHeader->extraDataPtr, end, inHeader->extraDataLen); err = kNoErr; } else return kNoErr; exit: return err; }
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; }