ROOT logo
// $Id$
// Author: Sergey Linev   21/05/2015

#include "THttpCallArg.h"

#include <string.h>
#include "RZip.h"

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THttpCallArg                                                         //
//                                                                      //
// Contains arguments for single HTTP call                              //
// Must be used in THttpEngine to process incoming http requests        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(THttpCallArg)

//______________________________________________________________________________
THttpCallArg::THttpCallArg() :
   TObject(),
   fTopName(),
   fMethod(),
   fPathName(),
   fFileName(),
   fUserName(),
   fQuery(),
   fPostData(0),
   fPostDataLength(0),
   fCond(),
   fContentType(),
   fRequestHeader(),
   fHeader(),
   fContent(),
   fZipping(0),
   fBinData(0),
   fBinDataLength(0)
{
   // constructor
}

//______________________________________________________________________________
THttpCallArg::~THttpCallArg()
{
   // destructor

   if (fPostData) {
      free(fPostData);
      fPostData = 0;
   }

   if (fBinData) {
      free(fBinData);
      fBinData = 0;
   }
}

//______________________________________________________________________________
TString THttpCallArg::AccessHeader(TString& buf, const char* name, const char* value, Bool_t doing_set)
{
   // method used to get or set http header in the string buffer
   // Header has following format:
   //   field1 : value1\r\n
   //   field2 : value2\r\n
   // Such format corresponds to header format in HTTP requests

   if (name==0) return TString();

   Int_t curr = 0;

   while (curr < buf.Length()-2) {

      Int_t next = buf.Index("\r\n", curr);
      if (next == kNPOS) break; // should never happen

      if (buf.Index(name, curr) != curr) {
         curr = next + 2;
         continue;
      }

      if ((value==0) && doing_set) {
         // special case - empty value means that field must be removed completely
         buf.Remove(curr, next-curr+2);
         return TString();
      }

      curr += strlen(name);
      while ((curr < next) && (buf[curr] != ':')) curr++;
      curr++;
      while ((curr < next) && (buf[curr] == ' ')) curr++;

      if (value==0) return buf(curr, next-curr);
      buf.Remove(curr, next-curr);
      buf.Insert(curr, value);
      return TString(value);
   }

   if (value==0) return TString();

   buf.Append(TString::Format("%s: %s\r\n", name, value));
   return TString(value);
}

//______________________________________________________________________________
TString THttpCallArg::CountHeader(const TString& buf, Int_t number) const
{
   // method used to counter number of headers or returns name of specified header

   Int_t curr(0), cnt(0);

   while (curr < buf.Length()-2) {

      Int_t next = buf.Index("\r\n", curr);
      if (next == kNPOS) break; // should never happen

      if (cnt == number) {
         // we should extract name of header
         Int_t separ = curr + 1;
         while ((separ < next) && (buf[separ] != ':')) separ++;
         return buf(curr, separ-curr);
      }

      curr = next + 2;
      cnt++;
   }

   // return total number of headers
   if (number == -1111) return TString::Format("%d", cnt);
   return TString();
}

//______________________________________________________________________________
void THttpCallArg::SetPostData(void *data, Long_t length)
{
   // set data, posted with the request
   // buffer should be allocated with malloc(length+1) call,
   // while last byte will be set to 0
   // Than one could use post data as null-terminated string

   if (fPostData) free(fPostData);
   if (data!=0) *(((char*) data) + length) = 0;
   fPostData = data;
   fPostDataLength = length;
}

//______________________________________________________________________________
void THttpCallArg::SetBinData(void *data, Long_t length)
{
   // set binary data, which will be returned as reply body

   if (fBinData) free(fBinData);
   fBinData = data;
   fBinDataLength = length;

   // string content must be cleared in any case
   fContent.Clear();
}

//______________________________________________________________________________
void THttpCallArg::SetPathAndFileName(const char *fullpath)
{
   // set complete path of requested http element
   // For instance, it could be "/folder/subfolder/get.bin"
   // Here "/folder/subfolder/" is element path and "get.bin" requested file.
   // One could set path and file name separately

   fPathName.Clear();
   fFileName.Clear();

   if (fullpath == 0) return;

   const char *rslash = strrchr(fullpath, '/');
   if (rslash == 0) {
      fFileName = fullpath;
   } else {
      while ((fullpath != rslash) && (*fullpath == '/')) fullpath++;
      fPathName.Append(fullpath, rslash - fullpath);
      if (fPathName == "/") fPathName.Clear();
      fFileName = rslash + 1;
   }
}

//______________________________________________________________________________
TString THttpCallArg::GetHeader(const char* name)
{
   // return specified header

   if ((name == 0) || (*name == 0)) return TString();

   if (strcmp(name,"Content-Type") == 0) return fContentType;
   if (strcmp(name,"Content-Length") == 0) return TString::Format("%ld", GetContentLength());

   return AccessHeader(fHeader, name);
}

//______________________________________________________________________________
void THttpCallArg::AddHeader(const char *name, const char *value)
{
   // Set name: value pair to reply header
   // Content-Type field handled separately - one should use SetContentType() method
   // Content-Length field cannot be set at all;

   if ((name == 0) || (*name == 0) || (strcmp(name,"Content-Length") == 0)) return;

   if (strcmp(name,"Content-Type") == 0)
      SetContentType(value);
   else
      AccessHeader(fHeader, name, value, kTRUE);
}

//______________________________________________________________________________
void THttpCallArg::FillHttpHeader(TString &hdr, const char *kind)
{
   // fill HTTP header

   if (kind == 0) kind = "HTTP/1.1";

   if ((fContentType.Length() == 0) || Is404()) {
      hdr.Form("%s 404 Not Found\r\n"
               "Content-Length: 0\r\n"
               "Connection: close\r\n\r\n", kind);
   } else {
      hdr.Form("%s 200 OK\r\n"
               "Content-Type: %s\r\n"
               "Connection: keep-alive\r\n"
               "Content-Length: %ld\r\n"
               "%s\r\n",
               kind,
               GetContentType(),
               GetContentLength(),
               fHeader.Data());
   }
}

//______________________________________________________________________________
Bool_t THttpCallArg::CompressWithGzip()
{
   // compress reply data with gzip compression

   char *objbuf = (char *) GetContent();
   Long_t objlen = GetContentLength();

   unsigned long objcrc = R__crc32(0, NULL, 0);
   objcrc = R__crc32(objcrc, (const unsigned char *) objbuf, objlen);

   // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
   Int_t buflen = 10 + objlen + 8;
   if (buflen < 512) buflen = 512;

   void *buffer = malloc(buflen);

   char *bufcur = (char *) buffer;

   *bufcur++ = 0x1f;  // first byte of ZIP identifier
   *bufcur++ = 0x8b;  // second byte of ZIP identifier
   *bufcur++ = 0x08;  // compression method
   *bufcur++ = 0x00;  // FLAG - empty, no any file names
   *bufcur++ = 0;    // empty timestamp
   *bufcur++ = 0;    //
   *bufcur++ = 0;    //
   *bufcur++ = 0;    //
   *bufcur++ = 0;    // XFL (eXtra FLags)
   *bufcur++ = 3;    // OS   3 means Unix
   //strcpy(bufcur, "item.json");
   //bufcur += strlen("item.json")+1;

   char dummy[8];
   memcpy(dummy, bufcur - 6, 6);

   // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
   unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, objbuf, objlen);

   memcpy(bufcur - 6, dummy, 6);

   bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)

   *bufcur++ = objcrc & 0xff;    // CRC32
   *bufcur++ = (objcrc >> 8) & 0xff;
   *bufcur++ = (objcrc >> 16) & 0xff;
   *bufcur++ = (objcrc >> 24) & 0xff;

   *bufcur++ = objlen & 0xff;  // original data length
   *bufcur++ = (objlen >> 8) & 0xff;  // original data length
   *bufcur++ = (objlen >> 16) & 0xff;  // original data length
   *bufcur++ = (objlen >> 24) & 0xff;  // original data length

   SetBinData(buffer, bufcur - (char *) buffer);

   SetEncoding("gzip");

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