ROOTANA
xmlServer.cxx
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: xmlServer.cxx
4  Created by: Konstantin Olchanski
5 
6  Contents: Serve XML-encoded ROOT objects through a TCP socket
7 
8  $Id$
9 
10 \********************************************************************/
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <assert.h>
15 
16 #include "xmlServer.h"
17 
18 /*==== ROOT socket histo server ====================================*/
19 
20 #if 1
21 #define THREADRETURN
22 #define THREADTYPE void
23 #endif
24 #if defined( OS_WINNT )
25 #define THREADRETURN 0
26 #define THREADTYPE DWORD WINAPI
27 #endif
28 #ifndef THREADTYPE
29 #define THREADTYPE int
30 #define THREADRETURN 0
31 #endif
32 
33 #include <TROOT.h>
34 #include <TClass.h>
35 #include <TDirectory.h>
36 #include <TKey.h>
37 #include <TFolder.h>
38 #include <TSocket.h>
39 #include <TServerSocket.h>
40 #include <TThread.h>
41 #include <TMessage.h>
42 #include <TObjString.h>
43 #include <TH1.h>
44 #include <TCutG.h>
45 #include <TBufferXML.h>
46 
47 #include <deque>
48 #include <map>
49 #include <string>
50 
52 {
53 public:
54  bool fIsLocked;
55 
56  XLockRootGuard() // ctor
57  {
58  TThread::Lock();
59  fIsLocked = true;
60  }
61 
62  ~XLockRootGuard() // dtor
63  {
64  if (fIsLocked)
65  Unlock();
66  }
67 
68  void Unlock()
69  {
70  fIsLocked = false;
71  TThread::UnLock();
72  };
73 };
74 
75 static bool gVerbose = false;
76 
77 static std::deque<std::string> gExports;
78 static std::map<std::string,std::string> gExportNames;
79 
80 /*------------------------------------------------------------------*/
81 
82 static std::string HtmlEncode(const char* s)
83 {
84  std::string r;
85  while (*s) {
86  char c = *s;
87  if (c == '<') {
88  r += "&lt;";
89  } else if (c == '>') {
90  r += "&gt;";
91  } else if (c == '&') {
92  r += "&amp;";
93  } else {
94  r += c;
95  }
96  s++;
97  }
98  return r;
99 }
100 
101 static std::string UrlEncode(const char* s)
102 {
103  std::string r;
104  while (*s) {
105  char c = *s;
106  if (isalpha(c)) {
107  r += c;
108  } else if (isdigit(c)) {
109  r += c;
110  } else {
111  char buf[16];
112  sprintf(buf, "%%%02x", c);
113  r += buf;
114  }
115  s++;
116  }
117  return r;
118 }
119 
120 static int atohex(int a)
121 {
122  if (a>='0' && a<='9')
123  return a-'0';
124  if (a>='a' && a<='f')
125  return a-'a'+10;
126  if (a>='A' && a<='F')
127  return a-'A'+10;
128  return 0;
129 }
130 
131 static std::string HtmlDecode(const char* s)
132 {
133  std::string r;
134  while (*s) {
135  if (*s == '%') {
136  s++;
137  char c = 0;
138  c = c*16 + atohex(s[0]);
139  c = c*16 + atohex(s[1]);
140  r += c;
141 
142  // be careful when incrementing "s" to not overrun the '\0' string terminator!
143  if (*s)
144  s++;
145  if (*s)
146  s++;
147  } else {
148  r += *s++;
149  }
150  }
151  return r;
152 }
153 
154 /*------------------------------------------------------------------*/
155 
156 static TObject* FollowPath(TObject* container, char* path)
157 {
158  if (0)
159  printf("Follow path [%s] in container %p\n", path, container);
160 
161  while (1)
162  {
163  while (*path == '/')
164  path++;
165 
166  char* s = strchr(path,'/');
167 
168  if (s)
169  *s = 0;
170 
171  TObject *obj = NULL;
172 
173  std::string xpath = HtmlDecode(path);
174  //printf("FindObject %s, decoded [%s]\n", path, xpath.c_str());
175 
176  if (container->InheritsFrom(TDirectory::Class()))
177  obj = ((TDirectory*)container)->FindObject(xpath.c_str());
178  else if (container->InheritsFrom(TFolder::Class()))
179  obj = ((TFolder*)container)->FindObject(xpath.c_str());
180  else if (container->InheritsFrom(TCollection::Class()))
181  obj = ((TCollection*)container)->FindObject(xpath.c_str());
182  else
183  {
184  fprintf(stderr, "XmlServer: ERROR: Container \'%s\' of type %s is not a TDirectory, TFolder or TCollection\n", container->GetName(), container->IsA()->GetName());
185  return NULL;
186  }
187 
188  if (!obj)
189  return NULL;
190 
191  if (!s)
192  return obj;
193 
194  container = obj;
195 
196  path = s+1;
197  }
198  /* NOT REACHED */
199 }
200 
201 static TObject* FindTopLevelObject(const char* name)
202 {
203  if (0)
204  printf("FindTopLevelObject [%s]\n", name);
205  if (strcmp(name, "root") == 0)
206  return gROOT;
207  TObject *obj = NULL;
208  //gROOT->GetListOfFiles()->Print();
209  obj = gROOT->GetListOfFiles()->FindObject(name);
210  if (obj)
211  return obj;
212  obj = gROOT->FindObjectAny(name);
213  if (obj)
214  return obj;
215  return NULL;
216 }
217 
218 static TObject* TopLevel(char* path, char**opath)
219 {
220  if (0)
221  printf("Extract top level object from [%s]\n", path);
222 
223  while (*path == '/')
224  path++;
225 
226  char* s = strchr(path,'/');
227 
228  if (s)
229  {
230  *s = 0;
231  *opath = s+1;
232  }
233  else
234  {
235  *opath = NULL;
236  }
237 
238  std::string xpath = HtmlDecode(path);
239 
240  TObject *obj = NULL;
241 
242  for (unsigned int i=0; i<gExports.size(); i++)
243  {
244  const char* ename = gExports[i].c_str();
245  //printf("Compare [%s] and [%s]\n", xpath.c_str(), ename);
246  if (strcmp(xpath.c_str(), ename) == 0)
247  {
248  const char* xname = gExportNames[ename].c_str();
249  obj = FindTopLevelObject(xname);
250  //printf("Lookup of [%s] returned %p\n", xname, obj);
251  break;
252  }
253  }
254 
255  if (!obj)
256  {
257  fprintf(stderr, "XmlServer: ERROR: Top level object \'%s\' not found in exports list\n", xpath.c_str());
258  return NULL;
259  }
260 
261  return obj;
262 }
263 
264 static TObject* FollowPath(char* path)
265 {
266  if (0)
267  printf("Follow path [%s]\n", path);
268 
269  char *s;
270  TObject *obj = TopLevel(path, &s);
271 
272  if (!obj)
273  return NULL;
274 
275  if (!s)
276  return obj;
277 
278  return FollowPath(obj, s);
279 }
280 
281 /*------------------------------------------------------------------*/
282 
283 #if 0
284 static void ResetObject(TObject* obj)
285 {
286  assert(obj!=NULL);
287 
288  if (gVerbose)
289  printf("ResetObject object %p name [%s] type [%s]\n", obj, obj->GetName(), obj->IsA()->GetName());
290 
291  if (obj->InheritsFrom(TH1::Class()))
292  {
293  ((TH1*)obj)->Reset();
294  }
295  else if (obj->InheritsFrom(TDirectory::Class()))
296  {
297  TDirectory* dir = (TDirectory*)obj;
298  TList* objs = dir->GetList();
299 
300  TIter next = objs;
301  while(1)
302  {
303  TObject *obj = next();
304  if (obj == NULL)
305  break;
306  ResetObject(obj);
307  }
308  }
309 }
310 #endif
311 
312 /*------------------------------------------------------------------*/
313 
314 static void SendString(TSocket* sock, const char* str)
315 {
316  sock->SendRaw(str, strlen(str));
317 }
318 
319 static void SendHttpReply(TSocket* sock, const char* mimetype, const char* message)
320 {
321  char buf[256];
322  int len = strlen(message);
323  SendString(sock, "HTTP/1.1 200 OK\n");
324  //SendString(sock, "Date: Tue, 15 May 2012 16:50:31 GMT\n");
325  SendString(sock, "Server: ROOTANA xmlServer\n");
326  sprintf(buf, "Content-Length: %d\n", len);
327  SendString(sock, buf);
328  //Connection: close\n
329  sprintf(buf, "Content-Type: %s\n", mimetype);
330  SendString(sock, buf);
331  //charset=iso-8859-1\n
332  SendString(sock, "\n");
333  SendString(sock, message);
334  printf("XmlServer: Reply content-length %d, content-type %s\n", len, mimetype);
335 }
336 
337 static void SendHttpReply(TSocket* sock, const char* mimetype, const std::string& str)
338 {
339  SendHttpReply(sock, mimetype, str.c_str());
340 }
341 
342 /*------------------------------------------------------------------*/
343 
344 static std::string HtmlTag(const char* tag, const char* contents)
345 {
346  std::string s;
347  s += "<";
348  s += tag;
349  s += ">";
350  s += contents;
351  s += "</";
352  s += tag;
353  s += ">";
354  return s;
355 }
356 
357 static std::string HtmlTag(const char* tag, const std::string& contents)
358 {
359  std::string s;
360  s += "<";
361  s += tag;
362  s += ">";
363  s += contents;
364  s += "</";
365  s += tag;
366  s += ">";
367  return s;
368 }
369 
370 /*------------------------------------------------------------------*/
371 
372 std::string MakeXmlEntry(const TObject* obj)
373 {
374  const char* objname = obj->GetName();
375  const char* classname = obj->ClassName();
376  bool isSubdir = false;
377  std::string xkey = "";
378 
379  if (obj->InheritsFrom(TKey::Class())) {
380  TKey* key = (TKey*)obj;
381  classname = key->GetClassName();
382  xkey = "<key/>";
383  }
384 
385  const TClass *xclass = TClass::GetClass(classname);
386 
387  if (xclass->InheritsFrom(TDirectory::Class()))
388  isSubdir = true;
389 
390  if (xclass->InheritsFrom(TFolder::Class()))
391  isSubdir = true;
392 
393  if (xclass->InheritsFrom(TCollection::Class()))
394  isSubdir = true;
395 
396  //printf("xclass %s, classname %s, subdir %d\n", xclass->GetName(), classname, isSubdir);
397 
398  if (isSubdir)
399  return HtmlTag("subdir", HtmlTag("name", HtmlEncode(objname)) + HtmlTag("class", HtmlEncode(classname)) + xkey) + "\n";
400  else
401  return HtmlTag("object", HtmlTag("name", HtmlEncode(objname)) + HtmlTag("class", HtmlEncode(classname)) + xkey) + "\n";
402 }
403 
404 std::string MakeHtmlEntry(const TObject* obj, const char* path)
405 {
406  const char* objname = obj->GetName();
407  const char* classname = obj->ClassName();
408  bool isKey = false;
409 
410  if (obj->InheritsFrom(TKey::Class())) {
411  TKey* key = (TKey*)obj;
412  classname = key->GetClassName();
413  isKey = true;
414  }
415 
416  std::string s;
417 
418  s += "<a href=\"";
419  s += path; //dir->GetName();
420  s += "/";
421  s += UrlEncode(objname);
422  s += "\">";
423  s += objname;
424  s += "</a>\n";
425  s += " (";
426  s += classname;
427  s += ")";
428  if (isKey)
429  s += "-KEY";
430  s += " ";
431  s += "<a href=\"";
432  s += path; //dir->GetName();
433  s += "/";
434  s += UrlEncode(objname);
435  s += ".xml";
436  s += "\">";
437  s += "XML</a>\n";
438 
439  return s;
440 }
441 
442 /*------------------------------------------------------------------*/
443 
444 static void SendFile(TSocket* sock, const char* filename, const char* mimetype)
445 {
446  std::string f = filename;
447  std::string reply;
448  FILE *fp = fopen(f.c_str(), "r");
449  if (!fp) {
450  std::string home = getenv("HOME");
451  f = home + "/packages/rootana/libXmlServer/" + filename;
452  fp = fopen(f.c_str(), "r");
453  }
454  printf("sending file %s, fp %p\n", f.c_str(), fp);
455  if (fp) {
456  while (1) {
457  char buf[1024+1];
458  int rd = fread(buf, 1, sizeof(buf)-1, fp);
459  if (rd <= 0)
460  break;
461  buf[rd] = 0;
462  reply += buf;
463  }
464  fclose(fp);
465  }
466  SendHttpReply(sock, mimetype, reply);
467 }
468 
469 /*------------------------------------------------------------------*/
470 
472 /*
473  Serve histograms over TCP/IP socket link
474 */
475 {
476  char request[2560];
477 
478  TSocket *sock = (TSocket *) arg;
479  //TMessage message(kMESS_OBJECT);
480 
481  do {
482 
483  /* close connection if client has disconnected */
484  int rd = sock->RecvRaw(request, sizeof(request), kDontBlock); // (ESendRecvOptions)-1);
485  if (rd <= 0)
486  {
487  if (gVerbose)
488  fprintf(stderr, "XmlServer: connection from %s closed\n", sock->GetInetAddress().GetHostName());
489  sock->Close();
490  delete sock;
491  return THREADRETURN;
492  }
493 
494  if (1) {
495  char *p;
496  p = strchr(request, '\n');
497  if (p)
498  *p = 0;
499 
500  p = strchr(request, '\r');
501  if (p)
502  *p = 0;
503  }
504 
505  if (gVerbose)
506  printf("XmlServer: Request [%s] from %s\n", request, sock->GetInetAddress().GetHostName());
507 
508  if (0) {}
509  else if (strstr(request, "GET / "))
510  {
511  // enumerate top level exported directories
512 
513  XLockRootGuard lock;
514 
515  std::string reply;
516 
517  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
518  reply += HtmlTag("title", "Export list") + "\n";
519  reply += "</head><body>\n";
520  reply += HtmlTag("h1", "Export list") + "\n";
521 
522  for (unsigned int i=0; i<gExports.size(); i++) {
523  const char* ename = gExports[i].c_str();
524  const char* xname = gExportNames[ename].c_str();
525 
526  TObject* obj = FindTopLevelObject(xname);
527 
528  if (obj) {
529  std::string s;
530  s += " ";
531  s += "<a href=\"";
532  s += UrlEncode(ename);
533  s += "\">";
534  s += ename;
535  s += "</a>\n";
536  s += "<a href=\"";
537  s += UrlEncode(ename);
538  s += ".xml";
539  s += "\">";
540  s += "XML</a>\n";
541  reply += HtmlTag("p", s) + "\n";
542  } else {
543  std::string s;
544  s += ename;
545  s += " (cannot be found. maybe deleted?)\n";
546  reply += HtmlTag("p", s) + "\n";
547  }
548  }
549 
550  lock.Unlock();
551 
552  reply += "</body></html>\n";
553  SendHttpReply(sock, "text/html", reply);
554  }
555  //else if (strstr(request, "GET /plot.html "))
556  // {
557  // SendFile(sock, "plot.html", "text/html");
558  // }
559  else if (strstr(request, "js/jquery.min.js "))
560  {
561  SendFile(sock, "jquery.min.js", "text/javascript");
562  }
563  else if (strstr(request, "js/highcharts.js "))
564  {
565  SendFile(sock, "highcharts.js", "text/javascript");
566  }
567  else if (strstr(request, "js/exporting.js "))
568  {
569  SendFile(sock, "exporting.js", "text/javascript");
570  }
571  else if (strstr(request, "GET /favicon.ico "))
572  {
573  std::string reply;
574 
575  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
576  reply += HtmlTag("title", "No favicon") + "\n";
577  reply += "</head><body>\n";
578  reply += HtmlTag("h1", "No favicon") + "\n";
579  reply += HtmlTag("p", "No favicon") + "\n";
580  reply += "</body></html>\n";
581  SendHttpReply(sock, "text/html", reply);
582  }
583  else if (strstr(request, "GET /index.xml "))
584  {
585  // enumerate top level exported directories
586 
587  XLockRootGuard lock;
588 
589  std::string xml;
590 
591  xml += "<xml>\n";
592  xml += "<dir>\n";
593 
594  for (unsigned int i=0; i<gExports.size(); i++)
595  {
596  const char* ename = gExports[i].c_str();
597  const char* xname = gExportNames[ename].c_str();
598 
599  TObject* obj = FindTopLevelObject(xname);
600 
601  if (!obj) {
602  xml += HtmlTag("subdir", HtmlTag("name", HtmlEncode(ename)) + "<deleted/>") + "\n";
603  continue;
604  }
605 
606  const char* cname = obj->ClassName();
607 
608  xml += HtmlTag("subdir", HtmlTag("name", HtmlEncode(ename)) + HtmlTag("class", HtmlEncode(cname))) + "\n";
609  }
610 
611  lock.Unlock();
612 
613  xml += "</dir>\n";
614  xml += "</xml>\n";
615 
616  SendHttpReply(sock, "application/xml", xml);
617  }
618  else if (strncmp(request, "GET /", 5) == 0)
619  {
620  XLockRootGuard lock;
621 
622  char* dirname = request + 5;
623 
624  char* x = strstr(dirname, " HTTP");
625  if (x)
626  *x = 0;
627 
628  bool xmlOutput = false;
629 
630  x = strstr(dirname, ".xml");
631  if (x) {
632  *x = 0;
633  xmlOutput = true;
634  }
635 
636  std::string path;
637  path += "/";
638  path += dirname;
639 
640  std::string xpath = HtmlDecode(dirname);
641 
642  //printf("path [%s] dirname [%s] xpath [%s]\n", path.c_str(), dirname, xpath.c_str());
643 
644  TObject* obj = FollowPath(dirname);
645 
646  if (!obj) {
647  std::string reply;
648  std::string buf;
649 
650  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
651 
652  buf = "Not found ";
653  buf += xpath;
654  reply += HtmlTag("title", buf) + "\n";
655  reply += "</head><body>\n";
656  reply += HtmlTag("h1", buf) + "\n";
657 
658  reply += HtmlTag("p", "Object not found");
659 
660  reply += "</body></html>\n";
661  SendHttpReply(sock, "text/html", reply);
662 
663  } else if (obj && obj->InheritsFrom(TDirectory::Class())) {
664  TDirectory* dir = (TDirectory*)obj;
665 
666  std::string reply;
667  std::string buf;
668  std::string xml;
669 
670  xml += "<xml>\n";
671  xml += "<dir>\n";
672 
673  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
674 
675  buf = "Dir ";
676  buf += xpath;
677  reply += HtmlTag("title", buf) + "\n";
678  reply += "</head><body>\n";
679  reply += HtmlTag("h1", buf) + "\n";
680 
681  //printf("Directory %p\n", dir);
682  //dir->Print();
683 
684  std::map<std::string, std::string> alist;
685 
686  if (1) {
687  TList* keys = dir->GetListOfKeys();
688 
689  //printf("Directory %p keys:\n", dir);
690  //keys->Print();
691 
692  TIter next = keys;
693  while(1) {
694  TObject *obj = next();
695 
696  //printf("object %p\n", obj);
697 
698  if (obj == NULL)
699  break;
700 
701  std::string a = HtmlTag("p", MakeHtmlEntry(obj, path.c_str())) + "\n";
702  //alist[objname] = a;
703  reply += a;
704 
705  xml += MakeXmlEntry(obj);
706  }
707  }
708 
709  if (1) {
710  TList* objs = dir->GetList();
711 
712  //printf("Directory %p objects:\n", dir);
713  //objs->Print();
714 
715  TIter next = objs;
716  while(1)
717  {
718  TObject *obj = next();
719 
720  //printf("object %p\n", obj);
721 
722  if (obj == NULL)
723  break;
724 
725  std::string a = HtmlTag("p", MakeHtmlEntry(obj, path.c_str())) + "\n";
726  //alist[objname] = a;
727  reply += a;
728 
729  xml += MakeXmlEntry(obj);
730  }
731  }
732 
733  lock.Unlock();
734 
735  if (1) {
736  std::map<std::string, std::string>::iterator iter = alist.begin();
737  for (; iter!=alist.end(); iter++) {
738  // iter->first is your key
739  // iter->second is it''s value
740  reply += iter->second;
741  }
742  }
743 
744  reply += "</body></html>\n";
745 
746  xml += "</dir></xml>\n";
747 
748  if (xmlOutput)
749  SendHttpReply(sock, "application/xml", xml);
750  else
751  SendHttpReply(sock, "text/html", reply);
752 
753  } else if (obj && obj->InheritsFrom(TFolder::Class())) {
754  TFolder* folder = (TFolder*)obj;
755 
756  //printf("Folder %p\n", folder);
757  //folder->Print();
758 
759  std::string xml;
760 
761  xml += "<xml>\n";
762  xml += "<dir>\n";
763 
764  std::string reply;
765  std::string buf;
766 
767  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
768 
769  buf = "Folder ";
770  buf += xpath;
771  reply += HtmlTag("title", buf) + "\n";
772  reply += "</head><body>\n";
773  reply += HtmlTag("h1", buf) + "\n";
774 
775  TIterator *iterator = folder->GetListOfFolders()->MakeIterator();
776 
777  while (1)
778  {
779  TNamed *obj = (TNamed*)iterator->Next();
780  if (obj == NULL)
781  break;
782 
783  reply += HtmlTag("p", MakeHtmlEntry(obj, path.c_str())) + "\n";
784  xml += MakeXmlEntry(obj);
785  }
786 
787  delete iterator;
788 
789  lock.Unlock();
790 
791  xml += "</dir></xml>\n";
792  reply += "</body></html>\n";
793 
794  if (xmlOutput)
795  SendHttpReply(sock, "application/xml", xml);
796  else
797  SendHttpReply(sock, "text/html", reply);
798 
799  } else if (obj && obj->InheritsFrom(TCollection::Class())) {
800  TCollection* collection = (TCollection*)obj;
801 
802  //printf("Collection %p\n", collection);
803  //collection->Print();
804  //printf("Entries %d\n", collection->GetEntries());
805  //printf("IsEmpty %d\n", collection->IsEmpty());
806 
807  std::string xml;
808 
809  xml += "<xml>\n";
810  xml += "<dir>\n";
811 
812  std::string reply;
813  std::string buf;
814 
815  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
816 
817  buf = "Collection ";
818  buf += xpath;
819  reply += HtmlTag("title", buf) + "\n";
820  reply += "</head><body>\n";
821  reply += HtmlTag("h1", buf) + "\n";
822 
823  TIterator *iterator = collection->MakeIterator();
824 
825  while (1)
826  {
827  TNamed *obj = (TNamed*)iterator->Next();
828  if (obj == NULL)
829  break;
830 
831  reply += HtmlTag("p", MakeHtmlEntry(obj, path.c_str())) + "\n";
832  xml += MakeXmlEntry(obj);
833  }
834 
835  delete iterator;
836 
837  lock.Unlock();
838 
839  xml += "</dir></xml>\n";
840  reply += "</body></html>\n";
841 
842  if (xmlOutput)
843  SendHttpReply(sock, "application/xml", xml);
844  else
845  SendHttpReply(sock, "text/html", reply);
846 
847  } else {
848  if (xmlOutput) {
849  std::string xml;
850  xml += "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
851  xml += "<xml>\n";
852  xml += "<ROOTobject>\n";
853  TString msg = TBufferXML::ConvertToXML(obj);
854  xml += msg;
855  xml += "</ROOTobject>\n";
856  xml += "</xml>\n";
857  lock.Unlock();
858  SendHttpReply(sock, "application/xml", xml);
859  } else {
860  SendFile(sock, "plot.html", "text/html");
861  if (0) {
862  std::string reply;
863  std::string buf;
864 
865  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
866 
867  buf = "Object ";
868  buf += xpath;
869  reply += HtmlTag("title", buf) + "\n";
870  reply += "</head><body>\n";
871  reply += HtmlTag("h1", buf) + "\n";
872 
873  reply += HtmlTag("p", obj->GetName());
874  reply += HtmlTag("p", obj->ClassName());
875 
876  reply += "</body></html>\n";
877  SendHttpReply(sock, "text/html", reply);
878  }
879  }
880  }
881  }
882 #if 0
883  else if (strncmp(request, "ResetTH1 ", 9) == 0)
884  {
885  XLockRootGuard lock;
886 
887  char* path = request + 9;
888 
889  if (strlen(path) > 1)
890  {
891  TObject *obj = FollowPath(path);
892 
893  if (obj)
894  ResetObject(obj);
895  }
896  else
897  {
898  for (unsigned int i=0; i<gExports.size(); i++)
899  {
900  const char* ename = gExports[i].c_str();
901  const char* xname = gExportNames[ename].c_str();
902 
903  TObject* obj = FindTopLevelObject(xname);
904 
905  if (!obj)
906  {
907  fprintf(stderr, "XmlServer: ResetTH1: Exported name \'%s\' cannot be found!\n", xname);
908  continue;
909  }
910 
911  ResetObject(obj);
912  }
913  }
914 
915  //TObjString s("Success");
916 
917  //message.Reset(kMESS_OBJECT);
918  //message.WriteObject(&s);
919  lock.Unlock();
920  //sock->Send(message);
921 
922  const char *msg = "Success";
923  sock->SendRaw(msg, strlen(msg) + 1);
924  }
925 #endif
926  else
927  {
928  fprintf(stderr, "XmlServer: Received unknown request \"%s\"\n", request);
929 
930  std::string reply;
931  reply += "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n";
932  reply += HtmlTag("title", "Unknown request") + "\n";
933  reply += "</head><body>\n";
934  reply += HtmlTag("h1", "Unknown request") + "\n";
935  reply += HtmlTag("p", request) + "\n";
936  reply += "</body></html>\n";
937  SendHttpReply(sock, "text/html", reply);
938  }
939  } while (1);
940 
941  return THREADRETURN;
942 }
943 
944 /*------------------------------------------------------------------*/
945 
946 static THREADTYPE xsocket_listener(void *arg)
947 {
948  // Server loop listening for incoming network connections on specified port.
949  // Starts a searver_thread for each connection.
950 
951  int port = *(int *) arg;
952 
953  fprintf(stderr, "XmlServer: Listening on port %d...\n", port);
954  TServerSocket *lsock = new TServerSocket(port, kTRUE);
955 
956  while (1)
957  {
958  TSocket *sock = lsock->Accept();
959 
960  if (sock==NULL)
961  {
962  fprintf(stderr, "XmlServer: TSocket->Accept() error\n");
963  break;
964  }
965 
966  if (gVerbose)
967  fprintf(stderr, "XmlServer: connection from %s\n", sock->GetInetAddress().GetHostName());
968 
969 #if 1
970  TThread *thread = new TThread("XmlServer", xroot_server_thread, sock);
971  thread->Run();
972 #else
973  LPDWORD lpThreadId = 0;
974  CloseHandle(CreateThread(NULL, 1024, &xroot_server_thread, sock, 0, lpThreadId));
975 #endif
976  }
977 
978  return THREADRETURN;
979 }
980 
981 /*------------------------------------------------------------------*/
982 
983 void XmlServer::SetVerbose(bool verbose)
984 {
985  gVerbose = verbose;
986 }
987 
988 /*------------------------------------------------------------------*/
989 
990 void XmlServer::Export(TDirectory* dir, const char* exportName)
991 {
992  if (gVerbose)
993  printf("Export TDirectory %p named [%s] of type [%s] as [%s]\n", dir, dir->GetName(), dir->IsA()->GetName(), exportName);
994 
995  bool found = false;
996  for (unsigned int i=0; i<gExports.size(); i++)
997  {
998  const char* ename = gExports[i].c_str();
999  if (strcmp(ename, exportName) == 0)
1000  found = true;
1001  }
1002 
1003  if (!found)
1004  gExports.push_back(exportName);
1005  gExportNames[exportName] = dir->GetName();
1006 }
1007 
1008 void XmlServer::Export(TFolder* folder, const char* exportName)
1009 {
1010  if (gVerbose)
1011  printf("Export TFolder %p named [%s] of type [%s] as [%s]\n", folder, folder->GetName(), folder->IsA()->GetName(), exportName);
1012 
1013  bool found = false;
1014  for (unsigned int i=0; i<gExports.size(); i++)
1015  {
1016  const char* ename = gExports[i].c_str();
1017  if (strcmp(ename, exportName) == 0)
1018  found = true;
1019  }
1020 
1021  if (!found)
1022  gExports.push_back(exportName);
1023  gExportNames[exportName] = folder->GetName();
1024 }
1025 
1026 void XmlServer::Export(TCollection* collection, const char* exportName)
1027 {
1028  if (gVerbose)
1029  printf("Export TCollection %p named [%s] of type [%s] as [%s]\n", collection, collection->GetName(), collection->IsA()->GetName(), exportName);
1030 
1031  bool found = false;
1032  for (unsigned int i=0; i<gExports.size(); i++)
1033  {
1034  const char* ename = gExports[i].c_str();
1035  if (strcmp(ename, exportName) == 0)
1036  found = true;
1037  }
1038 
1039  if (!found)
1040  gExports.push_back(exportName);
1041  gExportNames[exportName] = collection->GetName();
1042 }
1043 
1044 void XmlServer::Start(int port)
1045 {
1046  if (port==0)
1047  return;
1048 
1049  //printf("Here!\n");
1050 
1051  static int pport = port;
1052 #if 1
1053  TThread *thread = new TThread("XmlServer", xsocket_listener, &pport);
1054  thread->Run();
1055 #else
1056  LPDWORD lpThreadId = 0;
1057  CloseHandle(CreateThread(NULL, 1024, &xroot_socket_server, &pport, 0, lpThreadId));
1058 #endif
1059 }
1060 
1061 /* emacs
1062  * Local Variables:
1063  * tab-width: 8
1064  * c-basic-offset: 3
1065  * indent-tabs-mode: nil
1066  * End:
1067  */
virtual TList * GetList() const
virtual TList * GetListOfKeys() const
void Export(TDirectory *dir, const char *exportName)
Definition: xmlServer.cxx:990
void SetVerbose(bool verbose)
Definition: xmlServer.cxx:983
void Start(int port)
Definition: xmlServer.cxx:1044
static void ResetObject(TObject *obj)
static std::string HtmlDecode(const char *s)
Definition: xmlServer.cxx:131
std::string MakeHtmlEntry(const TObject *obj, const char *path)
Definition: xmlServer.cxx:404
std::string MakeXmlEntry(const TObject *obj)
Definition: xmlServer.cxx:372
static std::deque< std::string > gExports
Definition: xmlServer.cxx:77
static TObject * FollowPath(TObject *container, char *path)
Definition: xmlServer.cxx:156
#define THREADRETURN
Definition: xmlServer.cxx:21
static std::string HtmlTag(const char *tag, const char *contents)
Definition: xmlServer.cxx:344
#define THREADTYPE
Definition: xmlServer.cxx:22
static bool gVerbose
Definition: xmlServer.cxx:75
static std::map< std::string, std::string > gExportNames
Definition: xmlServer.cxx:78
static TObject * TopLevel(char *path, char **opath)
Definition: xmlServer.cxx:218
static std::string UrlEncode(const char *s)
Definition: xmlServer.cxx:101
static void SendString(TSocket *sock, const char *str)
Definition: xmlServer.cxx:314
static THREADTYPE xsocket_listener(void *arg)
Definition: xmlServer.cxx:946
static void SendHttpReply(TSocket *sock, const char *mimetype, const char *message)
Definition: xmlServer.cxx:319
static std::string HtmlEncode(const char *s)
Definition: xmlServer.cxx:82
static THREADTYPE xroot_server_thread(void *arg)
Definition: xmlServer.cxx:471
static TObject * FindTopLevelObject(const char *name)
Definition: xmlServer.cxx:201
static int atohex(int a)
Definition: xmlServer.cxx:120
static void SendFile(TSocket *sock, const char *filename, const char *mimetype)
Definition: xmlServer.cxx:444