#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.