ROOT logo
// @(#)root/net:$Id: THTTPMessage.cxx 41644 2011-10-29 22:38:37Z rdm $
// Author: Marcelo Sousa   23/08/2011

/*************************************************************************
 * Copyright (C) 1995-2011, Rene Brun and Fons Rademakers.               *
 * 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     = kFALSE;
   fInitByte     = 0;
   fOffset       = 0;
   fLen          = 0;
   fNumBuf       = 0;
   fCurrentBuf   = 0;
   fLength       = 0;

   fSignature    = Sign();
}

//______________________________________________________________________________
THTTPMessage::THTTPMessage(EHTTP_Verb mverb, TString mpath, TString mbucket, TString mhost,
                           TString maprefix, TString maid, TString maidkey, Long64_t offset,
                           Long64_t *pos, Int_t *len, Int_t nbuf)
{
   // 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    = pos;
   fOffset      = offset;
   fLen         = len;
   fNumBuf      = nbuf;
   fCurrentBuf  = 0;
   fLength      = 0;

   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;
      fOffset      = rhs.fOffset;
      fLen         = rhs.fLen;
      fNumBuf      = rhs.fNumBuf;
      fCurrentBuf  = rhs.fCurrentBuf;
      fAuthPrefix  = rhs.fAuthPrefix;
      fAccessId    = rhs.fAccessId;
      fAccessIdKey = rhs.fAccessIdKey;
      fSignature   = rhs.fSignature;
      fLength      = rhs.fLength;
   }
   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

   time_t date_temp;
   struct tm *date_format;
   char date_out[128];

   time(&date_temp);
   date_format = gmtime(&date_temp);
   strftime(date_out, 128, "%a, %d %b %Y %H:%M:%S GMT", date_format);

   return TString(date_out);
}

//______________________________________________________________________________
TString THTTPMessage::CreateHead() const
{
   return HTTPVerbToTString() + " " + GetPath() + " HTTP/1.1";
}

//______________________________________________________________________________
TString THTTPMessage::CreateHost() const
{
   return (fBucket.EqualTo("")) ? "Host: "+GetHost() : "Host: "+GetBucket()+"."+GetHost();
}

//______________________________________________________________________________
TString THTTPMessage::CreateDate() const
{
   return "Date: " + GetDatime();
}

//______________________________________________________________________________
TString THTTPMessage::CreateAuth() const
{
   if (GetAuthPrefix() == "AWS") {
      return "Authorization: " + GetAuthPrefix() + " " + GetAccessId()+":"+GetSignature();
   } else {
      return "x-goog-api-version: 1\r\nAuthorization: " + GetAuthPrefix() + " " +
      GetAccessId() + ":" + GetSignature();
   }
}

//______________________________________________________________________________
TString THTTPMessage::GetRequest()
{
   // Generates a TString with the HTTP Request.

   TString msg;
   msg  = CreateHead()+"\r\n";
   msg += CreateHost()+"\r\n";
   msg += CreateDate()+"\r\n";

   Int_t n = 0;
   if(HasRange()){
      msg += "Range: bytes=";
      for (Int_t i = 0; i < fNumBuf; i++) {
         if (n) msg += ",";
         msg += fInitByte[i] + fOffset;
         msg += "-";
         msg += fInitByte[i] + fOffset + fLen[i] - 1;
         fLength += fLen[i];
         n += fLen[i];
         fCurrentBuf++;
         if (msg.Length() > 8000) {
            break;
         }
      }
      msg += "\r\n";
   }

   msg += CreateAuth()+"\r\n";
   msg += "\r\n\r\n";;
   return msg;
}
 THTTPMessage.cxx:1
 THTTPMessage.cxx:2
 THTTPMessage.cxx:3
 THTTPMessage.cxx:4
 THTTPMessage.cxx:5
 THTTPMessage.cxx:6
 THTTPMessage.cxx:7
 THTTPMessage.cxx:8
 THTTPMessage.cxx:9
 THTTPMessage.cxx:10
 THTTPMessage.cxx:11
 THTTPMessage.cxx:12
 THTTPMessage.cxx:13
 THTTPMessage.cxx:14
 THTTPMessage.cxx:15
 THTTPMessage.cxx:16
 THTTPMessage.cxx:17
 THTTPMessage.cxx:18
 THTTPMessage.cxx:19
 THTTPMessage.cxx:20
 THTTPMessage.cxx:21
 THTTPMessage.cxx:22
 THTTPMessage.cxx:23
 THTTPMessage.cxx:24
 THTTPMessage.cxx:25
 THTTPMessage.cxx:26
 THTTPMessage.cxx:27
 THTTPMessage.cxx:28
 THTTPMessage.cxx:29
 THTTPMessage.cxx:30
 THTTPMessage.cxx:31
 THTTPMessage.cxx:32
 THTTPMessage.cxx:33
 THTTPMessage.cxx:34
 THTTPMessage.cxx:35
 THTTPMessage.cxx:36
 THTTPMessage.cxx:37
 THTTPMessage.cxx:38
 THTTPMessage.cxx:39
 THTTPMessage.cxx:40
 THTTPMessage.cxx:41
 THTTPMessage.cxx:42
 THTTPMessage.cxx:43
 THTTPMessage.cxx:44
 THTTPMessage.cxx:45
 THTTPMessage.cxx:46
 THTTPMessage.cxx:47
 THTTPMessage.cxx:48
 THTTPMessage.cxx:49
 THTTPMessage.cxx:50
 THTTPMessage.cxx:51
 THTTPMessage.cxx:52
 THTTPMessage.cxx:53
 THTTPMessage.cxx:54
 THTTPMessage.cxx:55
 THTTPMessage.cxx:56
 THTTPMessage.cxx:57
 THTTPMessage.cxx:58
 THTTPMessage.cxx:59
 THTTPMessage.cxx:60
 THTTPMessage.cxx:61
 THTTPMessage.cxx:62
 THTTPMessage.cxx:63
 THTTPMessage.cxx:64
 THTTPMessage.cxx:65
 THTTPMessage.cxx:66
 THTTPMessage.cxx:67
 THTTPMessage.cxx:68
 THTTPMessage.cxx:69
 THTTPMessage.cxx:70
 THTTPMessage.cxx:71
 THTTPMessage.cxx:72
 THTTPMessage.cxx:73
 THTTPMessage.cxx:74
 THTTPMessage.cxx:75
 THTTPMessage.cxx:76
 THTTPMessage.cxx:77
 THTTPMessage.cxx:78
 THTTPMessage.cxx:79
 THTTPMessage.cxx:80
 THTTPMessage.cxx:81
 THTTPMessage.cxx:82
 THTTPMessage.cxx:83
 THTTPMessage.cxx:84
 THTTPMessage.cxx:85
 THTTPMessage.cxx:86
 THTTPMessage.cxx:87
 THTTPMessage.cxx:88
 THTTPMessage.cxx:89
 THTTPMessage.cxx:90
 THTTPMessage.cxx:91
 THTTPMessage.cxx:92
 THTTPMessage.cxx:93
 THTTPMessage.cxx:94
 THTTPMessage.cxx:95
 THTTPMessage.cxx:96
 THTTPMessage.cxx:97
 THTTPMessage.cxx:98
 THTTPMessage.cxx:99
 THTTPMessage.cxx:100
 THTTPMessage.cxx:101
 THTTPMessage.cxx:102
 THTTPMessage.cxx:103
 THTTPMessage.cxx:104
 THTTPMessage.cxx:105
 THTTPMessage.cxx:106
 THTTPMessage.cxx:107
 THTTPMessage.cxx:108
 THTTPMessage.cxx:109
 THTTPMessage.cxx:110
 THTTPMessage.cxx:111
 THTTPMessage.cxx:112
 THTTPMessage.cxx:113
 THTTPMessage.cxx:114
 THTTPMessage.cxx:115
 THTTPMessage.cxx:116
 THTTPMessage.cxx:117
 THTTPMessage.cxx:118
 THTTPMessage.cxx:119
 THTTPMessage.cxx:120
 THTTPMessage.cxx:121
 THTTPMessage.cxx:122
 THTTPMessage.cxx:123
 THTTPMessage.cxx:124
 THTTPMessage.cxx:125
 THTTPMessage.cxx:126
 THTTPMessage.cxx:127
 THTTPMessage.cxx:128
 THTTPMessage.cxx:129
 THTTPMessage.cxx:130
 THTTPMessage.cxx:131
 THTTPMessage.cxx:132
 THTTPMessage.cxx:133
 THTTPMessage.cxx:134
 THTTPMessage.cxx:135
 THTTPMessage.cxx:136
 THTTPMessage.cxx:137
 THTTPMessage.cxx:138
 THTTPMessage.cxx:139
 THTTPMessage.cxx:140
 THTTPMessage.cxx:141
 THTTPMessage.cxx:142
 THTTPMessage.cxx:143
 THTTPMessage.cxx:144
 THTTPMessage.cxx:145
 THTTPMessage.cxx:146
 THTTPMessage.cxx:147
 THTTPMessage.cxx:148
 THTTPMessage.cxx:149
 THTTPMessage.cxx:150
 THTTPMessage.cxx:151
 THTTPMessage.cxx:152
 THTTPMessage.cxx:153
 THTTPMessage.cxx:154
 THTTPMessage.cxx:155
 THTTPMessage.cxx:156
 THTTPMessage.cxx:157
 THTTPMessage.cxx:158
 THTTPMessage.cxx:159
 THTTPMessage.cxx:160
 THTTPMessage.cxx:161
 THTTPMessage.cxx:162
 THTTPMessage.cxx:163
 THTTPMessage.cxx:164
 THTTPMessage.cxx:165
 THTTPMessage.cxx:166
 THTTPMessage.cxx:167
 THTTPMessage.cxx:168
 THTTPMessage.cxx:169
 THTTPMessage.cxx:170
 THTTPMessage.cxx:171
 THTTPMessage.cxx:172
 THTTPMessage.cxx:173
 THTTPMessage.cxx:174
 THTTPMessage.cxx:175
 THTTPMessage.cxx:176
 THTTPMessage.cxx:177
 THTTPMessage.cxx:178
 THTTPMessage.cxx:179
 THTTPMessage.cxx:180
 THTTPMessage.cxx:181
 THTTPMessage.cxx:182
 THTTPMessage.cxx:183
 THTTPMessage.cxx:184
 THTTPMessage.cxx:185
 THTTPMessage.cxx:186
 THTTPMessage.cxx:187
 THTTPMessage.cxx:188
 THTTPMessage.cxx:189
 THTTPMessage.cxx:190
 THTTPMessage.cxx:191
 THTTPMessage.cxx:192
 THTTPMessage.cxx:193
 THTTPMessage.cxx:194
 THTTPMessage.cxx:195
 THTTPMessage.cxx:196
 THTTPMessage.cxx:197
 THTTPMessage.cxx:198
 THTTPMessage.cxx:199
 THTTPMessage.cxx:200
 THTTPMessage.cxx:201
 THTTPMessage.cxx:202
 THTTPMessage.cxx:203
 THTTPMessage.cxx:204
 THTTPMessage.cxx:205
 THTTPMessage.cxx:206
 THTTPMessage.cxx:207
 THTTPMessage.cxx:208
 THTTPMessage.cxx:209
 THTTPMessage.cxx:210
 THTTPMessage.cxx:211
 THTTPMessage.cxx:212
 THTTPMessage.cxx:213
 THTTPMessage.cxx:214
 THTTPMessage.cxx:215
 THTTPMessage.cxx:216
 THTTPMessage.cxx:217
 THTTPMessage.cxx:218
 THTTPMessage.cxx:219
 THTTPMessage.cxx:220
 THTTPMessage.cxx:221
 THTTPMessage.cxx:222
 THTTPMessage.cxx:223
 THTTPMessage.cxx:224
 THTTPMessage.cxx:225
 THTTPMessage.cxx:226
 THTTPMessage.cxx:227
 THTTPMessage.cxx:228
 THTTPMessage.cxx:229
 THTTPMessage.cxx:230
 THTTPMessage.cxx:231
 THTTPMessage.cxx:232
 THTTPMessage.cxx:233
 THTTPMessage.cxx:234
 THTTPMessage.cxx:235
 THTTPMessage.cxx:236
 THTTPMessage.cxx:237
 THTTPMessage.cxx:238
 THTTPMessage.cxx:239
 THTTPMessage.cxx:240
 THTTPMessage.cxx:241
 THTTPMessage.cxx:242
 THTTPMessage.cxx:243
 THTTPMessage.cxx:244
 THTTPMessage.cxx:245
 THTTPMessage.cxx:246
 THTTPMessage.cxx:247
 THTTPMessage.cxx:248
 THTTPMessage.cxx:249
 THTTPMessage.cxx:250
 THTTPMessage.cxx:251
 THTTPMessage.cxx:252