示例#1
0
文件: HTTPUtils.c 项目: Eric2015/MICO
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;
}
示例#2
0
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;
}