<commit_before>// @(#)root/net:$Id$
// Author: <NAME>   23/08/2011

/*************************************************************************
 * Copyright (C) 1995-2011, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THTTPMessage                                                         //
//                                                                      //
// A THTTPMessage object represents a generic HTTP request for the      //
// Amazon S3 and the Google Storage services. It can easily be extended //
// to other API's. It assumes that each request is signed with the      //
// client id and an encripted key, Base64(HMAC + SHA1 (HTTP Request))   //
// which is based on a secret key provided in the constructor.          //
// For more information about the authentication :                      //
// Google Storage:                                                      //
//   http://code.google.com/apis/storage/docs/reference/v1/developer-guidev1.html#authentication //
// Amazon S3:                                                           //
//   http://awsdocs.s3.amazonaws.com/S3/latest/s3-qrc.pdf               //
// At the moment THTTPMessage is used for derived classes of TWebFile   //
// (read only) files supporting HEAD and GET requests.                  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "THTTPMessage.h"
#include "TBase64.h"
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

ClassImp(THTTPMessage)

//______________________________________________________________________________
THTTPMessage::THTTPMessage(EHTTP_Verb mverb, TString mpath, TString mbucket,
                           TString mhost, TString maprefix, TString maid,
                           TString maidkey)
{
   // THTTPMessage for HTTP requests without the Range attribute.

   fVerb        = mverb;
   fPath        = mpath;
   fBucket      = mbucket;
   fHost        = mhost;
   fDate        = DatimeToTString();
   fAuthPrefix  = maprefix;
   fAccessId    = maid;
   fAccessIdKey = maidkey;
   fHasRange    = kFALSE;
   fInitByte    = 0;
   fFinalByte   = 0;
   fSignature   = Sign();
}

//______________________________________________________________________________
THTTPMessage::THTTPMessage(EHTTP_Verb mverb, TString mpath, TString mbucket,
                           TString mhost, TString maprefix, TString maid,
                           TString maidkey, Int_t ibyte, Int_t fbyte)
{
   // THTTPMessage for HTTP Get Requests with Range.

   fVerb        = mverb;
   fPath        = mpath;
   fBucket      = mbucket;
   fHost        = mhost;
   fDate        = DatimeToTString();
   fAuthPrefix  = maprefix;
   fAccessId    = maid;
   fAccessIdKey = maidkey;
   fHasRange    = kTRUE;
   fInitByte    = ibyte;
   fFinalByte   = fbyte;
   fSignature   = Sign();
}

//______________________________________________________________________________
THTTPMessage &THTTPMessage::operator=(const THTTPMessage &rhs)
{
   // Copy ctor.

   if (this != &rhs){
      TObject::operator=(rhs);
      fVerb        = rhs.fVerb;
      fPath        = rhs.fPath;
      fBucket      = rhs.fBucket;
      fHost        = rhs.fHost;
      fDate        = rhs.fDate;
      fHasRange    = rhs.fHasRange;
      fInitByte    = rhs.fInitByte;
      fFinalByte   = rhs.fFinalByte;
      fAuthPrefix  = rhs.fAuthPrefix;
      fAccessId    = rhs.fAccessId;
      fAccessIdKey = rhs.fAccessIdKey;
      fSignature   = rhs.fSignature;
   }
   return *this;
}

//______________________________________________________________________________
TString THTTPMessage::Sign()
{
   // Message Signature according to:
   //    http://awsdocs.s3.amazonaws.com/S3/latest/s3-qrc.pdf
   // and
   //    http://code.google.com/apis/storage/docs/reference/v1/developer-guidev1.html#authentication

   TString sign;
   sign += HTTPVerbToTString() + "\n";
   sign += "\n"; // GetContentMD5()
   sign += "\n"; // GetContentType()
   sign += DatimeToTString() + "\n";

   if(GetAuthPrefix() == "GOOG1"){
      sign += "x-goog-api-version:1\n";
   }

   sign += "/"+GetBucket()+GetPath();
   char digest[SHA_DIGEST_LENGTH] = {0};
   unsigned int *sd = NULL;

   TString key = GetAccessIdKey();

   HMAC(EVP_sha1(), key.Data(), key.Length() , (unsigned char *) sign.Data(), sign.Length(), (unsigned char *) digest, sd);

   return TBase64::Encode((const char *) digest, SHA_DIGEST_LENGTH);
}

//______________________________________________________________________________
TString THTTPMessage::HTTPVerbToTString() const
{
   EHTTP_Verb mverb = GetHTTPVerb();
   switch(mverb){
      case kGET:    return TString("GET");
      case kPOST:   return TString("POST");
      case kPUT:    return TString("PUT");
      case kDELETE: return TString("DELETE");
      case kHEAD:   return TString("HEAD");
      case kCOPY:   return TString("COPY");
      default:      return TString("");
   }
}

//______________________________________________________________________________
TString THTTPMessage::DatimeToTString() const
{
   // Generates a Date TString according to:
   //   http://code.google.com/apis/storage/docs/reference-headers.html#date<commit_msg>From Marcelo: Use the new Apple CommonCrypto libraryt instead of the deprecated OpenSSL. See: http://ludovicrousseau.blogspot.com/.<commit_after>// @(#)root/net:$Id$
// Author: <NAME>   23/08/2011

/*************************************************************************
 * Copyright (C) 1995-2011, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THTTPMessage                                                         //
//                                                                      //
// A THTTPMessage object represents a generic HTTP request for the      //
// Amazon S3 and the Google Storage services. It can easily be extended //
// to other API's. It assumes that each request is signed with the      //
// client id and an encripted key, Base64(HMAC + SHA1 (HTTP Request))   //
// which is based on a secret key provided in the constructor.          //
// For more information about the authentication :                      //
// Google Storage:                                                      //
//   http://code.google.com/apis/storage/docs/reference/v1/developer-guidev1.html#authentication //
// Amazon S3:                                                           //
//   http://awsdocs.s3.amazonaws.com/S3/latest/s3-qrc.pdf               //
// At the moment THTTPMessage is used for derived classes of TWebFile   //
// (read only) files supporting HEAD and GET requests.                  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "THTTPMessage.h"
#include "TBase64.h"
#if defined(MAC_OS_X_VERSION_10_7)
#include <CommonCrypto/CommonHMAC.h>
#define SHA_DIGEST_LENGTH 20
#else
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#endif

#include <stdio.h>
#include <time.h>
#include <string.h>

ClassImp(THTTPMessage)

//______________________________________________________________________________
THTTPMessage::THTTPMessage(EHTTP_Verb mverb, TString mpath, TString mbucket,
                           TString mhost, TString maprefix, TString maid,
                           TString maidkey)
{
   // THTTPMessage for HTTP requests without the Range attribute.

   fVerb         = mverb;
   fPath         = mpath;
   fBucket       = mbucket;
   fHost         = mhost;
   fDate         = DatimeToTString();
   fAuthPrefix   = maprefix;
   fAccessId     = maid;
   fAccessIdKey  = maidkey;
   fHasRange     = false;
   fInitByte     = 0;
   fFinalByte    = 0;
   fSignature    = Sign();
}                

//______________________________________________________________________________
THTTPMessage::THTTPMessage(EHTTP_Verb mverb, TString mpath, TString mbucket,
                           TString mhost, TString maprefix, TString maid,
                           TString maidkey, Int_t ibyte, Int_t fbyte)
{
   // THTTPMessage for HTTP Get Requests with Range.

   fVerb        = mverb;
   fPath        = mpath;
   fBucket      = mbucket;
   fHost        = mhost;
   fDate        = DatimeToTString();
   fAuthPrefix  = maprefix;
   fAccessId    = maid;
   fAccessIdKey = maidkey;
   fHasRange    = kTRUE;
   fInitByte    = ibyte;
   fFinalByte   = fbyte;
   fSignature   = Sign();
}

//______________________________________________________________________________
THTTPMessage &THTTPMessage::operator=(const THTTPMessage &rhs)
{
   // Copy ctor.

   if (this != &rhs){
      TObject::operator=(rhs);
      fVerb        = rhs.fVerb;
      fPath        = rhs.fPath;
      fBucket      = rhs.fBucket;
      fHost        = rhs.fHost;
      fDate        = rhs.fDate;
      fHasRange    = rhs.fHasRange;
      fInitByte    = rhs.fInitByte;
      fFinalByte   = rhs.fFinalByte;
      fAuthPrefix  = rhs.fAuthPrefix;
      fAccessId    = rhs.fAccessId;
      fAccessIdKey = rhs.fAccessIdKey;
      fSignature   = rhs.fSignature;
   }
   return *this;
}

//______________________________________________________________________________
TString THTTPMessage::Sign()
{
   // Message Signature according to:
   //    http://awsdocs.s3.amazonaws.com/S3/latest/s3-qrc.pdf
   // and
   //    http://code.google.com/apis/storage/docs/reference/v1/developer-guidev1.html#authentication

   TString sign;
   sign += HTTPVerbToTString() + "\n";
   sign += "\n"; // GetContentMD5()
   sign += "\n"; // GetContentType()
   sign += DatimeToTString() + "\n";

   if(GetAuthPrefix() == "GOOG1"){
      sign += "x-goog-api-version:1\n";
   }

   sign += "/"+GetBucket()+GetPath();
   char digest[SHA_DIGEST_LENGTH] = {0};
   TString key = GetAccessIdKey();
	
   #if defined(MAC_OS_X_VERSION_10_7)
   CCHmac(kCCHmacAlgSHA1, key.Data(), key.Length() , (unsigned char *) sign.Data(), sign.Length(), (unsigned char *) digest);
   #else
   unsigned int *sd = NULL;
   HMAC(EVP_sha1(), key.Data(), key.Length() , (unsigned char *) sign.Data(), sign.Length(), (unsigned char *) digest, sd);	
   #endif



   return TBase64::Encode((const char *) digest, SHA_DIGEST_LENGTH);
}

//______________________________________________________________________________
TString THTTPMessage::HTTPVerbToTString() const
{
   EHTTP_Verb mverb = GetHTTPVerb();
   switch(mverb){
      case kGET:    return TString("GET");
      case kPOST:   return TString("POST");
      case kPUT:    return TString("PUT");
      case kDELETE: return TString("DELETE");
      case kHEAD:   return TString("HEAD");
      case kCOPY:   return TString("COPY");
      default:      return TString("");
   }
}

//______________________________________________________________________________
TString THTTPMessage::DatimeToTString() const
{
   // Generates a Date TString according to:
   //   http://code.google.com/apis/storage/docs/reference-headers.html#date
{'fraction_non_alphanumeric': 0.1510791366906475, 'fraction_numerical': 0.007603008502289078, 'mean_word_length': 1.8905954631379962, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7363662', 'n_tokens_mistral': 3350, 'n_tokens_neox': 3240, 'n_words': 766}