#include "TWebFile.h"
#include "TROOT.h"
#include "TSocket.h"
#include "Bytes.h"
#include "TError.h"
#include "TSystem.h"
#include "TBase64.h"
#include "TVirtualPerfStats.h"
#ifdef R__SSL
#include "TSSLSocket.h"
#endif
#include <errno.h>
#include <stdlib.h>
#ifdef WIN32
# ifndef EADDRINUSE
# define EADDRINUSE 10048
# endif
# ifndef EISCONN
# define EISCONN 10056
# endif
#endif
static const char *gUserAgent = "User-Agent: ROOT-TWebFile/1.1";
TUrl TWebFile::fgProxy;
class TWebSocket {
private:
TWebFile *fWebFile;
public:
TWebSocket(TWebFile *f);
~TWebSocket();
void ReOpen();
};
TWebSocket::TWebSocket(TWebFile *f)
{
fWebFile = f;
if (!f->fSocket)
ReOpen();
}
TWebSocket::~TWebSocket()
{
if (!fWebFile->fHTTP11) {
delete fWebFile->fSocket;
fWebFile->fSocket = 0;
}
}
void TWebSocket::ReOpen()
{
if (fWebFile->fSocket)
delete fWebFile->fSocket;
TUrl connurl;
if (fWebFile->fProxy.IsValid())
connurl = fWebFile->fProxy;
else
connurl = fWebFile->fUrl;
for (Int_t i = 0; i < 5; i++) {
if (strcmp(connurl.GetProtocol(), "https") == 0) {
#ifdef R__SSL
fWebFile->fSocket = new TSSLSocket(connurl.GetHost(), connurl.GetPort());
#else
::Error("TWebSocket::ReOpen", "library compiled without SSL, https not supported");
return;
#endif
} else
fWebFile->fSocket = new TSocket(connurl.GetHost(), connurl.GetPort());
if (!fWebFile->fSocket || !fWebFile->fSocket->IsValid()) {
delete fWebFile->fSocket;
fWebFile->fSocket = 0;
if (gSystem->GetErrno() == EADDRINUSE || gSystem->GetErrno() == EISCONN) {
gSystem->Sleep(i*10);
} else {
::Error("TWebSocket::ReOpen", "cannot connect to host %s (errno=%d)",
fWebFile->fUrl.GetHost(), gSystem->GetErrno());
return;
}
} else
return;
}
}
ClassImp(TWebFile)
TWebFile::TWebFile(const char *url, Option_t *opt) : TFile(url, "WEB")
{
TString option = opt;
fNoProxy = kFALSE;
if (option.Contains("NOPROXY", TString::kIgnoreCase))
fNoProxy = kTRUE;
CheckProxy();
Bool_t headOnly = kFALSE;
if (option.Contains("HEADONLY", TString::kIgnoreCase))
headOnly = kTRUE;
if (option == "IO")
return;
Init(headOnly);
}
TWebFile::TWebFile(TUrl url, Option_t *opt) : TFile(url.GetUrl(), "WEB")
{
TString option = opt;
fNoProxy = kFALSE;
if (option.Contains("NOPROXY", TString::kIgnoreCase))
fNoProxy = kTRUE;
CheckProxy();
Bool_t headOnly = kFALSE;
if (option.Contains("HEADONLY", TString::kIgnoreCase))
headOnly = kTRUE;
Init(headOnly);
}
TWebFile::~TWebFile()
{
delete fSocket;
}
void TWebFile::Init(Bool_t readHeadOnly)
{
char buf[4];
int err;
fSocket = 0;
fSize = -1;
fHasModRoot = kFALSE;
fHTTP11 = kFALSE;
SetMsgReadBuffer10();
if ((err = GetHead()) < 0) {
if (readHeadOnly) {
fD = -1;
fWritten = err;
return;
}
if (err == -2) {
Error("TWebFile", "%s does not exist", fBasicUrl.Data());
MakeZombie();
gDirectory = gROOT;
return;
}
}
if (readHeadOnly) {
fD = -1;
return;
}
if (fIsRootFile) {
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", fBasicUrl.Data());
MakeZombie();
gDirectory = gROOT;
return;
}
}
TFile::Init(kFALSE);
fD = -2;
}
void TWebFile::SetMsgReadBuffer10(const char *redirectLocation, Bool_t tempRedirect)
{
TUrl oldUrl;
TString oldBasicUrl;
if (redirectLocation) {
if (tempRedirect) {
fUrlOrg = fUrl;
fBasicUrlOrg = fBasicUrl;
} else {
fUrlOrg = "";
fBasicUrlOrg = "";
}
oldUrl = fUrl;
oldBasicUrl = fBasicUrl;
fUrl.SetUrl(redirectLocation);
fBasicUrl = fUrl.GetProtocol();
fBasicUrl += "://";
fBasicUrl += fUrl.GetHost();
fBasicUrl += ":";
fBasicUrl += fUrl.GetPort();
fBasicUrl += "/";
fBasicUrl += fUrl.GetFile();
TString rdl(redirectLocation);
if (rdl.Index("?") >= 0) {
rdl = rdl(rdl.Index("?"), rdl.Length());
fBasicUrl += rdl;
}
}
if (fMsgReadBuffer10 != "") {
if (oldBasicUrl != "") {
fMsgReadBuffer10.ReplaceAll(oldBasicUrl, fBasicUrl);
fMsgReadBuffer10.ReplaceAll(TString("Host: ")+oldUrl.GetHost(), TString("Host: ")+fUrl.GetHost());
} else if (fBasicUrlOrg != "") {
fMsgReadBuffer10.ReplaceAll(fBasicUrl, fBasicUrlOrg);
fMsgReadBuffer10.ReplaceAll(TString("Host: ")+fUrl.GetHost(), TString("Host: ")+fUrlOrg.GetHost());
fUrl = fUrlOrg;
fBasicUrl = fBasicUrlOrg;
fUrlOrg = "";
fBasicUrlOrg = "";
}
}
if (fBasicUrl == "") {
fBasicUrl += fUrl.GetProtocol();
fBasicUrl += "://";
fBasicUrl += fUrl.GetHost();
fBasicUrl += ":";
fBasicUrl += fUrl.GetPort();
fBasicUrl += "/";
fBasicUrl += fUrl.GetFile();
fBasicUrl += "?";
fBasicUrl += fUrl.GetOptions();
}
if (fMsgReadBuffer10 == "") {
fMsgReadBuffer10 = "GET ";
fMsgReadBuffer10 += fBasicUrl;
if (fHTTP11)
fMsgReadBuffer10 += " HTTP/1.1";
else
fMsgReadBuffer10 += " HTTP/1.0";
fMsgReadBuffer10 += "\r\n";
if (fHTTP11) {
fMsgReadBuffer10 += "Host: ";
fMsgReadBuffer10 += fUrl.GetHost();
fMsgReadBuffer10 += "\r\n";
}
fMsgReadBuffer10 += BasicAuthentication();
fMsgReadBuffer10 += gUserAgent;
fMsgReadBuffer10 += "\r\n";
fMsgReadBuffer10 += "Range: bytes=";
}
}
void TWebFile::CheckProxy()
{
if (fNoProxy)
return;
if (fgProxy.IsValid()) {
fProxy = fgProxy;
return;
}
TString proxy = gSystem->Getenv("http_proxy");
if (proxy != "") {
TUrl p(proxy);
if (strcmp(p.GetProtocol(), "http")) {
Error("CheckProxy", "protocol must be HTTP in proxy URL %s",
proxy.Data());
return;
}
fProxy = p;
if (gDebug > 0)
Info("CheckProxy", "using HTTP proxy %s", fProxy.GetUrl());
}
}
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);
if (fMsgReadBuffer == "") {
fMsgReadBuffer = "GET ";
fMsgReadBuffer += fBasicUrl;
fMsgReadBuffer += "?";
}
TString msg = fMsgReadBuffer;
msg += fOffset;
msg += ":";
msg += len;
msg += "\r\n";
if (GetFromWeb(buf, len, msg) == -1)
return kTRUE;
fOffset += len;
return kFALSE;
}
Bool_t TWebFile::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
SetOffset(pos);
return ReadBuffer(buf, len);
}
Bool_t TWebFile::ReadBuffer10(char *buf, Int_t len)
{
SetMsgReadBuffer10();
TString msg = fMsgReadBuffer10;
msg += fOffset;
msg += "-";
msg += fOffset+len-1;
msg += "\r\n\r\n";
Int_t n = GetFromWeb10(buf, len, msg);
if (n == -1)
return kTRUE;
if (n == -2) {
Error("ReadBuffer10", "%s does not exist", fBasicUrl.Data());
MakeZombie();
gDirectory = gROOT;
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);
if (fMsgReadBuffer == "") {
fMsgReadBuffer = "GET ";
fMsgReadBuffer += fBasicUrl;
fMsgReadBuffer += "?";
}
TString msg = fMsgReadBuffer;
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 = fMsgReadBuffer;
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)
{
SetMsgReadBuffer10();
TString msg = fMsgReadBuffer10;
Int_t k = 0, n = 0, r;
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";
r = GetFromWeb10(&buf[k], n, msg);
if (r == -1)
return kTRUE;
msg = fMsgReadBuffer10;
k += n;
n = 0;
}
}
msg += "\r\n\r\n";
r = GetFromWeb10(&buf[k], n, msg);
if (r == -1)
return kTRUE;
return kFALSE;
}
Int_t TWebFile::GetFromWeb(char *buf, Int_t len, const TString &msg)
{
TSocket *s;
if (!len) return 0;
Double_t start = 0;
if (gPerfStats) start = TTimeStamp();
TUrl connurl;
if (fProxy.IsValid())
connurl = fProxy;
else
connurl = fUrl;
if (strcmp(connurl.GetProtocol(), "https") == 0) {
#ifdef R__SSL
s = new TSSLSocket(connurl.GetHost(), connurl.GetPort());
#else
Error("GetFromWeb", "library compiled without SSL, https not supported");
return -1;
#endif
} else
s = new TSocket(connurl.GetHost(), connurl.GetPort());
if (!s->IsValid()) {
Error("GetFromWeb", "cannot connect to host %s", fUrl.GetHost());
delete s;
return -1;
}
if (s->SendRaw(msg.Data(), msg.Length()) == -1) {
Error("GetFromWeb", "error sending command to host %s", fUrl.GetHost());
delete s;
return -1;
}
if (s->RecvRaw(buf, len) == -1) {
Error("GetFromWeb", "error receiving data from host %s", fUrl.GetHost());
delete s;
return -1;
}
fBytesRead += len;
fReadCalls++;
#ifdef R__WIN32
SetFileBytesRead(GetFileBytesRead() + len);
SetFileReadCalls(GetFileReadCalls() + 1);
#else
fgBytesRead += len;
fgReadCalls++;
#endif
if (gPerfStats)
gPerfStats->FileReadEvent(this, len, start);
delete s;
return 0;
}
Int_t TWebFile::GetFromWeb10(char *buf, Int_t len, const TString &msg)
{
if (!len) return 0;
Double_t start = 0;
if (gPerfStats) start = TTimeStamp();
TWebSocket ws(this);
if (!fSocket || !fSocket->IsValid()) {
Error("GetFromWeb10", "cannot connect to host %s", fUrl.GetHost());
return -1;
}
if (gDebug > 0)
Info("GetFromWeb10", "sending HTTP request:\n%s", msg.Data());
if (fSocket->SendRaw(msg.Data(), msg.Length()) == -1) {
Error("GetFromWeb10", "error sending command to host %s", fUrl.GetHost());
return -1;
}
char line[8192];
Int_t n, ret = 0, nranges = 0, ltot = 0, redirect = 0;
TString boundary, boundaryEnd;
Long64_t first = -1, last = -1, tot;
while ((n = GetLine(fSocket, line, sizeof(line))) >= 0) {
if (n == 0) {
if (ret < 0)
return ret;
if (redirect) {
ws.ReOpen();
TString msg_1 = fMsgReadBuffer10;
msg_1 += fOffset;
msg_1 += "-";
msg_1 += fOffset+len-1;
msg_1 += "\r\n\r\n";
return GetFromWeb10(buf, len, msg_1);
}
if (first >= 0) {
Int_t ll = Int_t(last - first) + 1;
Int_t rsize;
if ((rsize = fSocket->RecvRaw(&buf[ltot], ll)) == -1) {
Error("GetFromWeb10", "error receiving data from host %s", fUrl.GetHost());
return -1;
}
else if (ll != rsize) {
Error("GetFromWeb10", "expected %d bytes, got %d", ll, rsize);
return -1;
}
ltot += 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.")) {
if (res.BeginsWith("HTTP/1.1")) {
if (!fHTTP11)
fMsgReadBuffer10 = "";
fHTTP11 = kTRUE;
}
TString scode = res(9, 3);
Int_t code = scode.Atoi();
if (code >= 500) {
ret = -1;
TString mess = res(13, 1000);
Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
} else if (code >= 400) {
if (code == 404)
ret = -2;
else {
ret = -1;
TString mess = res(13, 1000);
Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
} else if (code >= 300) {
if (code == 301 || code == 303) {
redirect = 1;
} else if (code == 302 || code == 307) {
redirect = 1;
} else {
ret = -1;
TString mess = res(13, 1000);
Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
} else if (code > 200) {
if (code != 206) {
ret = -1;
TString mess = res(13, 1000);
Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
}
} else if (res.BeginsWith("Content-Type: multipart")) {
boundary = res(res.Index("boundary=")+9, 1000);
if (boundary[0]=='"' && boundary[boundary.Length()-1]=='"') {
boundary = boundary(1,boundary.Length()-2);
}
boundary = "--" + boundary;
boundaryEnd = boundary + "--";
} else if (res.BeginsWith("Content-range:")) {
#ifdef R__WIN32
sscanf(res.Data(), "Content-range: bytes %I64d-%I64d/%I64d", &first, &last, &tot);
#else
sscanf(res.Data(), "Content-range: bytes %lld-%lld/%lld", &first, &last, &tot);
#endif
if (fSize == -1) fSize = tot;
} else if (res.BeginsWith("Content-Range:")) {
#ifdef R__WIN32
sscanf(res.Data(), "Content-Range: bytes %I64d-%I64d/%I64d", &first, &last, &tot);
#else
sscanf(res.Data(), "Content-Range: bytes %lld-%lld/%lld", &first, &last, &tot);
#endif
if (fSize == -1) fSize = tot;
} else if (res.BeginsWith("Location:") && redirect) {
TString redir = res(10, 1000);
if (redirect == 2)
SetMsgReadBuffer10(redir, kTRUE);
else
SetMsgReadBuffer10(redir, kFALSE);
}
}
if (n == -1 && fHTTP11) {
if (gDebug > 0)
Info("GetFromWeb10", "HTTP/1.1 socket closed, reopen");
if (fBasicUrlOrg != "") {
SetMsgReadBuffer10();
}
ws.ReOpen();
return GetFromWeb10(buf, len, msg);
}
if (ltot != len) {
Error("GetFromWeb10", "error receiving expected amount of data (got %d, expected %d) from host %s",
ltot, len, fUrl.GetHost());
return -1;
}
fBytesRead += len;
fReadCalls++;
#ifdef R__WIN32
SetFileBytesRead(GetFileBytesRead() + len);
SetFileReadCalls(GetFileReadCalls() + 1);
#else
fgBytesRead += len;
fgReadCalls++;
#endif
if (gPerfStats)
gPerfStats->FileReadEvent(this, len, start);
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 += fBasicUrl;
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()
{
if (fMsgGetHead == "") {
fMsgGetHead = "HEAD ";
fMsgGetHead += fBasicUrl;
if (fHTTP11)
fMsgGetHead += " HTTP/1.1";
else
fMsgGetHead += " HTTP/1.0";
fMsgGetHead += "\r\n";
if (fHTTP11) {
fMsgGetHead += "Host: ";
fMsgGetHead += fUrl.GetHost();
fMsgGetHead += "\r\n";
}
fMsgGetHead += BasicAuthentication();
fMsgGetHead += gUserAgent;
fMsgGetHead += "\r\n\r\n";
}
TString msg = fMsgGetHead;
TUrl connurl;
if (fProxy.IsValid())
connurl = fProxy;
else
connurl = fUrl;
TSocket *s = 0;
for (Int_t i = 0; i < 5; i++) {
if (strcmp(connurl.GetProtocol(), "https") == 0) {
#ifdef R__SSL
s = new TSSLSocket(connurl.GetHost(), connurl.GetPort());
#else
Error("GetHead", "library compiled without SSL, https not supported");
return -1;
#endif
} else
s = new TSocket(connurl.GetHost(), connurl.GetPort());
if (!s->IsValid()) {
delete s;
if (gSystem->GetErrno() == EADDRINUSE || gSystem->GetErrno() == EISCONN) {
s = 0;
gSystem->Sleep(i*10);
} else {
Error("GetHead", "cannot connect to host %s (errno=%d)", fUrl.GetHost(),
gSystem->GetErrno());
return -1;
}
} else
break;
}
if (!s)
return -1;
if (gDebug > 0) {
Info("GetHead", "connected to host %s", connurl.GetHost());
Info("GetHead", "sending HTTP request:\n%s", msg.Data());
}
if (s->SendRaw(msg.Data(), msg.Length()) == -1) {
Error("GetHead", "error sending command to host %s", fUrl.GetHost());
delete s;
return -1;
}
char line[8192];
Int_t n, ret = 0, redirect = 0;
while ((n = GetLine(s, line, sizeof(line))) >= 0) {
if (n == 0) {
if (gDebug > 0)
Info("GetHead", "got all headers");
delete s;
if (fBasicUrlOrg != "" && !redirect) {
SetMsgReadBuffer10();
fMsgGetHead = "";
}
if (ret < 0)
return ret;
if (redirect)
return GetHead();
return 0;
}
if (gDebug > 0)
Info("GetHead", "header: %s", line);
TString res = line;
ProcessHttpHeader(res);
if (res.BeginsWith("HTTP/1.")) {
if (res.BeginsWith("HTTP/1.1")) {
if (!fHTTP11) {
fMsgGetHead = "";
fMsgReadBuffer10 = "";
}
fHTTP11 = kTRUE;
}
TString scode = res(9, 3);
Int_t code = scode.Atoi();
if (code >= 500) {
if (code == 500)
fHasModRoot = kTRUE;
else {
ret = -1;
TString mess = res(13, 1000);
Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
} else if (code >= 400) {
if (code == 400)
ret = -3;
else if (code == 404)
ret = -2;
else {
ret = -1;
TString mess = res(13, 1000);
Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
} else if (code >= 300) {
if (code == 301 || code == 303)
redirect = 1;
else if (code == 302 || code == 307)
redirect = 2;
else {
ret = -1;
TString mess = res(13, 1000);
Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
} else if (code > 200) {
ret = -1;
TString mess = res(13, 1000);
Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
}
} else if (res.BeginsWith("Content-Length:")) {
TString slen = res(16, 1000);
fSize = slen.Atoll();
} else if (res.BeginsWith("Location:") && redirect) {
TString redir = res(10, 1000);
if (redirect == 2)
SetMsgReadBuffer10(redir, kTRUE);
else
SetMsgReadBuffer10(redir, kFALSE);
fMsgGetHead = "";
}
}
delete s;
return ret;
}
Int_t TWebFile::GetLine(TSocket *s, char *line, Int_t maxsize)
{
Int_t n = GetHunk(s, line, maxsize);
if (n < 0) {
if (!fHTTP11 || gDebug > 0)
Error("GetLine", "error receiving data from host %s", fUrl.GetHost());
return -1;
}
if (n > 0 && line[n-1] == '\n') {
n--;
if (n > 0 && line[n-1] == '\r')
n--;
line[n] = '\0';
}
return n;
}
Int_t TWebFile::GetHunk(TSocket *s, char *hunk, Int_t maxsize)
{
if (maxsize <= 0) return 0;
Int_t bufsize = maxsize;
Int_t tail = 0;
while (1) {
const char *end;
Int_t pklen, rdlen, remain;
pklen = s->RecvRaw(hunk+tail, bufsize-1-tail, kPeek);
if (pklen < 0) {
return -1;
}
end = HttpTerminator(hunk, hunk+tail, pklen);
if (end) {
remain = end - (hunk + tail);
if (remain == 0) {
hunk[tail] = '\0';
return tail;
}
if (bufsize - 1 < tail + remain) {
Error("GetHunk", "hunk buffer too small for data from host %s (%d bytes needed)",
fUrl.GetHost(), tail + remain + 1);
hunk[tail] = '\0';
return -1;
}
} else {
remain = pklen;
}
rdlen = s->RecvRaw(hunk+tail, remain, kDontBlock);
if (rdlen < 0) {
return -1;
}
tail += rdlen;
hunk[tail] = '\0';
if (rdlen == 0) {
if (tail == 0) {
return tail;
} else {
return tail;
}
}
if (end && rdlen == remain) {
return tail;
}
if (tail == bufsize - 1) {
Error("GetHunk", "hunk buffer too small for data from host %s",
fUrl.GetHost());
return -1;
}
}
}
const char *TWebFile::HttpTerminator(const char *start, const char *peeked,
Int_t peeklen)
{
#if 0
const char *p, *end;
p = peeked - start < 1 ? start : peeked - 1;
end = peeked + peeklen;
for (; p < end - 1; p++)
if (p[0] == '\r' && p[1] == '\n')
return p + 2;
if (p[0] == '\r' && p[1] == '\n')
return p + 2;
#else
if (start) { }
const char *p = (const char*) memchr(peeked, '\n', peeklen);
if (p)
return p + 1;
#endif
return 0;
}
TString TWebFile::BasicAuthentication()
{
TString msg;
if (strlen(fUrl.GetUser())) {
TString auth = fUrl.GetUser();
if (strlen(fUrl.GetPasswd())) {
auth += ":";
auth += fUrl.GetPasswd();
}
msg += "Authorization: Basic ";
msg += TBase64::Encode(auth);
msg += "\r\n";
}
return msg;
}
void TWebFile::SetProxy(const char *proxy)
{
if (proxy && *proxy) {
TUrl p(proxy);
if (strcmp(p.GetProtocol(), "http")) {
:: Error("TWebFile::SetProxy", "protocol must be HTTP in proxy URL %s",
proxy);
return;
}
fgProxy = p;
}
}
const char *TWebFile::GetProxy()
{
if (fgProxy.IsValid())
return fgProxy.GetUrl();
return "";
}
void TWebFile::ProcessHttpHeader(const TString&)
{
}
TWebSystem::TWebSystem() : TSystem("-http", "HTTP Helper System")
{
SetName("http");
fDirp = 0;
}
Int_t TWebSystem::MakeDirectory(const char *)
{
return -1;
}
void *TWebSystem::OpenDirectory(const char *)
{
if (fDirp) {
Error("OpenDirectory", "invalid directory pointer (should never happen)");
fDirp = 0;
}
fDirp = 0;
return fDirp;
}
void TWebSystem::FreeDirectory(void *dirp)
{
if (dirp != fDirp) {
Error("FreeDirectory", "invalid directory pointer (should never happen)");
return;
}
fDirp = 0;
}
const char *TWebSystem::GetDirEntry(void *dirp)
{
if (dirp != fDirp) {
Error("GetDirEntry", "invalid directory pointer (should never happen)");
return 0;
}
return 0;
}
Int_t TWebSystem::GetPathInfo(const char *path, FileStat_t &buf)
{
TWebFile *f = new TWebFile(path, "HEADONLY");
if (f->fWritten == 0) {
buf.fDev = 0;
buf.fIno = 0;
buf.fMode = 0;
buf.fUid = 0;
buf.fGid = 0;
buf.fSize = f->GetSize();
buf.fMtime = 0;
buf.fIsLink = kFALSE;
delete f;
return 0;
}
delete f;
return 1;
}
Bool_t TWebSystem::AccessPathName(const char *path, EAccessMode)
{
TWebFile *f = new TWebFile(path, "HEADONLY");
if (f->fWritten == 0) {
delete f;
return kFALSE;
}
delete f;
return kTRUE;
}
Int_t TWebSystem::Unlink(const char *)
{
return -1;
}