upnp/upnpstack/dlnawebserver/src/upnprangeheaderparser.cpp
changeset 0 f5a58ecadc66
equal deleted inserted replaced
-1:000000000000 0:f5a58ecadc66
       
     1 /** @file
       
     2 * Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies  this distribution, and is available 
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Declares CUpnpRangeHeaderParser class.
       
    15 *
       
    16 */
       
    17 
       
    18 #include "upnphttpservertransactioncreator.h"
       
    19 #include "upnphttpmessage.h"
       
    20 #include "upnprangeheaderparser.h"
       
    21 #include "upnphttpservertransaction.h"
       
    22 #include "upnphttpservertransaction.h"
       
    23 
       
    24 // ---------------------------------------------------------------------------
       
    25 // CUpnpRangeHeaderParser::NewL
       
    26 // Factory method.
       
    27 // ---------------------------------------------------------------------------
       
    28 //
       
    29 CUpnpRangeHeaderParser* CUpnpRangeHeaderParser::NewL(
       
    30     CUpnpHttpServerTransaction &aTransaction, TInt& aStartPos, TInt& aEndPos )
       
    31     {
       
    32     CUpnpRangeHeaderParser* self = 
       
    33         CUpnpRangeHeaderParser::NewLC( aTransaction, aStartPos, aEndPos );
       
    34     CleanupStack::Pop( self );
       
    35     return self;
       
    36     }
       
    37 
       
    38 // ---------------------------------------------------------------------------
       
    39 // CUpnpRangeHeaderParser::NewLC
       
    40 // Factory method.
       
    41 // ---------------------------------------------------------------------------
       
    42 //
       
    43 CUpnpRangeHeaderParser* CUpnpRangeHeaderParser::NewLC(
       
    44     CUpnpHttpServerTransaction &aTransaction, TInt& aStartPos, TInt& aEndPos )
       
    45     {
       
    46     CUpnpRangeHeaderParser* self = 
       
    47         new( ELeave ) CUpnpRangeHeaderParser( aTransaction, aStartPos, aEndPos );
       
    48     CleanupStack::PushL( self );
       
    49     self->ConstructL();
       
    50     return self;
       
    51     }
       
    52 
       
    53 // ---------------------------------------------------------------------------
       
    54 // CUpnpRangeHeaderParser::CUpnpRangeHeaderParser
       
    55 // C++ constructor.
       
    56 // ---------------------------------------------------------------------------
       
    57 //
       
    58 CUpnpRangeHeaderParser::CUpnpRangeHeaderParser(
       
    59     CUpnpHttpServerTransaction &aTransaction, TInt& aStartPos, TInt& aEndPos )
       
    60     :iTransaction(aTransaction), iStartPos( aStartPos ), iEndPos( aEndPos )
       
    61     {
       
    62     }
       
    63 
       
    64 // ---------------------------------------------------------------------------
       
    65 // CUpnpRangeHeaderParser::ConstructL
       
    66 // Two-phased constructor
       
    67 // ---------------------------------------------------------------------------
       
    68 //    
       
    69 void CUpnpRangeHeaderParser::ConstructL()
       
    70     {
       
    71     }
       
    72 
       
    73 // ---------------------------------------------------------------------------
       
    74 // CUpnpRangeHeaderParser::~CUpnpRangeHeaderParser
       
    75 // Destructor.
       
    76 // ---------------------------------------------------------------------------
       
    77 //
       
    78 CUpnpRangeHeaderParser::~CUpnpRangeHeaderParser()
       
    79     {
       
    80     }
       
    81 
       
    82 // ---------------------------------------------------------------------------
       
    83 // CUpnpRangeHeaderParser::ParseRangeL
       
    84 // Function returns parsinfg status.
       
    85 // ---------------------------------------------------------------------------
       
    86 //
       
    87 TInt CUpnpRangeHeaderParser::ParseRangeL( CUpnpHttpMessage* aMsg, TInt aFileSize )
       
    88     {
       
    89     //checks if Range header exist and is correct
       
    90     TInt rangeStatus = CheckRangeHeaderSyntax( aMsg );
       
    91     if ( rangeStatus != EHttpPartialContent )
       
    92         {
       
    93         return rangeStatus;
       
    94         }
       
    95     
       
    96     //checks Range values    
       
    97     rangeStatus = CheckRangeValues( aFileSize );
       
    98     if ( rangeStatus < 0 )
       
    99     {
       
   100         return rangeStatus;
       
   101     }
       
   102     
       
   103     // creates response if Range header occurs
       
   104     if ( rangeStatus==EHttpPartialContent )
       
   105         {
       
   106         //HTTP/1.1 206 Partial Content
       
   107         CreatePartialContentResponseL( aFileSize, rangeStatus ); 
       
   108         }
       
   109     else if ( rangeStatus==EHttpNoContent )
       
   110         {
       
   111         //HTTP/1.1 204 No Content
       
   112         CreateNoContentResponseL( aFileSize, rangeStatus ); //HTTP/1.1 204 No Content
       
   113         }
       
   114 
       
   115     return rangeStatus;
       
   116     }
       
   117 
       
   118 // ---------------------------------------------------------------------------
       
   119 // CUpnpRangeHeaderParser::CheckRangeHeaderSyntax
       
   120 // Checks range header syntax.
       
   121 // ---------------------------------------------------------------------------
       
   122 //
       
   123 TInt CUpnpRangeHeaderParser::CheckRangeHeaderSyntax( CUpnpHttpMessage* aMsg )
       
   124     {
       
   125     // checks if range header exist
       
   126     TBool rangeHeaderExist = EFalse;
       
   127     aMsg->IsHeader( (TDesC8&) UpnpHTTP::KHdrRange, rangeHeaderExist );
       
   128     if( !rangeHeaderExist )
       
   129         {
       
   130         return EHttpOk; //Range header doesn't exist
       
   131         }
       
   132     
       
   133     // checks if Range value exist    
       
   134     if( !(aMsg->GetHeaderValue( (TDesC8&) UpnpHTTP::KHdrRange ).Length() > 0 ) )
       
   135         {
       
   136         return -EHttpBadRequest; //Range value doesn't exist
       
   137         }
       
   138     
       
   139     // checks syntax of Range header
       
   140     if( !CUpnpRangeHeaderParser::ParseRangeHeader( aMsg->GetHeaderValue(
       
   141         (TDesC8&) UpnpHTTP::KHdrRange ), iStartPos, iEndPos ) )
       
   142         {
       
   143         return -EHttpBadRequest; //error in syntax
       
   144         }            
       
   145      
       
   146      return EHttpPartialContent; //Range header is proper
       
   147     }
       
   148     
       
   149 // ---------------------------------------------------------------------------
       
   150 // CUpnpRangeHeaderParser::CheckRangeValue
       
   151 // Checks range values.
       
   152 // ---------------------------------------------------------------------------
       
   153 //    
       
   154 TInt CUpnpRangeHeaderParser::CheckRangeValues( TInt aFileSize )
       
   155     { 
       
   156     
       
   157     // empty file
       
   158     if ( aFileSize == 0 )
       
   159         {
       
   160         if ( ( iStartPos == 0 ) || ( iStartPos == iEndPos ) 
       
   161              || ( iStartPos > 0 && iEndPos == KErrNotFound ) 
       
   162              || ( iStartPos == KErrNotFound && iEndPos > 0 ) )
       
   163             {
       
   164             return EHttpNoContent;
       
   165             }
       
   166         else
       
   167             {
       
   168             return -EHttpBadRequest;
       
   169             }
       
   170         }
       
   171      else
       
   172         {
       
   173         // final bytes request
       
   174         // e.g. Range: bytes=-70 
       
   175         if ( ( iStartPos == KErrNotFound && iEndPos > 0 && iEndPos <= aFileSize ) )
       
   176             {
       
   177             iStartPos = aFileSize - iEndPos; 
       
   178             iEndPos = aFileSize-1;
       
   179             return EHttpPartialContent;
       
   180             }
       
   181         // bad posision dependece
       
   182         // e.g. Range: bytes=70-20 
       
   183         // e.g requested final bytes bigger than file size
       
   184         else if ( ( iStartPos == KErrNotFound && iEndPos == 0 ) 
       
   185                   || ( iStartPos == KErrNotFound && iEndPos > 0  && iEndPos > aFileSize )
       
   186                   || ( iStartPos > iEndPos && iEndPos != KErrNotFound ) )   
       
   187             {
       
   188             return -EHttpBadRequest;
       
   189             }
       
   190         // start position larger than file size     
       
   191         else if ( ( iStartPos >= aFileSize 
       
   192                   && ( iStartPos <= iEndPos || iEndPos == KErrNotFound ) ) )
       
   193             {
       
   194             return -EHttpRequestedRangeNotSatisfiable;
       
   195             }
       
   196         }
       
   197         
       
   198         // updates end position if it is out of file size
       
   199         if ( iEndPos == KErrNotFound || iEndPos > aFileSize-1 )
       
   200             {
       
   201             iEndPos = aFileSize-1;
       
   202             }
       
   203             
       
   204         return EHttpPartialContent; 
       
   205     }
       
   206      
       
   207 // ---------------------------------------------------------------------------
       
   208 // CUpnpRangeHeaderParser::AppendContentLengthToResponseL
       
   209 // Appends Content-Length header to response.
       
   210 // ---------------------------------------------------------------------------
       
   211 //            
       
   212 void CUpnpRangeHeaderParser::AppendContentLengthToResponseL( 
       
   213     TInt aFileSize, TInt rangeStatus )
       
   214     {
       
   215     TInt size( 0 );
       
   216     if ( rangeStatus == EHttpPartialContent )
       
   217         {
       
   218         size = iEndPos - iStartPos + 1;    
       
   219         }
       
   220     else
       
   221         {
       
   222         size = aFileSize;
       
   223         }
       
   224     iSizeBuffer.Num( size ); 
       
   225     iTransaction.AddResponseHeaderL( UpnpHTTP::KHdrContentLength(), iSizeBuffer );
       
   226     }
       
   227        
       
   228 // ---------------------------------------------------------------------------
       
   229 // CUpnpRangeHeaderParser::AppendBytesToResponseL
       
   230 // Appends Bytes header to response.
       
   231 // ---------------------------------------------------------------------------
       
   232 //         
       
   233 void CUpnpRangeHeaderParser::AppendBytesToResponseL( TInt aFileSize )
       
   234     {
       
   235     HBufC8* buffer = HBufC8::NewLC( sizeof(UpnpHTTP::KBytes) +
       
   236                          KIntegerOccurance*KMaxIntegerLength + KSlashSpaceAndMinusSize );
       
   237     
       
   238     //bytes
       
   239     buffer->Des().Append( UpnpHTTP::KBytes() );
       
   240     buffer->Des().Append( UpnpString::KSpace );
       
   241     //x
       
   242     iSizeBuffer.Num( iStartPos );
       
   243     buffer->Des().Append( iSizeBuffer ); 
       
   244     buffer->Des().Append( UpnpString::KMinus );
       
   245     //y
       
   246     iSizeBuffer.Num( iEndPos ); 
       
   247     buffer->Des().Append( iSizeBuffer ); 
       
   248     buffer->Des().Append( UpnpString::KSlash );
       
   249     //total
       
   250     iSizeBuffer.Num( aFileSize );
       
   251     buffer->Des().Append( iSizeBuffer );
       
   252 
       
   253     iTransaction.AddResponseHeaderL( UpnpHTTP::KHdrContentRange(), *buffer );
       
   254 
       
   255     CleanupStack::PopAndDestroy( buffer );
       
   256     }
       
   257 
       
   258 // ---------------------------------------------------------------------------
       
   259 // CUpnpRangeHeaderParser::CreatePartialContentResponseL
       
   260 // Creates response 206 Partial Content.
       
   261 // ---------------------------------------------------------------------------
       
   262 //     
       
   263 void CUpnpRangeHeaderParser::CreatePartialContentResponseL( 
       
   264     TInt aFileSize, TInt aHttpCode )
       
   265     {
       
   266     // append Partial Content To Response - "206 Partial Content"    
       
   267     iTransaction.AddResponseHeaderL( KNullDesC8(), UpnpHTTP::KHTTPPartialContent() );
       
   268     AppendContentLengthToResponseL( aFileSize, aHttpCode );
       
   269     
       
   270     AppendBytesToResponseL( aFileSize );
       
   271     }
       
   272 
       
   273 // ---------------------------------------------------------------------------
       
   274 // CUpnpRangeHeaderParser::CreateNoContentResponseL
       
   275 // Creates response for 204 No Content.
       
   276 // ---------------------------------------------------------------------------
       
   277 //     
       
   278 void CUpnpRangeHeaderParser::CreateNoContentResponseL( 
       
   279     TInt aFileSize, TInt aHttpCode )
       
   280     {
       
   281     // append No Content To Response - "204 No Content"
       
   282     iTransaction.AddResponseHeaderL( KNullDesC8(), UpnpHTTP::KHTTPNoContent() );    
       
   283     
       
   284     AppendContentLengthToResponseL( aFileSize, aHttpCode );
       
   285 
       
   286     // Append No Content Fields To Response;
       
   287     iTransaction.AddResponseHeaderL( UpnpHTTP::KHdrPragma(), UpnpHTTP::KNoCache() );
       
   288     iTransaction.AddResponseHeaderL( UpnpHTTP::KHdrCacheControl(), UpnpHTTP::KNoCache() );
       
   289 
       
   290     
       
   291     }
       
   292 
       
   293 // -----------------------------------------------------------------------------
       
   294 //  CUpnpHttpSession::ParseRangeHeader
       
   295 //  Parse range values
       
   296 // -----------------------------------------------------------------------------
       
   297 //    
       
   298 TBool CUpnpRangeHeaderParser::ParseRangeHeader( TDesC8& aRangeHeader, TInt& aStartPos,
       
   299                                                 TInt& aEndPos )
       
   300     {
       
   301     // Check header's syntax: "bytes=x-y" where y i optional
       
   302     TInt pos( KErrNotFound );
       
   303 
       
   304     // 1 string has to contain "="
       
   305     pos = aRangeHeader.FindC( UpnpString::KEqual() );
       
   306     if( pos == KErrNotFound ) 
       
   307         return EFalse;
       
   308 
       
   309     // 2 "bytes" has to be at the beginnig
       
   310     pos = aRangeHeader.FindC( UpnpHTTP::KBytes() );
       
   311     if( pos == KErrNotFound || pos != 0 ) 
       
   312         return EFalse;
       
   313 
       
   314     // 3 Sets position to after bytes
       
   315     pos = UpnpHTTP::KBytes().Length();
       
   316 
       
   317     // 4 If there any space or tab after "bytes" - move pos after it
       
   318     CUpnpRangeHeaderParser::MovePosition( aRangeHeader, pos );
       
   319 
       
   320     // 5 "=" - has to be at this position (after "bytes" + spaces or tabs)
       
   321     if( aRangeHeader[ pos ] != UpnpString::KEqual()[0] )
       
   322         return EFalse;
       
   323 
       
   324     // 6 Sets position to after "="
       
   325     pos++;
       
   326 
       
   327     // 7 If there any space or tab after "=" - move pos after it
       
   328     CUpnpRangeHeaderParser::MovePosition( aRangeHeader, pos );
       
   329     
       
   330     // 8 extract x-y. -1 stands for '=' length
       
   331     TPtrC8 byteRange = aRangeHeader.Right( aRangeHeader.Length() - pos );
       
   332 
       
   333     // 9 There can't be any comas because multi-range is not allowed
       
   334     if( byteRange.Find( UpnpString::KComa() ) != KErrNotFound ) 
       
   335         return EFalse;
       
   336 
       
   337     // 10 "-" delimiter must occure and it cant't be first char, because notation as follows: "-y"  is not allowed
       
   338     pos = byteRange.Find( UpnpString::KMinus() );
       
   339     if( pos == KErrNotFound ) 
       
   340         return EFalse;
       
   341     
       
   342     // 11 Checks if it is a final bytes request
       
   343     // e.g. Range: bytes= -20
       
   344     if( pos == 0 )
       
   345         {
       
   346         // If there any space or tab after "-" - move pos after it
       
   347         CUpnpRangeHeaderParser::MovePosition( byteRange.Right( byteRange.Length()-1 ), pos );
       
   348         // if pos equal 0 should be 1 to avoid "-" in getting number from string operation
       
   349         pos = pos == 0 ? 1 : pos;
       
   350         TLex8 endMinus( byteRange.Right( byteRange.Length() - pos  ) );
       
   351         endMinus.SkipSpace();
       
   352         TInt error = endMinus.Val( aEndPos );
       
   353         if ( !CUpnpRangeHeaderParser::HandleConversionException( endMinus, aEndPos, error ) )
       
   354             {
       
   355             return EFalse;
       
   356             }
       
   357             
       
   358         // We have to check if something else than space or tab leaves after conversion - unless for example 11a will be correct but it is not
       
   359         if ( CUpnpRangeHeaderParser::HasImproperChars( endMinus ) )
       
   360             return EFalse;
       
   361          
       
   362         aStartPos = KErrNotFound;
       
   363         return ETrue;
       
   364         }
       
   365 
       
   366     // 12 All looks fine, so now parse it and get x and y
       
   367     TLex8 start( byteRange.Left( pos ) );
       
   368     start.SkipSpace();
       
   369 
       
   370     // 13 If conversion fails - return error
       
   371     TInt error = start.Val( aStartPos );
       
   372     if ( !CUpnpRangeHeaderParser::HandleConversionException( start, aStartPos, error ) )
       
   373         {
       
   374         return EFalse;
       
   375         }
       
   376     // 14 We have to check if something else than space or tab leaves after conversion - unless for example 11a will be correct but it is not
       
   377     if ( CUpnpRangeHeaderParser::HasImproperChars( start ) )
       
   378             return EFalse;
       
   379 
       
   380     // y is optional
       
   381     if( ( byteRange.Length() - pos - 1 ) > 0 )
       
   382         {
       
   383         TLex8 end( byteRange.Right( byteRange.Length() - pos - 1 ) );
       
   384         end.SkipSpace();
       
   385         
       
   386         error = end.Val( aEndPos );
       
   387         if ( !CUpnpRangeHeaderParser::HandleConversionException( end, aEndPos, error ) )
       
   388             {
       
   389             return EFalse;
       
   390             }
       
   391             
       
   392         // We have to check if something else than space or tab leaves after conversion - unless for example 11a will be correct but it is not
       
   393         if ( CUpnpRangeHeaderParser::HasImproperChars( end ) )
       
   394             return EFalse;
       
   395         
       
   396         } 
       
   397     else
       
   398         {
       
   399         aEndPos = KErrNotFound; 
       
   400         } 
       
   401 
       
   402     return ETrue;
       
   403     } 
       
   404 
       
   405 // -----------------------------------------------------------------------------
       
   406 //  CUpnpRangeHeaderParser::HasImproperChars
       
   407 //  Checks number format
       
   408 // -----------------------------------------------------------------------------
       
   409 //  
       
   410 TBool CUpnpRangeHeaderParser::HasImproperChars( const TLex8& aNumber )
       
   411     {
       
   412     TPtrC8 rem_ptr = aNumber.Remainder();
       
   413     for( TInt index = 0; index < rem_ptr.Length(); index++ )
       
   414         {
       
   415         if( rem_ptr[ index ] != UpnpString::KSpace()[0] &&
       
   416             rem_ptr[ index ] != UpnpString::KTab()[0] )
       
   417             return ETrue;
       
   418         }
       
   419     return EFalse;    
       
   420     }
       
   421     
       
   422 // -----------------------------------------------------------------------------
       
   423 //  CUpnpRangeHeaderParser::MovePosition
       
   424 //  Moves parser position to first not white space
       
   425 // -----------------------------------------------------------------------------
       
   426 //  
       
   427 void CUpnpRangeHeaderParser::MovePosition( const TDesC8& aString, TInt& aPos )
       
   428     {
       
   429     while ( aPos < aString.Length() && 
       
   430             ( aString[ aPos ] == UpnpString::KSpace()[0] || aString[ aPos ] ==
       
   431                                                             UpnpString::KTab()[0] ) 
       
   432           ) 
       
   433         {
       
   434         aPos++;
       
   435         }  
       
   436     }    
       
   437 
       
   438 // -----------------------------------------------------------------------------
       
   439 //  CUpnpRangeHeaderParser::HandleConversionException
       
   440 //  Handles conversion exceptions
       
   441 // -----------------------------------------------------------------------------
       
   442 // 
       
   443 TBool CUpnpRangeHeaderParser::HandleConversionException( TLex8& aNumber, TInt& aRangePos,
       
   444                                                          TInt aError )
       
   445     {
       
   446     if( aError == KErrOverflow )
       
   447     {
       
   448         aRangePos = KMaxTInt;
       
   449         while ( aNumber.Peek().IsDigit() )
       
   450             {
       
   451             aNumber.Inc();
       
   452             }        
       
   453     }        
       
   454     else if ( aError != KErrNone )
       
   455         {
       
   456         return EFalse;
       
   457         }
       
   458     
       
   459     return ETrue;
       
   460     }
       
   461     
       
   462 // End Of File
       
   463