#include "TWebFile.h"
#include "TROOT.h"
#include "TSocket.h"
#include "Bytes.h"
static const char *gUserAgent = "User-Agent: ROOT-TWebFile/1.0";
ClassImp(TWebFile)
TWebFile::TWebFile(const char *url) : TFile(url, "WEB")
{
   
   
   
   
   
   
   
   Init(kFALSE);
}
TWebFile::TWebFile(TUrl url) : TFile(url.GetUrl(), "WEB")
{
   
   
   
   
   
   
   Init(kFALSE);
}
void TWebFile::Init(Bool_t)
{
   
   char buf[4];
   int  err;
   if ((err = GetHead()) < 0) {
      if (err == -2)
         Error("TWebFile", "%s does not exist", fUrl.GetUrl());
      MakeZombie();
      gDirectory = gROOT;
      return;
   }
   Seek(0);
   if (ReadBuffer(buf, 4)) {
      MakeZombie();
      gDirectory = gROOT;
      return;
   }
   if (strncmp(buf, "root", 4) && strncmp(buf, "PK", 2)) {  
      Error("TWebFile", "%s is not a ROOT file", fUrl.GetUrl());
      MakeZombie();
      gDirectory = gROOT;
      return;
   }
   TFile::Init(kFALSE);
   fD = -2;   
}
Bool_t TWebFile::IsOpen() const
{
   
   return IsZombie() ? kFALSE : kTRUE;
}
Int_t TWebFile::ReOpen(Option_t *mode)
{
   
   
   
   
   
   
   
   TString opt = mode;
   opt.ToUpper();
   if (opt != "READ" && opt != "UPDATE")
      Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
   if (opt == "UPDATE")
      Error("ReOpen", "update mode not allowed for a TWebFile");
   return 1;
}
Bool_t TWebFile::ReadBuffer(char *buf, Int_t len)
{
   
   
   
   Int_t st;
   if ((st = ReadBufferViaCache(buf, len))) {
      if (st == 2)
         return kTRUE;
      return kFALSE;
   }
   if (!fHasModRoot)
      return ReadBuffer10(buf, len);
   
   
   TString msg = "GET ";
   msg += fUrl.GetProtocol();
   msg += "://";
   msg += fUrl.GetHost();
   msg += ":";
   msg += fUrl.GetPort();
   msg += "/";
   msg += fUrl.GetFile();
   msg += "?";
   msg += fOffset;
   msg += ":";
   msg += len;
   msg += "\r\n";
   if (GetFromWeb(buf, len, msg) == -1)
      return kTRUE;
   fOffset += len;
   return kFALSE;
}
Bool_t TWebFile::ReadBuffer10(char *buf, Int_t len)
{
   
   
   
   
   TString msg = "GET ";
   msg += fUrl.GetProtocol();
   msg += "://";
   msg += fUrl.GetHost();
   msg += ":";
   msg += fUrl.GetPort();
   msg += "/";
   msg += fUrl.GetFile();
   msg += " HTTP/1.0";
   msg += "\r\n";
   msg += gUserAgent;
   msg += "\r\n";
   msg += "Range: bytes=";
   msg += fOffset;
   msg += "-";
   msg += fOffset+len-1;
   msg += "\r\n\r\n";
   if (GetFromWeb10(buf, len, msg) == -1)
      return kTRUE;
   fOffset += len;
   return kFALSE;
}
Bool_t TWebFile::ReadBuffers(char *buf,  Long64_t *pos, Int_t *len, Int_t nbuf)
{
   
   
   
   
   
   
   if (!fHasModRoot)
      return ReadBuffers10(buf, pos, len, nbuf);
   
   
   TString msgh = "GET ";
   msgh += fUrl.GetProtocol();
   msgh += "://";
   msgh += fUrl.GetHost();
   msgh += ":";
   msgh += fUrl.GetPort();
   msgh += "/";
   msgh += fUrl.GetFile();
   msgh += "?";
   TString msg = msgh;
   Int_t k = 0, n = 0;
   for (Int_t i = 0; i < nbuf; i++) {
      if (n) msg += ",";
      msg += pos[i] + fArchiveOffset;
      msg += ":";
      msg += len[i];
      n   += len[i];
      if (msg.Length() > 8000) {
         msg += "\r\n";
         if (GetFromWeb(&buf[k], n, msg) == -1)
            return kTRUE;
         msg = msgh;
         k += n;
         n = 0;
      }
   }
   msg += "\r\n";
   if (GetFromWeb(&buf[k], n, msg) == -1)
      return kTRUE;
   return kFALSE;
}
Bool_t TWebFile::ReadBuffers10(char *buf,  Long64_t *pos, Int_t *len, Int_t nbuf)
{
   
   
   
   
   
   
   
   TString msgh = "GET ";
   msgh += fUrl.GetProtocol();
   msgh += "://";
   msgh += fUrl.GetHost();
   msgh += ":";
   msgh += fUrl.GetPort();
   msgh += "/";
   msgh += fUrl.GetFile();
   msgh += " HTTP/1.0";
   msgh += "\r\n";
   msgh += gUserAgent;
   msgh += "\r\n";
   msgh += "Range: bytes=";
   TString msg = msgh;
   Int_t k = 0, n = 0;
   for (Int_t i = 0; i < nbuf; i++) {
      if (n) msg += ",";
      msg += pos[i] + fArchiveOffset;
      msg += "-";
      msg += pos[i] + fArchiveOffset + len[i] - 1;
      n   += len[i];
      if (msg.Length() > 8000) {
         msg += "\r\n\r\n";
         if (GetFromWeb10(&buf[k], n, msg) == -1)
            return kTRUE;
         msg = msgh;
         k += n;
         n = 0;
      }
   }
   msg += "\r\n\r\n";
   if (GetFromWeb10(&buf[k], n, msg) == -1)
      return kTRUE;
   return kFALSE;
}
Int_t TWebFile::GetFromWeb(char *buf, Int_t len, const TString &msg)
{
   
   
   if (!len) return 0;
   TSocket s(fUrl.GetHost(), fUrl.GetPort());
   if (!s.IsValid()) {
      Error("GetFromWeb", "cannot connect to remote host %s", fUrl.GetHost());
      return -1;
   }
   if (s.SendRaw(msg.Data(), msg.Length()) == -1) {
      Error("GetFromWeb", "error sending command to remote host %s", fUrl.GetHost());
      return -1;
   }
   if (s.RecvRaw(buf, len) == -1) {
      Error("GetFromWeb", "error receiving data from remote host %s", fUrl.GetHost());
      return -1;
   }
   fBytesRead += len;
   SetFileBytesRead(GetFileBytesRead() + len);
   return 0;
}
Int_t TWebFile::GetFromWeb10(char *buf, Int_t len, const TString &msg)
{
   
   
   
   if (!len) return 0;
   TSocket s(fUrl.GetHost(), fUrl.GetPort());
   if (!s.IsValid()) {
      Error("GetFromWeb10", "cannot connect to remote host %s", fUrl.GetHost());
      return -1;
   }
   if (s.SendRaw(msg.Data(), msg.Length()) == -1) {
      Error("GetFromWeb10", "error sending command to remote host %s", fUrl.GetHost());
      return -1;
   }
   char line[1024];
   Int_t n, ret = 0, nranges = 0, ltot = 0;
   TString boundary, boundaryEnd;
   Long64_t first = -1, last, tot;
   while ((n = GetLine(&s, line, 1024)) >= 0) {
      if (n == 0) {
         if (ret < 0)
            return ret;
         if (first >= 0) {
            Int_t ll = Int_t(last - first) + 1;
            if (s.RecvRaw(&buf[ltot], ll) == -1) {
               Error("GetFromWeb10", "error receiving data from remote host %s", fUrl.GetHost());
               return -1;
            }
            ltot += ll;
            fBytesRead += ll;
            SetFileBytesRead(GetFileBytesRead() + ll);
            first = -1;
            if (boundary == "")
               break;  
         }
         continue;
      }
      if (gDebug > 0)
         Info("GetFromWeb10", "header: %s", line);
      if (boundaryEnd == line) {
         if (gDebug > 0)
            Info("GetFromWeb10", "got all headers");
         break;
      }
      if (boundary == line) {
         nranges++;
         if (gDebug > 0)
            Info("GetFromWeb10", "get new multipart byte range (%d)", nranges);
      }
      TString res = line;
      if (res.BeginsWith("HTTP/1.")) {
         TString scode = res(9, 3);
         Int_t code = scode.Atoi();
         if (code != 206) {
            ret = -1;
            TString mess = res(13, 1000);
            Error("GetFromWeb10", "%s: %s (%d)", fUrl.GetUrl(), mess.Data(), code);
         }
      }
      if (res.BeginsWith("Content-Type: multipart")) {
         boundary = "--" + res(res.Index("boundary=")+9, 1000);
         boundaryEnd = boundary + "--";
      }
      if (res.BeginsWith("Content-range:")) {
         sscanf(res.Data(), "Content-range: bytes %lld-%lld/%lld", &first, &last, &tot);
      }
      if (res.BeginsWith("Content-Range:")) {
         sscanf(res.Data(), "Content-Range: bytes %lld-%lld/%lld", &first, &last, &tot);
      }
   }
   if (ltot != len) {
      Error("GetFromWeb10", "error receiving expected amount of data (got %d, expected %d) from remote host %s",
            ltot, len, fUrl.GetHost());
      return -1;
   }
   return 0;
}
void TWebFile::Seek(Long64_t offset, ERelativeTo pos)
{
   
   switch (pos) {
   case kBeg:
      fOffset = offset + fArchiveOffset;
      break;
   case kCur:
      fOffset += offset;
      break;
   case kEnd:
      
      if (fArchiveOffset)
         Error("Seek", "seeking from end in archive is not (yet) supported");
      fOffset = fEND - offset;  
      break;
   }
}
Long64_t TWebFile::GetSize() const
{
   
   if (!fHasModRoot || fSize >= 0)
      return fSize;
   Long64_t size;
   char     asize[64];
   TString msg = "GET ";
   msg += fUrl.GetProtocol();
   msg += "://";
   msg += fUrl.GetHost();
   msg += ":";
   msg += fUrl.GetPort();
   msg += "/";
   msg += fUrl.GetFile();
   msg += "?";
   msg += -1;
   msg += "\r\n";
   if (const_cast<TWebFile*>(this)->GetFromWeb(asize, 64, msg) == -1)
      return kMaxInt;
#ifndef R__WIN32
   size = atoll(asize);
#else
   size = _atoi64(asize);
#endif
   fSize = size;
   return size;
}
Int_t TWebFile::GetHead()
{
   
   
   
   
   fSize       = -1;
   fHasModRoot = kFALSE;
   
   TString msg = "HEAD ";
   msg += fUrl.GetProtocol();
   msg += "://";
   msg += fUrl.GetHost();
   msg += ":";
   msg += fUrl.GetPort();
   msg += "/";
   msg += fUrl.GetFile();
   msg += " HTTP/1.0";
   msg += "\r\n";
   msg += gUserAgent;
   msg += "\r\n\r\n";
   TSocket s(fUrl.GetHost(), fUrl.GetPort());
   if (!s.IsValid()) {
      Error("GetHead", "cannot connect to remote host %s", fUrl.GetHost());
      return -1;
   }
   if (s.SendRaw(msg.Data(), msg.Length()) == -1) {
      Error("GetHead", "error sending command to remote host %s", fUrl.GetHost());
      return -1;
   }
   char line[1024];
   Int_t n, ret = 0;
   while ((n = GetLine(&s, line, 1024)) >= 0) {
      if (n == 0) {
         if (gDebug > 0)
            Info("GetHead", "got all headers");
         return ret;
      }
      if (gDebug > 0)
         Info("GetHead", "header: %s", line);
      TString res = line;
      if (res.BeginsWith("HTTP/1.")) {
         TString scode = res(9, 3);
         Int_t code = scode.Atoi();
         if (code == 500)
            fHasModRoot = kTRUE;
         else if (code == 404)
            ret = -2;   
         else if (code > 200) {
            ret = -1;
            TString mess = res(13, 1000);
            Error("GetHead", "%s: %s (%d)", fUrl.GetUrl(), mess.Data(), code);
         }
      }
      if (res.BeginsWith("Content-Length:")) {
         TString slen = res(16, 1000);
         fSize = slen.Atoll();
      }
   }
   return ret;
}
Int_t TWebFile::GetLine(TSocket *s, char *line, Int_t size)
{
   
   
   
   
   
   char c;
   Int_t err, n = 0;
   while ((err = s->RecvRaw(&c, 1)) >= 0) {
      if (n == size-1 || c == '\n' || err == 0) {
         if (line[n-1] == '\r')
            n--;
         break;
      }
      line[n++] = c;
   }
   line[n] = '\0';
   if (err < 0) {
      Error("GetLine", "error receiving data from remote host %s", fUrl.GetHost());
      return -1;
   }
   return n;
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.