Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TWebFile.cxx
Go to the documentation of this file.
1// @(#)root/net:$Id$
2// Author: Fons Rademakers 17/01/97
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//////////////////////////////////////////////////////////////////////////
13// //
14// TWebFile //
15// //
16// A TWebFile is like a normal TFile except that it reads its data //
17// via a standard apache web server. A TWebFile is a read-only file. //
18// //
19//////////////////////////////////////////////////////////////////////////
20
21#include "TWebFile.h"
22#include "TROOT.h"
23#include "TSocket.h"
24#include "Bytes.h"
25#include "TError.h"
26#include "TSystem.h"
27#include "TBase64.h"
28#include "TVirtualPerfStats.h"
29#ifdef R__SSL
30#include "TSSLSocket.h"
31#endif
32
33#include <cerrno>
34#include <cstdlib>
35#include <cstring>
36
37#ifdef WIN32
38# ifndef EADDRINUSE
39# define EADDRINUSE 10048
40# endif
41# ifndef EISCONN
42# define EISCONN 10056
43# endif
44#endif
45
46static const char *gUserAgent = "User-Agent: ROOT-TWebFile/1.1";
47
49
51
52namespace ROOT::Deprecated {
53
54// Internal class used to manage the socket that may stay open between
55// calls when HTTP/1.1 protocol is used
57private:
58 TWebFile *fWebFile; // associated web file
59public:
62 void ReOpen();
63};
64
65} // namespace ROOT::Deprecated
66
67////////////////////////////////////////////////////////////////////////////////
68/// Open web file socket.
69
71{
72 fWebFile = f;
73 if (!f->fSocket)
74 ReOpen();
75}
76
77////////////////////////////////////////////////////////////////////////////////
78/// Close socket in case not HTTP/1.1 protocol or when explicitly requested.
79
81{
82 if (!fWebFile->fHTTP11) {
83 delete fWebFile->fSocket;
84 fWebFile->fSocket = nullptr;
85 }
86}
87
88////////////////////////////////////////////////////////////////////////////////
89/// Re-open web file socket.
90
92{
93 if (fWebFile->fSocket) {
94 delete fWebFile->fSocket;
95 fWebFile->fSocket = nullptr;
96 }
97
99 if (fWebFile->fProxy.IsValid())
100 connurl = fWebFile->fProxy;
101 else
102 connurl = fWebFile->fUrl;
103
104 for (Int_t i = 0; i < 5; i++) {
105 if (strcmp(connurl.GetProtocol(), "https") == 0) {
106#ifdef R__SSL
107 fWebFile->fSocket = new TSSLSocket(connurl.GetHost(), connurl.GetPort());
108#else
109 ::Error("TWebSocket::ReOpen", "library compiled without SSL, https not supported");
110 return;
111#endif
112 } else
113 fWebFile->fSocket = new TSocket(connurl.GetHost(), connurl.GetPort());
114
115 if (!fWebFile->fSocket || !fWebFile->fSocket->IsValid()) {
116 delete fWebFile->fSocket;
117 fWebFile->fSocket = nullptr;
118 if (gSystem->GetErrno() == EADDRINUSE || gSystem->GetErrno() == EISCONN) {
119 gSystem->Sleep(i*10);
120 } else {
121 ::Error("TWebSocket::ReOpen", "cannot connect to host %s (errno=%d)",
122 fWebFile->fUrl.GetHost(), gSystem->GetErrno());
123 return;
124 }
125 } else
126 return;
127 }
128}
129
130
131
132////////////////////////////////////////////////////////////////////////////////
133/// Create a Web file object. A web file is the same as a read-only
134/// TFile except that it is being read via a HTTP server. The url
135/// argument must be of the form: http://host.dom.ain/file.root.
136/// The opt can be "NOPROXY", to bypass any set "http_proxy" shell
137/// variable. The proxy can be specified as (in sh, or equivalent csh):
138/// export http_proxy=http://pcsalo.cern.ch:3128
139/// The proxy can also be specified via the static method TWebFile::SetProxy().
140/// Basic authentication (AuthType Basic) is supported. The user name and
141/// passwd can be specified in the url like this:
142/// http://username:mypasswd@pcsalo.cern.ch/files/aap.root
143/// If the file specified in the URL does not exist or is not accessible
144/// the kZombie bit will be set in the TWebFile object. Use IsZombie()
145/// to see if the file is accessible. The preferred interface to this
146/// constructor is via TFile::Open().
147
149 : TFile(url, strstr(opt, "_WITHOUT_GLOBALREGISTRATION") != nullptr ? "WEB_WITHOUT_GLOBALREGISTRATION" : "WEB"),
150 fSocket(0)
151{
152 TString option = opt;
154 if (option.Contains("NOPROXY", TString::kIgnoreCase))
155 fNoProxy = kTRUE;
156 CheckProxy();
157
159 if (option.Contains("HEADONLY", TString::kIgnoreCase))
160 headOnly = kTRUE;
161
162 if (option == "IO")
163 return;
164
165 Init(headOnly);
166}
167
168////////////////////////////////////////////////////////////////////////////////
169/// Create a Web file object. A web file is the same as a read-only
170/// TFile except that it is being read via a HTTP server. Make sure url
171/// is a valid TUrl object.
172/// The opt can be "NOPROXY", to bypass any set "http_proxy" shell
173/// variable. The proxy can be specified as (in sh, or equivalent csh):
174/// export http_proxy=http://pcsalo.cern.ch:3128
175/// The proxy can also be specified via the static method TWebFile::SetProxy().
176/// Basic authentication (AuthType Basic) is supported. The user name and
177/// passwd can be specified in the url like this:
178/// http://username:mypasswd@pcsalo.cern.ch/files/aap.root
179/// If the file specified in the URL does not exist or is not accessible
180/// the kZombie bit will be set in the TWebFile object. Use IsZombie()
181/// to see if the file is accessible.
182
183ROOT::Deprecated::TWebFile::TWebFile(TUrl url, Option_t *opt) : TFile(url.GetUrl(), "WEB"), fSocket(0)
184{
185 TString option = opt;
187 if (option.Contains("NOPROXY", TString::kIgnoreCase))
188 fNoProxy = kTRUE;
189 CheckProxy();
190
192 if (option.Contains("HEADONLY", TString::kIgnoreCase))
193 headOnly = kTRUE;
194
195 Init(headOnly);
196}
197
198////////////////////////////////////////////////////////////////////////////////
199/// Cleanup.
200
202{
203 delete fSocket;
204 if (fFullCache) {
205 free(fFullCache);
206 fFullCache = nullptr;
207 fFullCacheSize = 0;
208 }
209}
210
211////////////////////////////////////////////////////////////////////////////////
212/// Initialize a TWebFile object.
213
215{
216 char buf[4];
217 int err;
218
219 fSocket = nullptr;
220 fSize = -1;
221 fHasModRoot = kFALSE;
222#if defined(R__WIN32) && defined(R__SSL)
223 fHTTP11 = kTRUE;
224#else
225 fHTTP11 = kFALSE;
226#endif
227 fFullCache = nullptr;
228 fFullCacheSize = 0;
229 SetMsgReadBuffer10();
230
231 if ((err = GetHead()) < 0) {
232 if (readHeadOnly) {
233 fD = -1;
234 fWritten = err;
235 return;
236 }
237 if (err == -2) {
238 Error("TWebFile", "%s does not exist", fBasicUrl.Data());
239 MakeZombie();
241 return;
242 }
243 // err == -3 HEAD not supported, fall through and try ReadBuffer()
244 }
245 if (readHeadOnly) {
246 fD = -1;
247 return;
248 }
249
250 if (fIsRootFile) {
251 Seek(0);
252 if (ReadBuffer(buf, 4)) {
253 MakeZombie();
255 return;
256 }
257
258 if (strncmp(buf, "root", 4) && strncmp(buf, "PK", 2)) { // PK is zip file
259 Error("TWebFile", "%s is not a ROOT file", fBasicUrl.Data());
260 MakeZombie();
262 return;
263 }
264 }
265
267 fD = -2; // so TFile::IsOpen() will return true when in TFile::~TFile
268}
269
270////////////////////////////////////////////////////////////////////////////////
271/// Set GET command for use by ReadBuffer(s)10(), handle redirection if
272/// needed. Give full URL so Apache's virtual hosts solution works.
273
275{
276 TUrl oldUrl;
278
279 if (redirectLocation) {
280 if (tempRedirect) { // temp redirect
281 fUrlOrg = fUrl;
282 fBasicUrlOrg = fBasicUrl;
283 } else { // permanent redirect
284 fUrlOrg = "";
285 fBasicUrlOrg = "";
286 }
287
288 oldUrl = fUrl;
289 oldBasicUrl = fBasicUrl;
290
291 fUrl.SetUrl(redirectLocation);
292 fBasicUrl = fUrl.GetProtocol();
293 fBasicUrl += "://";
294 fBasicUrl += fUrl.GetHost();
295 fBasicUrl += ":";
296 fBasicUrl += fUrl.GetPort();
297 fBasicUrl += "/";
298 fBasicUrl += fUrl.GetFile();
299 // add query string again
301 if (rdl.Index("?") >= 0) {
302 rdl = rdl(rdl.Index("?"), rdl.Length());
303 fBasicUrl += rdl;
304 }
305 }
306
307 if (fMsgReadBuffer10 != "") {
308 // patch up existing command
309 if (oldBasicUrl != "") {
310 // change to redirection location
311 fMsgReadBuffer10.ReplaceAll(oldBasicUrl, fBasicUrl);
312 fMsgReadBuffer10.ReplaceAll(TString("Host: ")+oldUrl.GetHost(), TString("Host: ")+fUrl.GetHost());
313 } else if (fBasicUrlOrg != "") {
314 // change back from temp redirection location
315 fMsgReadBuffer10.ReplaceAll(fBasicUrl, fBasicUrlOrg);
316 fMsgReadBuffer10.ReplaceAll(TString("Host: ")+fUrl.GetHost(), TString("Host: ")+fUrlOrg.GetHost());
317 fUrl = fUrlOrg;
318 fBasicUrl = fBasicUrlOrg;
319 fUrlOrg = "";
320 fBasicUrlOrg = "";
321 }
322 }
323
324 if (fBasicUrl == "") {
325 fBasicUrl += fUrl.GetProtocol();
326 fBasicUrl += "://";
327 fBasicUrl += fUrl.GetHost();
328 fBasicUrl += ":";
329 fBasicUrl += fUrl.GetPort();
330 fBasicUrl += "/";
331 fBasicUrl += fUrl.GetFile();
332 if (strlen(fUrl.GetOptions())) {
333 fBasicUrl += "?";
334 fBasicUrl += fUrl.GetOptions();
335 }
336 }
337
338 if (fMsgReadBuffer10 == "") {
339 fMsgReadBuffer10 = "GET ";
340 fMsgReadBuffer10 += fBasicUrl;
341 if (fHTTP11)
342 fMsgReadBuffer10 += " HTTP/1.1";
343 else
344 fMsgReadBuffer10 += " HTTP/1.0";
345 fMsgReadBuffer10 += "\r\n";
346 if (fHTTP11) {
347 fMsgReadBuffer10 += "Host: ";
348 fMsgReadBuffer10 += fUrl.GetHost();
349 fMsgReadBuffer10 += "\r\n";
350 }
351 fMsgReadBuffer10 += BasicAuthentication();
352 fMsgReadBuffer10 += gUserAgent;
353 fMsgReadBuffer10 += "\r\n";
354 fMsgReadBuffer10 += "Range: bytes=";
355 }
356}
357
358////////////////////////////////////////////////////////////////////////////////
359/// Check if shell var "http_proxy" has been set and should be used.
360
362{
363 if (fNoProxy)
364 return;
365
366 if (fgProxy.IsValid()) {
367 fProxy = fgProxy;
368 return;
369 }
370
371 TString proxy = gSystem->Getenv("http_proxy");
372 if (proxy != "") {
373 TUrl p(proxy);
374 if (strcmp(p.GetProtocol(), "http")) {
375 Error("CheckProxy", "protocol must be HTTP in proxy URL %s",
376 proxy.Data());
377 return;
378 }
379 fProxy = p;
380 if (gDebug > 0)
381 Info("CheckProxy", "using HTTP proxy %s", fProxy.GetUrl());
382 }
383}
384
385////////////////////////////////////////////////////////////////////////////////
386/// A TWebFile that has been correctly constructed is always considered open.
387
389{
390 return IsZombie() ? kFALSE : kTRUE;
391}
392
393////////////////////////////////////////////////////////////////////////////////
394/// Reopen a file with a different access mode, like from READ to
395/// UPDATE or from NEW, CREATE, RECREATE, UPDATE to READ. Thus the
396/// mode argument can be either "READ" or "UPDATE". The method returns
397/// 0 in case the mode was successfully modified, 1 in case the mode
398/// did not change (was already as requested or wrong input arguments)
399/// and -1 in case of failure, in which case the file cannot be used
400/// anymore. A TWebFile cannot be reopened in update mode.
401
403{
404 TString opt = mode;
405 opt.ToUpper();
406
407 if (opt != "READ" && opt != "UPDATE")
408 Error("ReOpen", "mode must be either READ or UPDATE, not %s", opt.Data());
409
410 if (opt == "UPDATE")
411 Error("ReOpen", "update mode not allowed for a TWebFile");
412
413 return 1;
414}
415
416////////////////////////////////////////////////////////////////////////////////
417/// Close a Web file. Close the socket connection and delete the cache
418/// See also the TFile::Close() function
419
421{
422 delete fSocket;
423 fSocket = nullptr;
424 if (fFullCache) {
425 free(fFullCache);
426 fFullCache = nullptr;
427 fFullCacheSize = 0;
428 }
429 return TFile::Close(option);
430}
431
432////////////////////////////////////////////////////////////////////////////////
433/// Read specified byte range from remote file via HTTP daemon. This
434/// routine connects to the remote host, sends the request and returns
435/// the buffer. Returns kTRUE in case of error.
436
438{
439 Int_t st;
440 if ((st = ReadBufferViaCache(buf, len))) {
441 if (st == 2)
442 return kTRUE;
443 return kFALSE;
444 }
445
446 if (!fHasModRoot)
447 return ReadBuffer10(buf, len);
448
449 // Give full URL so Apache's virtual hosts solution works.
450 // Use protocol 0.9 for efficiency, we are not interested in the 1.0 headers.
451 if (fMsgReadBuffer == "") {
452 fMsgReadBuffer = "GET ";
453 fMsgReadBuffer += fBasicUrl;
454 fMsgReadBuffer += "?";
455 }
456 TString msg = fMsgReadBuffer;
457 msg += fOffset;
458 msg += ":";
459 msg += len;
460 msg += "\r\n";
461
462 if (GetFromWeb(buf, len, msg) == -1)
463 return kTRUE;
464
465 fOffset += len;
466
467 return kFALSE;
468}
469
470////////////////////////////////////////////////////////////////////////////////
471/// Read specified byte range from remote file via HTTP daemon. This
472/// routine connects to the remote host, sends the request and returns
473/// the buffer. Returns kTRUE in case of error.
474
476{
477 SetOffset(pos);
478 return ReadBuffer(buf, len);
479}
480
481////////////////////////////////////////////////////////////////////////////////
482/// Read specified byte range from remote file via HTTP 1.0 daemon (without
483/// mod-root installed). This routine connects to the remote host, sends the
484/// request and returns the buffer. Returns kTRUE in case of error.
485
487{
488 SetMsgReadBuffer10();
489
490 TString msg = fMsgReadBuffer10;
491 msg += fOffset;
492 msg += "-";
493 msg += fOffset+len-1;
494 msg += "\r\n\r\n";
495
496 Long64_t apos = fOffset - fArchiveOffset;
497
498 // in case when server does not support segments, let chance to recover
499 Int_t n = GetFromWeb10(buf, len, msg, 1, &apos, &len);
500 if (n == -1)
501 return kTRUE;
502 // The -2 error condition typically only happens when
503 // GetHead() failed because not implemented, in the first call to
504 // ReadBuffer() in Init(), it is not checked in ReadBuffers10().
505 if (n == -2) {
506 Error("ReadBuffer10", "%s does not exist", fBasicUrl.Data());
507 MakeZombie();
509 return kTRUE;
510 }
511
512 fOffset += len;
513
514 return kFALSE;
515}
516
517////////////////////////////////////////////////////////////////////////////////
518/// Read specified byte ranges from remote file via HTTP daemon.
519/// Reads the nbuf blocks described in arrays pos and len,
520/// where pos[i] is the seek position of block i of length len[i].
521/// Note that for nbuf=1, this call is equivalent to TFile::ReafBuffer
522/// This function is overloaded by TNetFile, TWebFile, etc.
523/// Returns kTRUE in case of failure.
524
526{
527 if (!fHasModRoot)
528 return ReadBuffers10(buf, pos, len, nbuf);
529
530 // Give full URL so Apache's virtual hosts solution works.
531 // Use protocol 0.9 for efficiency, we are not interested in the 1.0 headers.
532 if (fMsgReadBuffer == "") {
533 fMsgReadBuffer = "GET ";
534 fMsgReadBuffer += fBasicUrl;
535 fMsgReadBuffer += "?";
536 }
537 TString msg = fMsgReadBuffer;
538
539 Int_t k = 0, n = 0, cnt = 0;
540 for (Int_t i = 0; i < nbuf; i++) {
541 if (n) msg += ",";
542 msg += pos[i] + fArchiveOffset;
543 msg += ":";
544 msg += len[i];
545 n += len[i];
546 cnt++;
547 if ((msg.Length() > 8000) || (cnt >= 200)) {
548 msg += "\r\n";
549 if (GetFromWeb(&buf[k], n, msg) == -1)
550 return kTRUE;
551 msg = fMsgReadBuffer;
552 k += n;
553 n = 0;
554 cnt = 0;
555 }
556 }
557
558 msg += "\r\n";
559
560 if (GetFromWeb(&buf[k], n, msg) == -1)
561 return kTRUE;
562
563 return kFALSE;
564}
565
566////////////////////////////////////////////////////////////////////////////////
567/// Read specified byte ranges from remote file via HTTP 1.0 daemon (without
568/// mod-root installed). Read the nbuf blocks described in arrays pos and len,
569/// where pos[i] is the seek position of block i of length len[i].
570/// Note that for nbuf=1, this call is equivalent to TFile::ReafBuffer
571/// This function is overloaded by TNetFile, TWebFile, etc.
572/// Returns kTRUE in case of failure.
573
575{
576 SetMsgReadBuffer10();
577
578 TString msg = fMsgReadBuffer10;
579
580 Int_t k = 0, n = 0, r, cnt = 0;
581 for (Int_t i = 0; i < nbuf; i++) {
582 if (n) msg += ",";
583 msg += pos[i] + fArchiveOffset;
584 msg += "-";
585 msg += pos[i] + fArchiveOffset + len[i] - 1;
586 n += len[i];
587 cnt++;
588 if ((msg.Length() > 8000) || (cnt >= 200) || (i+1 == nbuf)) {
589 msg += "\r\n\r\n";
590 r = GetFromWeb10(&buf[k], n, msg, cnt, pos + (i+1-cnt), len + (i+1-cnt));
591 if (r == -1)
592 return kTRUE;
593 msg = fMsgReadBuffer10;
594 k += n;
595 n = 0;
596 cnt = 0;
597 }
598 }
599
600 return kFALSE;
601}
602
603////////////////////////////////////////////////////////////////////////////////
604/// Extract requested segments from the cached content.
605/// Such cache can be produced when server suddenly returns full data instead of segments
606/// Returns -1 in case of error, 0 in case of success
607
609{
610 if (!fFullCache) return -1;
611
612 if (gDebug > 0)
613 Info("GetFromCache", "Extract %d segments total len %d from cached data", nseg, len);
614
615 Int_t curr = 0;
616 for (Int_t cnt=0;cnt<nseg;cnt++) {
617 // check that target buffer has enough space
618 if (curr + seg_len[cnt] > len) return -1;
619 // check that segment is inside cached area
620 if (fArchiveOffset + seg_pos[cnt] + seg_len[cnt] > fFullCacheSize) return -1;
621 char* src = (char*) fFullCache + fArchiveOffset + seg_pos[cnt];
622 memcpy(buf + curr, src, seg_len[cnt]);
623 curr += seg_len[cnt];
624 }
625
626 return 0;
627}
628
629////////////////////////////////////////////////////////////////////////////////
630/// Read request from web server. Returns -1 in case of error,
631/// 0 in case of success.
632
634{
635 TSocket *s;
636
637 if (!len) return 0;
638
639 Double_t start = 0;
640 if (gPerfStats) start = TTimeStamp();
641
643 if (fProxy.IsValid())
644 connurl = fProxy;
645 else
646 connurl = fUrl;
647
648 if (strcmp(connurl.GetProtocol(), "https") == 0) {
649#ifdef R__SSL
650 s = new TSSLSocket(connurl.GetHost(), connurl.GetPort());
651#else
652 Error("GetFromWeb", "library compiled without SSL, https not supported");
653 return -1;
654#endif
655 } else
656 s = new TSocket(connurl.GetHost(), connurl.GetPort());
657
658 if (!s->IsValid()) {
659 Error("GetFromWeb", "cannot connect to host %s", fUrl.GetHost());
660 delete s;
661 return -1;
662 }
663
664 if (s->SendRaw(msg.Data(), msg.Length()) == -1) {
665 Error("GetFromWeb", "error sending command to host %s", fUrl.GetHost());
666 delete s;
667 return -1;
668 }
669
670 if (s->RecvRaw(buf, len) == -1) {
671 Error("GetFromWeb", "error receiving data from host %s", fUrl.GetHost());
672 delete s;
673 return -1;
674 }
675
676 // collect statistics
677 fBytesRead += len;
678 fReadCalls++;
679#ifdef R__WIN32
680 SetFileBytesRead(GetFileBytesRead() + len);
681 SetFileReadCalls(GetFileReadCalls() + 1);
682#else
683 fgBytesRead += len;
684 fgReadCalls++;
685#endif
686
687 if (gPerfStats)
688 gPerfStats->FileReadEvent(this, len, start);
689
690 delete s;
691 return 0;
692}
693
694////////////////////////////////////////////////////////////////////////////////
695/// Read multiple byte range request from web server.
696/// Uses HTTP 1.0 daemon wihtout mod-root.
697/// Returns -2 in case file does not exist, -1 in case
698/// of error and 0 in case of success.
699
701 Int_t *seg_len)
702{
703 if (!len) return 0;
704
705 // if file content was cached, reuse it
706 if (fFullCache && (nseg>0))
707 return GetFromCache(buf, len, nseg, seg_pos, seg_len);
708
709 Double_t start = 0;
710 if (gPerfStats) start = TTimeStamp();
711
712 // open fSocket and close it when going out of scope
713 TWebSocket ws(this);
714
715 if (!fSocket || !fSocket->IsValid()) {
716 Error("GetFromWeb10", "cannot connect to host %s", fUrl.GetHost());
717 return -1;
718 }
719
720 if (gDebug > 0)
721 Info("GetFromWeb10", "sending HTTP request:\n%s", msg.Data());
722
723 if (fSocket->SendRaw(msg.Data(), msg.Length()) == -1) {
724 Error("GetFromWeb10", "error sending command to host %s", fUrl.GetHost());
725 return -1;
726 }
727
728 char line[8192];
729 Int_t n, ret = 0, nranges = 0, ltot = 0, redirect = 0;
731 Long64_t first = -1, last = -1, tot, fullsize = 0;
733
734 while ((n = GetLine(fSocket, line, sizeof(line))) >= 0) {
735 if (n == 0) {
736 if (ret < 0)
737 return ret;
738 if (redirect) {
739 if (redir.IsNull()) {
740 // Some sites (s3.amazonaws.com) do not return a Location field on 301
741 Error("GetFromWeb10", "error - redirect without location from host %s", fUrl.GetHost());
742 return -1;
743 }
744
745 ws.ReOpen();
746 // set message to reflect the redirectLocation and add bytes field
747 TString msg_1 = fMsgReadBuffer10;
748 msg_1 += fOffset;
749 msg_1 += "-";
750 msg_1 += fOffset+len-1;
751 msg_1 += "\r\n\r\n";
752 return GetFromWeb10(buf, len, msg_1);
753 }
754
755 if (first >= 0) {
756 Int_t ll = Int_t(last - first) + 1;
757 Int_t rsize;
758 if ((rsize = fSocket->RecvRaw(&buf[ltot], ll)) == -1) {
759 Error("GetFromWeb10", "error receiving data from host %s", fUrl.GetHost());
760 return -1;
761 }
762 else if (ll != rsize) {
763 Error("GetFromWeb10", "expected %d bytes, got %d", ll, rsize);
764 return -1;
765 }
766 ltot += ll;
767
768 first = -1;
769
770 if (boundary == "")
771 break; // not a multipart response
772 }
773
774 if (fullsize > 0) {
775
776 if (nseg <= 0) {
777 Error("GetFromWeb10","Need segments data to extract parts from full size %lld", fullsize);
778 return -1;
779 }
780
781 if (len > fullsize) {
782 Error("GetFromWeb10","Requested part %d longer than full size %lld", len, fullsize);
783 return -1;
784 }
785
786 if ((fFullCache == 0) && (fullsize <= GetMaxFullCacheSize())) {
787 // try to read file content into cache and than reuse it, limit cache by 2 GB
788 fFullCache = malloc(fullsize);
789 if (fFullCache != 0) {
790 if (fSocket->RecvRaw(fFullCache, fullsize) != fullsize) {
791 Error("GetFromWeb10", "error receiving data from host %s", fUrl.GetHost());
792 free(fFullCache); fFullCache = nullptr;
793 return -1;
794 }
795 fFullCacheSize = fullsize;
796 return GetFromCache(buf, len, nseg, seg_pos, seg_len);
797 }
798 // when cache allocation failed, try without cache
799 }
800
801 // check all segemnts are inside range and in sorted order
802 for (Int_t cnt=0;cnt<nseg;cnt++) {
803 if (fArchiveOffset + seg_pos[cnt] + seg_len[cnt] > fullsize) {
804 Error("GetFromWeb10","Requested segment %lld len %d is outside of full range %lld", seg_pos[cnt], seg_len[cnt], fullsize);
805 return -1;
806 }
807 if ((cnt>0) && (seg_pos[cnt-1] + seg_len[cnt-1] > seg_pos[cnt])) {
808 Error("GetFromWeb10","Requested segments are not in sorted order");
809 return -1;
810 }
811 }
812
813 Long64_t pos = 0;
814 char* curr = buf;
815 char dbuf[2048]; // dummy buffer for skip data
816
817 // now read complete file and take only requested segments into the buffer
818 for (Int_t cnt=0; cnt<nseg; cnt++) {
819 // first skip data before segment
820 while (pos < fArchiveOffset + seg_pos[cnt]) {
821 Long64_t ll = fArchiveOffset + seg_pos[cnt] - pos;
822 if (ll > Int_t(sizeof(dbuf))) ll = sizeof(dbuf);
823 if (fSocket->RecvRaw(dbuf, ll) != ll) {
824 Error("GetFromWeb10", "error receiving data from host %s", fUrl.GetHost());
825 return -1;
826 }
827 pos += ll;
828 }
829
830 // reading segment itself
831 if (fSocket->RecvRaw(curr, seg_len[cnt]) != seg_len[cnt]) {
832 Error("GetFromWeb10", "error receiving data from host %s", fUrl.GetHost());
833 return -1;
834 }
835 curr += seg_len[cnt];
836 pos += seg_len[cnt];
837 ltot += seg_len[cnt];
838 }
839
840 // now read file to the end
841 while (pos < fullsize) {
842 Long64_t ll = fullsize - pos;
843 if (ll > Int_t(sizeof(dbuf))) ll = sizeof(dbuf);
844 if (fSocket->RecvRaw(dbuf, ll) != ll) {
845 Error("GetFromWeb10", "error receiving data from host %s", fUrl.GetHost());
846 return -1;
847 }
848 pos += ll;
849 }
850
851 if (gDebug > 0)
852 Info("GetFromWeb10", "Complete reading %d bytes in %d segments out of full size %lld", len, nseg, fullsize);
853
854 break;
855 }
856
857 continue;
858 }
859
860 if (gDebug > 0)
861 Info("GetFromWeb10", "header: %s", line);
862
863 if (boundaryEnd == line) {
864 if (gDebug > 0)
865 Info("GetFromWeb10", "got all headers");
866 break;
867 }
868 if (boundary == line) {
869 nranges++;
870 if (gDebug > 0)
871 Info("GetFromWeb10", "get new multipart byte range (%d)", nranges);
872 }
873
874 TString res = line;
875 res.ToLower();
876 if (res.BeginsWith("HTTP/1.", TString::kIgnoreCase)) {
877 if (res.BeginsWith("HTTP/1.1", TString::kIgnoreCase)) {
878 if (!fHTTP11)
879 fMsgReadBuffer10 = "";
880 fHTTP11 = kTRUE;
881 }
882 TString scode = res(9, 3);
883 Int_t code = scode.Atoi();
884 if (code >= 500) {
885 ret = -1;
886 TString mess = res(13, 1000);
887 Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
888 } else if (code >= 400) {
889 if (code == 404)
890 ret = -2; // file does not exist
891 else {
892 ret = -1;
893 TString mess = res(13, 1000);
894 Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
895 }
896 } else if (code >= 300) {
897 if (code == 301 || code == 303) {
898 redirect = 1; // permanent redirect
899 } else if (code == 302 || code == 307) {
900 // treat 302 as 303: permanent redirect
901 redirect = 1;
902 //redirect = 2; // temp redirect
903 } else {
904 ret = -1;
905 TString mess = res(13, 1000);
906 Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
907 }
908 } else if (code > 200) {
909 if (code != 206) {
910 ret = -1;
911 TString mess = res(13, 1000);
912 Error("GetFromWeb10", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
913 }
914 } else if (code == 200) {
915 fullsize = -200; // make indication of code 200
916 Warning("GetFromWeb10",
917 "Server %s response with complete file, but only part of it was requested.\n"
918 "Check MaxRanges configuration parameter (if Apache is used)",
919 fUrl.GetHost());
920
921 }
922 } else if (res.BeginsWith("content-type: multipart", TString::kIgnoreCase)) {
923 boundary = res(res.Index("boundary=", TString::kIgnoreCase) + 9, 1000);
924 if (boundary[0] == '"' && boundary[boundary.Length()-1] == '"') {
925 boundary = boundary(1, boundary.Length() - 2);
926 }
927 boundary = "--" + boundary;
928 boundaryEnd = boundary + "--";
929 } else if (res.BeginsWith("content-range:", TString::kIgnoreCase)) {
930 sscanf(res.Data(), "content-range: bytes %lld-%lld/%lld", &first, &last, &tot);
931 if (fSize == -1) fSize = tot;
932 } else if (res.BeginsWith("content-length:", TString::kIgnoreCase) && (fullsize == -200)) {
933 sscanf(res.Data(), "content-length: %lld", &fullsize);
934 } else if (res.BeginsWith("location:", TString::kIgnoreCase) && redirect) {
935 redir = res(10, 1000);
936 if (redirect == 2) // temp redirect
937 SetMsgReadBuffer10(redir, kTRUE);
938 else // permanent redirect
939 SetMsgReadBuffer10(redir, kFALSE);
940 }
941 }
942
943 if (redirect && redir.IsNull()) {
944 Error("GetFromWeb10", "error - redirect without location from host %s", fUrl.GetHost());
945 }
946
947 if (n == -1 && fHTTP11) {
948 if (gDebug > 0)
949 Info("GetFromWeb10", "HTTP/1.1 socket closed, reopen");
950 if (fBasicUrlOrg != "") {
951 // if we have to close temp redirection, set back to original url
952 SetMsgReadBuffer10();
953 }
954 ws.ReOpen();
955 return GetFromWeb10(buf, len, msg);
956 }
957
958 if (ltot != len) {
959 Error("GetFromWeb10", "error receiving expected amount of data (got %d, expected %d) from host %s",
960 ltot, len, fUrl.GetHost());
961 return -1;
962 }
963
964 // collect statistics
965 fBytesRead += len;
966 fReadCalls++;
967#ifdef R__WIN32
968 SetFileBytesRead(GetFileBytesRead() + len);
969 SetFileReadCalls(GetFileReadCalls() + 1);
970#else
971 fgBytesRead += len;
972 fgReadCalls++;
973#endif
974
975 if (gPerfStats)
976 gPerfStats->FileReadEvent(this, len, start);
977
978 return 0;
979}
980
981////////////////////////////////////////////////////////////////////////////////
982/// Set position from where to start reading.
983
985{
986 switch (pos) {
987 case kBeg:
988 fOffset = offset + fArchiveOffset;
989 break;
990 case kCur:
991 fOffset += offset;
992 break;
993 case kEnd:
994 // this option is not used currently in the ROOT code
995 if (fArchiveOffset)
996 Error("Seek", "seeking from end in archive is not (yet) supported");
997 fOffset = fEND - offset; // is fEND really EOF or logical EOF?
998 break;
999 }
1000}
1001
1002////////////////////////////////////////////////////////////////////////////////
1003/// Return maximum file size.
1004
1006{
1007 if (!fHasModRoot || fSize >= 0)
1008 return fSize;
1009
1010 Long64_t size;
1011 char asize[64];
1012
1013 TString msg = "GET ";
1014 msg += fBasicUrl;
1015 msg += "?";
1016 msg += -1;
1017 msg += "\r\n";
1018
1019 if (const_cast<TWebFile*>(this)->GetFromWeb(asize, 64, msg) == -1)
1020 return kMaxInt;
1021
1022#ifndef R__WIN32
1023 size = atoll(asize);
1024#else
1025 size = _atoi64(asize);
1026#endif
1027
1028 fSize = size;
1029
1030 return size;
1031}
1032
1033////////////////////////////////////////////////////////////////////////////////
1034/// Get the HTTP header. Depending on the return code we can see if
1035/// the file exists and if the server uses mod_root.
1036/// Returns -1 in case of an error, -2 in case the file does not exists,
1037/// -3 in case HEAD is not supported (dCache HTTP door) and
1038/// 0 in case of success.
1039
1041{
1042 // Give full URL so Apache's virtual hosts solution works.
1043 if (fMsgGetHead == "") {
1044 fMsgGetHead = "HEAD ";
1045 fMsgGetHead += fBasicUrl;
1046 if (fHTTP11)
1047 fMsgGetHead += " HTTP/1.1";
1048 else
1049 fMsgGetHead += " HTTP/1.0";
1050 fMsgGetHead += "\r\n";
1051 if (fHTTP11) {
1052 fMsgGetHead += "Host: ";
1053 fMsgGetHead += fUrl.GetHost();
1054 fMsgGetHead += "\r\n";
1055 }
1056 fMsgGetHead += BasicAuthentication();
1057 fMsgGetHead += gUserAgent;
1058 fMsgGetHead += "\r\n\r\n";
1059 }
1060 TString msg = fMsgGetHead;
1061
1062 TUrl connurl;
1063 if (fProxy.IsValid())
1064 connurl = fProxy;
1065 else
1066 connurl = fUrl;
1067
1068 TSocket *s = nullptr;
1069 for (Int_t i = 0; i < 5; i++) {
1070 if (strcmp(connurl.GetProtocol(), "https") == 0) {
1071#ifdef R__SSL
1072 s = new TSSLSocket(connurl.GetHost(), connurl.GetPort());
1073#else
1074 Error("GetHead", "library compiled without SSL, https not supported");
1075 return -1;
1076#endif
1077 } else
1078 s = new TSocket(connurl.GetHost(), connurl.GetPort());
1079
1080 if (!s->IsValid()) {
1081 delete s;
1082 if (gSystem->GetErrno() == EADDRINUSE || gSystem->GetErrno() == EISCONN) {
1083 s = nullptr;
1084 gSystem->Sleep(i*10);
1085 } else {
1086 Error("GetHead", "cannot connect to host %s (errno=%d)", fUrl.GetHost(),
1087 gSystem->GetErrno());
1088 return -1;
1089 }
1090 } else
1091 break;
1092 }
1093 if (!s)
1094 return -1;
1095
1096 if (gDebug > 0) {
1097 Info("GetHead", "connected to host %s", connurl.GetHost());
1098 Info("GetHead", "sending HTTP request:\n%s", msg.Data());
1099 }
1100
1101 if (s->SendRaw(msg.Data(), msg.Length()) == -1) {
1102 Error("GetHead", "error sending command to host %s", fUrl.GetHost());
1103 delete s;
1104 return -1;
1105 }
1106
1107 char line[8192];
1108 Int_t n, ret = 0, redirect = 0;
1109 TString redir;
1110
1111 while ((n = GetLine(s, line, sizeof(line))) >= 0) {
1112 if (n == 0) {
1113 if (gDebug > 0)
1114 Info("GetHead", "got all headers");
1115 delete s;
1116 if (fBasicUrlOrg != "" && !redirect) {
1117 // set back to original url in case of temp redirect
1118 SetMsgReadBuffer10();
1119 fMsgGetHead = "";
1120 }
1121 if (ret < 0)
1122 return ret;
1123 if (redirect) {
1124 if (redir.IsNull()) {
1125 // Some sites (s3.amazonaws.com) do not return a Location field on 301
1126 Error("GetHead", "error - redirect without location from host %s", fUrl.GetHost());
1127 return -1;
1128 }
1129 return GetHead();
1130 }
1131 return 0;
1132 }
1133
1134 if (gDebug > 0)
1135 Info("GetHead", "header: %s", line);
1136
1137 TString res = line;
1138 ProcessHttpHeader(res);
1139 if (res.BeginsWith("HTTP/1.")) {
1140 if (res.BeginsWith("HTTP/1.1")) {
1141 if (!fHTTP11) {
1142 fMsgGetHead = "";
1143 fMsgReadBuffer10 = "";
1144 }
1145 fHTTP11 = kTRUE;
1146 }
1147 TString scode = res(9, 3);
1148 Int_t code = scode.Atoi();
1149 if (code >= 500) {
1150 if (code == 500)
1151 fHasModRoot = kTRUE;
1152 else {
1153 ret = -1;
1154 TString mess = res(13, 1000);
1155 Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
1156 }
1157 } else if (code >= 400) {
1158 if (code == 400)
1159 ret = -3; // command not supported
1160 else if (code == 404)
1161 ret = -2; // file does not exist
1162 else {
1163 ret = -1;
1164 TString mess = res(13, 1000);
1165 Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
1166 }
1167 } else if (code >= 300) {
1168 if (code == 301 || code == 303)
1169 redirect = 1; // permanent redirect
1170 else if (code == 302 || code == 307)
1171 redirect = 2; // temp redirect
1172 else {
1173 ret = -1;
1174 TString mess = res(13, 1000);
1175 Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
1176 }
1177 } else if (code > 200) {
1178 ret = -1;
1179 TString mess = res(13, 1000);
1180 Error("GetHead", "%s: %s (%d)", fBasicUrl.Data(), mess.Data(), code);
1181 }
1182 } else if (res.BeginsWith("Content-Length:", TString::kIgnoreCase)) {
1183 TString slen = res(16, 1000);
1184 fSize = slen.Atoll();
1185 } else if (res.BeginsWith("Location:", TString::kIgnoreCase) && redirect) {
1186 redir = res(10, 1000);
1187 if (redirect == 2) // temp redirect
1188 SetMsgReadBuffer10(redir, kTRUE);
1189 else // permanent redirect
1190 SetMsgReadBuffer10(redir, kFALSE);
1191 fMsgGetHead = "";
1192 }
1193 }
1194
1195 delete s;
1196
1197 return ret;
1198}
1199
1200////////////////////////////////////////////////////////////////////////////////
1201/// Read a line from the socket. Reads at most one less than the number of
1202/// characters specified by maxsize. Reading stops when a newline character
1203/// is found, The newline (\\n) and cr (\\r), if any, are removed.
1204/// Returns -1 in case of error, or the number of characters read (>= 0)
1205/// otherwise.
1206
1208{
1209 Int_t n = GetHunk(s, line, maxsize);
1210 if (n < 0) {
1211 if (!fHTTP11 || gDebug > 0)
1212 Error("GetLine", "error receiving data from host %s", fUrl.GetHost());
1213 return -1;
1214 }
1215
1216 if (n > 0 && line[n-1] == '\n') {
1217 n--;
1218 if (n > 0 && line[n-1] == '\r')
1219 n--;
1220 line[n] = '\0';
1221 }
1222 return n;
1223}
1224
1225////////////////////////////////////////////////////////////////////////////////
1226/// Read a hunk of data from the socket, up until a terminator. The hunk is
1227/// limited by whatever the TERMINATOR callback chooses as its
1228/// terminator. For example, if terminator stops at newline, the hunk
1229/// will consist of a line of data; if terminator stops at two
1230/// newlines, it can be used to read the head of an HTTP response.
1231/// Upon determining the boundary, the function returns the data (up to
1232/// the terminator) in hunk.
1233///
1234/// In case of read error, -1 is returned. In case of having read some
1235/// data, but encountering EOF before seeing the terminator, the data
1236/// that has been read is returned, but it will (obviously) not contain the
1237/// terminator.
1238///
1239/// The TERMINATOR function is called with three arguments: the
1240/// beginning of the data read so far, the beginning of the current
1241/// block of peeked-at data, and the length of the current block.
1242/// Depending on its needs, the function is free to choose whether to
1243/// analyze all data or just the newly arrived data. If TERMINATOR
1244/// returns 0, it means that the terminator has not been seen.
1245/// Otherwise it should return a pointer to the character immediately
1246/// following the terminator.
1247///
1248/// The idea is to be able to read a line of input, or otherwise a hunk
1249/// of text, such as the head of an HTTP request, without crossing the
1250/// boundary, so that the next call to RecvRaw() etc. reads the data
1251/// after the hunk. To achieve that, this function does the following:
1252///
1253/// 1. Peek at incoming data.
1254///
1255/// 2. Determine whether the peeked data, along with the previously
1256/// read data, includes the terminator.
1257///
1258/// 3a. If yes, read the data until the end of the terminator, and
1259/// exit.
1260///
1261/// 3b. If no, read the peeked data and goto 1.
1262///
1263/// The function is careful to assume as little as possible about the
1264/// implementation of peeking. For example, every peek is followed by
1265/// a read. If the read returns a different amount of data, the
1266/// process is retried until all data arrives safely.
1267///
1268/// Reads at most one less than the number of characters specified by maxsize.
1269
1271{
1272 if (maxsize <= 0) return 0;
1273
1275 Int_t tail = 0; // tail position in HUNK
1276
1277 while (1) {
1278 const char *end;
1280
1281 // First, peek at the available data.
1282 pklen = s->RecvRaw(hunk+tail, bufsize-1-tail, kPeek);
1283 if (pklen < 0) {
1284 return -1;
1285 }
1286 end = HttpTerminator(hunk, hunk+tail, pklen);
1287 if (end) {
1288 // The data contains the terminator: we'll drain the data up
1289 // to the end of the terminator.
1290 remain = end - (hunk + tail);
1291 if (remain == 0) {
1292 // No more data needs to be read.
1293 hunk[tail] = '\0';
1294 return tail;
1295 }
1296 if (bufsize - 1 < tail + remain) {
1297 Error("GetHunk", "hunk buffer too small for data from host %s (%d bytes needed)",
1298 fUrl.GetHost(), tail + remain + 1);
1299 hunk[tail] = '\0';
1300 return -1;
1301 }
1302 } else {
1303 // No terminator: simply read the data we know is (or should
1304 // be) available.
1305 remain = pklen;
1306 }
1307
1308 // Now, read the data. Note that we make no assumptions about
1309 // how much data we'll get. (Some TCP stacks are notorious for
1310 // read returning less data than the previous MSG_PEEK.)
1311 rdlen = s->RecvRaw(hunk+tail, remain, kDontBlock);
1312 if (rdlen < 0) {
1313 return -1;
1314 }
1315 tail += rdlen;
1316 hunk[tail] = '\0';
1317
1318 if (rdlen == 0) {
1319 // in case of EOF: return the data we've read.
1320 return tail;
1321 }
1322 if (end && rdlen == remain) {
1323 // The terminator was seen and the remaining data drained --
1324 // we got what we came for.
1325 return tail;
1326 }
1327
1328 // Keep looping until all the data arrives.
1329
1330 if (tail == bufsize - 1) {
1331 Error("GetHunk", "hunk buffer too small for data from host %s",
1332 fUrl.GetHost());
1333 return -1;
1334 }
1335 }
1336}
1337
1338////////////////////////////////////////////////////////////////////////////////
1339/// Determine whether [START, PEEKED + PEEKLEN) contains an HTTP new
1340/// line [\\r]\\n. If so, return the pointer to the position after the line,
1341/// otherwise return 0. This is used as callback to GetHunk(). The data
1342/// between START and PEEKED has been read and cannot be "unread"; the
1343/// data after PEEKED has only been peeked.
1344
1345const char *ROOT::Deprecated::TWebFile::HttpTerminator(const char *start, const char *peeked,
1346 Int_t peeklen)
1347{
1348#if 0
1349 const char *p, *end;
1350
1351 // Look for "[\r]\n", and return the following position if found.
1352 // Start one char before the current to cover the possibility that
1353 // part of the terminator (e.g. "\r") arrived in the previous batch.
1354 p = peeked - start < 1 ? start : peeked - 1;
1355 end = peeked + peeklen;
1356
1357 // Check for \r\n anywhere in [p, end-2).
1358 for (; p < end - 1; p++)
1359 if (p[0] == '\r' && p[1] == '\n')
1360 return p + 2;
1361
1362 // p==end-1: check for \r\n directly preceding END.
1363 if (p[0] == '\r' && p[1] == '\n')
1364 return p + 2;
1365#else
1366 (void) start; // start unused, silence compiler
1367 if (peeked) {
1368 const char *p = (const char*) memchr(peeked, '\n', peeklen);
1369 if (p)
1370 // p+1 because the line must include '\n'
1371 return p + 1;
1372 }
1373#endif
1374 return nullptr;
1375}
1376
1377////////////////////////////////////////////////////////////////////////////////
1378/// Return basic authentication scheme, to be added to the request.
1379
1381{
1382 TString msg;
1383 if (strlen(fUrl.GetUser())) {
1384 TString auth = fUrl.GetUser();
1385 if (strlen(fUrl.GetPasswd())) {
1386 auth += ":";
1387 auth += fUrl.GetPasswd();
1388 }
1389 msg += "Authorization: Basic ";
1391 msg += "\r\n";
1392 }
1393 return msg;
1394}
1395
1396////////////////////////////////////////////////////////////////////////////////
1397/// Static method setting global proxy URL.
1398
1400{
1401 if (proxy && *proxy) {
1402 TUrl p(proxy);
1403 if (strcmp(p.GetProtocol(), "http")) {
1404 :: Error("TWebFile::SetProxy", "protocol must be HTTP in proxy URL %s",
1405 proxy);
1406 return;
1407 }
1408 fgProxy = p;
1409 }
1410}
1411
1412////////////////////////////////////////////////////////////////////////////////
1413/// Static method returning the global proxy URL.
1414
1416{
1417 if (fgProxy.IsValid())
1418 return fgProxy.GetUrl();
1419 return "";
1420}
1421
1422////////////////////////////////////////////////////////////////////////////////
1423/// Process the HTTP header in the argument. This method is intended to be
1424/// overwritten by subclasses that exploit the information contained in the
1425/// HTTP headers.
1426
1430
1431////////////////////////////////////////////////////////////////////////////////
1432/// Static method returning maxmimal size of full cache,
1433/// which can be preserved by file instance
1434
1436{
1437 return fgMaxFullCacheSize;
1438}
1439
1440////////////////////////////////////////////////////////////////////////////////
1441/// Static method, set maxmimal size of full cache,
1442// which can be preserved by file instance
1443
1445{
1446 fgMaxFullCacheSize = sz;
1447}
1448
1449
1450////////////////////////////////////////////////////////////////////////////////
1451/// Create helper class that allows directory access via httpd.
1452/// The name must start with '-' to bypass the TSystem singleton check.
1453
1454ROOT::Deprecated::TWebSystem::TWebSystem() : TSystem("-http", "HTTP Helper System")
1455{
1456 SetName("http");
1457
1458 fDirp = nullptr;
1459}
1460
1461////////////////////////////////////////////////////////////////////////////////
1462/// Make a directory via httpd. Not supported.
1463
1465{
1466 return -1;
1467}
1468
1469////////////////////////////////////////////////////////////////////////////////
1470/// Open a directory via httpd. Returns an opaque pointer to a dir
1471/// structure. Returns 0 in case of error.
1472
1474{
1475 if (fDirp) {
1476 Error("OpenDirectory", "invalid directory pointer (should never happen)");
1477 fDirp = nullptr;
1478 }
1479
1480 fDirp = nullptr; // not implemented for the time being
1481
1482 return fDirp;
1483}
1484
1485////////////////////////////////////////////////////////////////////////////////
1486/// Free directory via httpd.
1487
1489{
1490 if (dirp != fDirp) {
1491 Error("FreeDirectory", "invalid directory pointer (should never happen)");
1492 return;
1493 }
1494
1495 fDirp = nullptr;
1496}
1497
1498////////////////////////////////////////////////////////////////////////////////
1499/// Get directory entry via httpd. Returns 0 in case no more entries.
1500
1502{
1503 if (dirp != fDirp) {
1504 Error("GetDirEntry", "invalid directory pointer (should never happen)");
1505 return 0;
1506 }
1507
1508 return 0;
1509}
1510
1511////////////////////////////////////////////////////////////////////////////////
1512/// Get info about a file. Info is returned in the form of a FileStat_t
1513/// structure (see TSystem.h).
1514/// The function returns 0 in case of success and 1 if the file could
1515/// not be stat'ed.
1516
1518{
1519 TWebFile *f = new TWebFile(path, "HEADONLY");
1520
1521 if (f->fWritten == 0) {
1522
1523 buf.fDev = 0;
1524 buf.fIno = 0;
1525 buf.fMode = 0;
1526 buf.fUid = 0;
1527 buf.fGid = 0;
1528 buf.fSize = f->GetSize();
1529 buf.fMtime = 0;
1530 buf.fIsLink = kFALSE;
1531
1532 delete f;
1533 return 0;
1534 }
1535
1536 delete f;
1537 return 1;
1538}
1539
1540////////////////////////////////////////////////////////////////////////////////
1541/// Returns FALSE if one can access a file using the specified access mode.
1542/// Mode is the same as for the Unix access(2) function.
1543/// Attention, bizarre convention of return value!!
1544
1546{
1547 TWebFile *f = new TWebFile(path, "HEADONLY");
1548 if (f->fWritten == 0) {
1549 delete f;
1550 return kFALSE;
1551 }
1552 delete f;
1553 return kTRUE;
1554}
1555
1556////////////////////////////////////////////////////////////////////////////////
1557/// Unlink, i.e. remove, a file or directory. Returns 0 when successful,
1558/// -1 in case of failure. Not supported for httpd.
1559
1561{
1562 return -1;
1563}
dim_t fSize
#define f(i)
Definition RSha256.hxx:104
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
constexpr Int_t kMaxInt
Definition RtypesCore.h:119
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
static const std::string gUserAgent
#define gDirectory
Definition TDirectory.h:385
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:783
#define gROOT
Definition TROOT.h:426
void ReadBuffer(char *&buffer) override
@ kDontBlock
Definition TSystem.h:246
@ kPeek
Definition TSystem.h:245
EAccessMode
Definition TSystem.h:51
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define gPerfStats
static const char * gUserAgent
Definition TWebFile.cxx:46
#define free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
static void SetProxy(const char *url)
Static method setting global proxy URL.
virtual Int_t GetFromWeb(char *buf, Int_t len, const TString &msg)
Read request from web server.
Definition TWebFile.cxx:633
static Long64_t fgMaxFullCacheSize
Definition TWebFile.h:61
virtual Bool_t ReadBuffers10(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
Read specified byte ranges from remote file via HTTP 1.0 daemon (without mod-root installed).
Definition TWebFile.cxx:574
virtual Int_t GetFromWeb10(char *buf, Int_t len, const TString &msg, Int_t nseg=0, Long64_t *seg_pos=nullptr, Int_t *seg_len=nullptr)
Read multiple byte range request from web server.
Definition TWebFile.cxx:700
void Seek(Long64_t offset, ERelativeTo pos=kBeg) override
Set position from where to start reading.
Definition TWebFile.cxx:984
virtual void CheckProxy()
Check if shell var "http_proxy" has been set and should be used.
Definition TWebFile.cxx:361
Bool_t ReadBuffer(char *buf, Int_t len) override
Read specified byte range from remote file via HTTP daemon.
Definition TWebFile.cxx:437
virtual TString BasicAuthentication()
Return basic authentication scheme, to be added to the request.
static const char * GetProxy()
Static method returning the global proxy URL.
void Init(Bool_t readHeadOnly) override
Initialize a TWebFile object.
Definition TWebFile.cxx:214
virtual Int_t GetHunk(TSocket *s, char *hunk, Int_t maxsize)
Read a hunk of data from the socket, up until a terminator.
virtual ~TWebFile()
Cleanup.
Definition TWebFile.cxx:201
virtual void ProcessHttpHeader(const TString &headerLine)
Process the HTTP header in the argument.
virtual Int_t GetLine(TSocket *s, char *line, Int_t maxsize)
Read a line from the socket.
Bool_t IsOpen() const override
A TWebFile that has been correctly constructed is always considered open.
Definition TWebFile.cxx:388
virtual Bool_t ReadBuffer10(char *buf, Int_t len)
Read specified byte range from remote file via HTTP 1.0 daemon (without mod-root installed).
Definition TWebFile.cxx:486
static void SetMaxFullCacheSize(Long64_t sz)
Static method, set maxmimal size of full cache,.
Int_t ReOpen(Option_t *mode) override
Reopen a file with a different access mode, like from READ to UPDATE or from NEW, CREATE,...
Definition TWebFile.cxx:402
virtual Int_t GetHead()
Get the HTTP header.
virtual void SetMsgReadBuffer10(const char *redirectLocation=nullptr, Bool_t tempRedirect=kFALSE)
Set GET command for use by ReadBuffer(s)10(), handle redirection if needed.
Definition TWebFile.cxx:274
void Close(Option_t *option="") override
Close a Web file.
Definition TWebFile.cxx:420
virtual const char * HttpTerminator(const char *start, const char *peeked, Int_t peeklen)
Determine whether [START, PEEKED + PEEKLEN) contains an HTTP new line [\r]\n.
Long64_t GetSize() const override
Return maximum file size.
Bool_t ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf) override
Read specified byte ranges from remote file via HTTP daemon.
Definition TWebFile.cxx:525
virtual Int_t GetFromCache(char *buf, Int_t len, Int_t nseg, Long64_t *seg_pos, Int_t *seg_len)
Extract requested segments from the cached content.
Definition TWebFile.cxx:608
static Long64_t GetMaxFullCacheSize()
Static method returning maxmimal size of full cache, which can be preserved by file instance.
~TWebSocket()
Close socket in case not HTTP/1.1 protocol or when explicitly requested.
Definition TWebFile.cxx:80
TWebSocket(TWebFile *f)
Open web file socket.
Definition TWebFile.cxx:70
void ReOpen()
Re-open web file socket.
Definition TWebFile.cxx:91
TWebSystem()
Create helper class that allows directory access via httpd.
Bool_t AccessPathName(const char *path, EAccessMode mode) override
Returns FALSE if one can access a file using the specified access mode.
const char * GetDirEntry(void *dirp) override
Get directory entry via httpd. Returns 0 in case no more entries.
void FreeDirectory(void *dirp) override
Free directory via httpd.
Int_t GetPathInfo(const char *path, FileStat_t &buf) override
Get info about a file.
Int_t Unlink(const char *path) override
Unlink, i.e.
Int_t MakeDirectory(const char *name) override
Make a directory via httpd. Not supported.
void * OpenDirectory(const char *name) override
Open a directory via httpd.
static TString Encode(const char *data)
Transform data into a null terminated base64 string.
Definition TBase64.cxx:106
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual void Init(Bool_t create)
Initialize a TFile object.
Definition TFile.cxx:638
ERelativeTo
Definition TFile.h:277
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:980
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
A TSocket wrapped in by SSL.
Definition TSSLSocket.h:28
This class implements client sockets.
Definition TSocket.h:54
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition TSocket.cxx:922
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition TSocket.cxx:629
virtual Bool_t IsValid() const
Definition TSocket.h:156
Basic string class.
Definition TString.h:138
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
const char * Data() const
Definition TString.h:384
@ kIgnoreCase
Definition TString.h:285
void ToUpper()
Change string to upper case.
Definition TString.cxx:1202
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:632
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
Abstract base class defining a generic interface to the underlying Operating System.
Definition TSystem.h:276
static Int_t GetErrno()
Static function returning system error number.
Definition TSystem.cxx:274
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1676
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:435
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition TTimeStamp.h:45
This class represents a WWW compatible URL.
Definition TUrl.h:33
TLine * line
const Int_t n
Definition legend1.C:16
Int_t fMode
Definition TSystem.h:135
Long64_t fSize
Definition TSystem.h:138
Long_t fDev
Definition TSystem.h:133
Int_t fGid
Definition TSystem.h:137
Long_t fMtime
Definition TSystem.h:139
Long_t fIno
Definition TSystem.h:134
Bool_t fIsLink
Definition TSystem.h:140
Int_t fUid
Definition TSystem.h:136