00001 # HTTP server in ROOT
00002
00003 The idea of THttpServer is to provide remote http access to running ROOT application and enable HTML/JavaScript user interface. Any registered object can be requested and displayed in the web browser. There are many benefits of such approach:
00004
00005 * standard http interface to ROOT application
00006 * no any temporary ROOT files to access data
00007 * user interface running in all browsers
00008
00009 ## Starting the HTTP server
00010
00011 To start the http server, at any time, create an instance of the [THttpServer](https:
00012
00013 serv = new THttpServer("http:8080");
00014
00015 This will start a [civetweb](https:
00016
00017 There is a [snapshot (frozen copy)](https:
00018
00019 <iframe width="800" height="500" src="https://root.cern.ch/js/latest/httpserver.C/?layout=simple&item=Canvases/c1">
00020 </iframe>
00021
00022 One could specify several options when creating http server. They could be add as additional URL parameters to the constructor arguments like:
00023
00024 serv = new THttpServer("http:8080?loopback&thrds=2");
00025
00026 Following parameters are supported:
00027
00028 - thrds=N - number of threads used by the civetweb (default is 5)
00029 - top=name - configure top name, visible in the web browser
00030 - auth_file=filename - authentication file name, created with htdigets utility
00031 - auth_domain=domain - authentication domain
00032 - loopback - bind specified port to loopback 127.0.0.1 address
00033 - debug - enable debug mode, server always returns html page with request info
00034
00035 If necessary, one could bind http server to specific IP address like:
00036
00037 new THttpServer("http:192.168.1.17:8080")
00038
00039
00040
00041 ## Registering objects
00042
00043 At any time, one could register other objects with the command:
00044
00045 TGraph* gr = new TGraph(10);
00046 gr->SetName("gr1");
00047 serv->Register("graphs/subfolder", gr);
00048
00049 One should specify sub-folder name, where objects will be registered.
00050 If sub-folder name does not starts with slash `/`, than top-name folder `/Objects/` will be prepended.
00051 At any time one could unregister objects:
00052
00053 serv->Unregister(gr);
00054
00055 THttpServer does not take ownership over registered objects - they should be deleted by user.
00056
00057 If the objects content is changing in the application, one could enable monitoring flag in the browser - then objects view will be regularly updated.
00058
00059
00060 ## Command interface
00061
00062 THttpServer class provide simple interface to invoke command from web browser.
00063 One just register command like:
00064
00065 serv->RegisterCommand("/DoSomething","SomeFunction()");
00066
00067 Element with name `DoSomething` will appear in the web browser and can be clicked.
00068 It will result in `gROOT->ProcessLineSync("SomeFunction()")` call.
00069
00070 One could configure argument(s) for the command.
00071 For that one should use `%arg1`, `%arg2` and so on identifiers. Like:
00072
00073 serv->RegisterCommand("/DoSomething","SomeFunction(%arg1%,%arg2%)");
00074
00075 User will be requested to enter arguments values, when command element clicked in the browser.
00076 Example of the command which executes arbitrary string in appliction via ProcessLine looks like:
00077
00078 serv->RegisterCommand("/Process","%arg1%");
00079
00080 When registering command, one could specify icon name which will be displayed with the command.
00081
00082 serv->RegisterCommand("/DoSomething","SomeFunction()", "rootsys/icons/ed_execute.png");
00083
00084 In example usage of images from `$ROOTSYS/icons` directory is shown. One could prepend `button;`
00085 string to the icon name to let browser show command as extra button. In last case one could hide command element from elements list:
00086
00087 serv->Hide("/DoSomething");
00088
00089 One can find example of command interface usage in [tutorials/http/httpcontrol.C](https:
00090
00091
00092
00093 ## Configuring user access
00094
00095 By default, the http server is open for anonymous access. One could restrict the access to the server for authenticated users only. First of all, one should create a password file, using the **htdigest** utility.
00096
00097 [shell] htdigest -c .htdigest domain_name user_name
00098
00099 It is recommended not to use special symbols in domain or user names. Several users can be add to the ".htdigest" file. When starting the server, the following arguments should be specified:
00100
00101 root [0] new THttpServer("http:8080?auth_file=.htdigest&auth_domain=domain_name");
00102
00103 After that, the web browser will automatically request to input a name/password for the domain "domain_name"
00104
00105 Based on authorized accounts, one could restrict or enable access to some elements in the server objects hierarchy, using THttpServer::Restrict() method.
00106
00107 For instance, one could hide complete folder from 'guest' account:
00108
00109 root [6] serv->Restrict("/Folder", "hidden=guest");
00110
00111 Or one could hide from all but 'admin' account:
00112
00113 root [7] serv->Restrict("/Folder", "visible=admin");
00114
00115 Hidden folders or objects can not be accessed via http protocol.
00116
00117 By default server runs in readonly mode and do not allow methods execution via 'exe.json' or 'exe.bin' requests. To allow such action, one could either grant generic access for all or one could allow to execute only special method:
00118
00119 root [8] serv->Restrict("/Folder/histo1", "allow=all");
00120 root [9] serv->Restrict("/Folder/histo1", "allow_method=GetTitle");
00121
00122 One could provide several options for the same item, separating them with '&' sign:
00123
00124 root [10] serv->Restrict("/Folder/histo1", "allow_method=GetTitle&hide=guest");
00125
00126 Complete list of supported options could be found in [TRootSniffer:Restrict()](https:
00127
00128
00129 ## Using FastCGI interface
00130
00131 [FastCGI](http:
00132
00133 When starting THttpServer, one could specify:
00134
00135 serv = new THttpServer("fastcgi:9000");
00136
00137 In fact, the FastCGI interface can run in parallel to http server. One can just call:
00138
00139 serv = new THttpServer("http:8080");
00140 serv->CreateEngine("fastcgi:9000");
00141
00142 One could specify a debug parameter to be able to adjust the FastCGI configuration on the web server:
00143
00144 serv->CreateEngine("fastcgi:9000?debug=1");
00145
00146 All user access will be ruled by the main web server. Authorized account names could be used to configure access restriction in THttpServer.
00147
00148 ### Configure fastcgi with Apcahe2
00149
00150 First of all, one should compile and install [mod_fastcgi](http:
00151 Then *mod_fastcgi* should be specified in httpd.conf to load it when Apache server is started.
00152 Finally in host configuration file one should have following lines:
00153
00154 <IfModule mod_fastcgi.c>
00155 FastCgiExternalServer "/srv/www/htdocs/root.app" -host rootapp_host_name:9000
00156 </IfModule>
00157
00158 Here is supposed that directory "/srv/www/htdocs" is root directory for web server.
00159 Than one should be able to open address:
00160
00161 http:
00162
00163 There are many ways to configure user authentication in Apache. Example of digest for FastCGI server:
00164
00165 <Location "/root.app/">
00166 AuthType Digest
00167 AuthName "root"
00168 AuthDigestDomain "/root.app/" "root"
00169 AuthDigestProvider file
00170 AuthUserFile "/srv/auth/auth.txt"
00171 Require valid-user
00172 </Location>
00173
00174
00175
00176 ### Configure fastcgi with lighttpd
00177
00178 An example of configuration file for *lighttpd* server is:
00179
00180 server.modules += ( "mod_fastcgi" )
00181 fastcgi.server = (
00182 "/root.app" =>
00183 (( "host" => "192.168.1.11",
00184 "port" => 9000,
00185 "check-local" => "disable",
00186 "docroot" => "/"
00187 ))
00188 )
00189
00190 Be aware, that with *lighttpd* one should specify IP address of the host, where ROOT application is running. Address of the ROOT application will be following:
00191
00192 http:
00193
00194 Example of authorization configuration for FastCGI connection:
00195
00196 auth.require = ( "/root.app" => (
00197 "method" => "digest",
00198 "realm" => "root",
00199 "require" => "valid-user"
00200 ) )
00201
00202
00203 ## Integration with existing applications
00204
00205 In many practical cases no change of existing code is required. Opened files (and all objects inside), existing canvas and histograms are automatically scanned by the server and will be available to the users. If necessary, any object can be registered directly to the server with a **`THttpServer::Register()`** call.
00206
00207 Central point of integration - when and how THttpServer get access to data from a running application. By default it is done during the gSystem->ProcessEvents() call - THttpServer uses a synchronous timer which is activated every 100 ms. Such approach works perfectly when running macros in an interactive ROOT session.
00208
00209 If an application runs in compiled code and does not contain gSystem->ProcessEvents() calls, two method are available.
00210
00211 ### Asynchronous timer
00212
00213 The first method is to configure an asynchronous timer for the server, like for example:
00214
00215 serv->SetTimer(100, kFALSE);
00216
00217 Then, the timer will be activated even without any gSystem->ProcessEvents() method call. The main advantage of such method is that the application code can be used without any modifications. But there is no control when access to the application data is performed. It could happen just in-between of **`TH1::Fill()`** calls and an histogram object may be incomplete. Therefore such method is not recommended.
00218
00219
00220 ### Regular calls of THttpServer::ProcessRequests() method
00221
00222 The second method is preferable - one just inserts in the application regular calls of the THttpServer::ProcessRequests() method, like:
00223
00224 serv->ProcessRequests();
00225
00226 In such case, one can fully disable the timer of the server:
00227
00228 serv->SetTimer(0, kTRUE);
00229
00230
00231
00232 ## Data access from command shell
00233
00234 The big advantage of the http protocol is that it is not only supported in web browsers, but also in many other applications. One could use http requests to directly access ROOT objects and data members from any kind of scripts.
00235
00236 If one starts a server and register an object like for example:
00237
00238 root [1] serv = new THttpServer("http:8080");
00239 root [2] TNamed* n1 = new TNamed("obj", "title");
00240 root [3] serv->Register("subfolder", n1);
00241
00242 One could request a JSON representation of such object with the command:
00243
00244 [shell] wget http:
00245
00246 Then, its representation will look like:
00247
00248 {
00249 "_typename" : "TNamed",
00250 "fUniqueID" : 0,
00251 "fBits" : 50331656,
00252 "fName" : "obj",
00253 "fTitle" : "title"
00254 }
00255
00256 The following requests can be performed:
00257
00258 - `root.bin` - binary data produced by object streaming with TBufferFile
00259 - `root.json` - ROOT JSON representation for object and objects members
00260 - `root.xml` - ROOT XML representation
00261 - `root.png` - PNG image (if object drawing implemented)
00262 - `root.gif` - GIF image
00263 - `root.jpeg` - JPEG image
00264 - `exe.json` - method execution in the object
00265 - `exe.bin` - method execution, return result in binary form
00266 - `cmd.json` - command execution
00267 - `item.json` - item (object) properties, specified on the server
00268 - `multi.json` - perform several requests at once
00269 - `multi.bin` - perform several requests at once, return result in binary form
00270
00271 All data will be automatically zipped if '.gz' extension is appended. Like:
00272
00273 [shell] wget http:
00274
00275 If the access to the server is restricted with htdigest, it is recommended to use the **curl** program since only curl correctly implements such authentication method. The command will look like:
00276
00277 [shell] curl --user "accout:password" http:
00278
00279
00280 ### Objects data access in JSON format
00281
00282 Request `root.json` implemented with [TBufferJSON](https:
00283
00284 [shell] wget http:
00285
00286 The result will be: "title".
00287
00288 For the `root.json` request one could specify the 'compact' parameter, which allow to reduce the number of spaces and new lines without data lost. This parameter can have values from '0' (no compression) till '3' (no spaces and new lines at all).
00289
00290 Usage of `root.json` request is about as efficient as binary `root.bin` request. Comparison of different request methods with TH1 object shown in the table:
00291
00292 | Request | Size |
00293 | :---------------------- | :--------- |
00294 | root.bin | 1658 bytes |
00295 | root.bin.gz | 782 bytes |
00296 | root.json | 7555 bytes |
00297 | root.json?compact=3 | 5381 bytes |
00298 | root.json.gz?compact=3 | 1207 bytes |
00299
00300 One should remember that JSON representation always includes names of the data fields which are not present in the binary representation. Even then the size difference is negligible.
00301
00302 `root.json` used in JSROOT to request objects from THttpServer.
00303
00304
00305 ### Generating images out of objects
00306
00307 For the ROOT classes which are implementing Draw method (like [TH1](https:
00308 one could produce images with requests: `root.png`, `root.gif`, `root.jpeg`. For example:
00309
00310 wget "http://localhost:8080/Files/hsimple.root/hpx/root.png?w=500&h=500&opt=lego1" -O lego1.png
00311
00312 For all such requests following parameters could be specified:
00313
00314 - `h` - image height
00315 - `w` - image width
00316 - `opt` - draw options
00317
00318
00319 ### Methods execution
00320
00321 By default THttpServer starts in monitoring (read-only) mode and therefore forbid any methods execution. One could specify read-write mode when server is started:
00322
00323 serv = new THttpServer("http:8080;rw");
00324
00325 Or one could disable read-only mode with the call:
00326
00327 serv->SetReadOnly(kFALSE);
00328
00329 Or one could allow access to the folder, object or specific object methods with:
00330
00331 serv->Restrict("/Histograms", "allow=admin");
00332 serv->Restrict("/Histograms/hist1", "allow=all");
00333 serv->Restrict("/Histograms/hist1", "allow_method=Rebin");
00334
00335 'exe.json' accepts following parameters:
00336
00337 - `method` - name of method to execute
00338 - `prototype` - method prototype (see [TClass::GetMethodWithPrototype](https:
00339 - `compact` - compact parameter, used to compress return value
00340 - `_ret_object_` - name of the object which should be returned as result of method execution (used together with remote TTree::Draw call)
00341
00342 Example of retrieving object title:
00343
00344 [shell] wget 'http://localhost:8080/Objects/subfolder/obj/exe.json?method=GetTitle' -O title.json
00345
00346 Example of TTree::Draw method execution:
00347
00348 [shell] wget 'http://localhost:8080/Files/job1.root/ntuple/exe.json?method=Draw&prototype="Option_t*"&opt="px:py>>h1"&_ret_object_=h1' -O exe.json
00349
00350 One also used `exe.bin` method - in this case results of method execution will be returned in binary format. In case when method returns temporary object, which should be delete at the end of command execution, one should specify `_destroy_result_` parameter in the URL string:
00351
00352 [shell] wget 'http://localhost:8080/Objects/subfolder/obj/exe.json?method=Clone&_destroy_result_' -O clone.json
00353
00354 If method required object as argument, it could be posted in binary or XML format as POST request. If binary form is used, one should specify following parameters:
00355
00356 [shell] wget 'http://localhost:8080/hist/exe.json?method=Add&h1=_post_object_&_post_class_=TH1I&c1=10' --post-file=h.bin -O res.json
00357
00358 Here is important to specify post object class, which is not stored in the binary buffer. When used XML form (produced with [TBufferXML::ConvertToXML](https:
00359
00360 [shell] wget 'http://localhost:8080/hist/exe.json?method=Add&h1=_post_object_xml_&c1=10' --post-file=h.xml -O res.json
00361
00362 To get debug information about command execution, one could submit `exe.txt` request with same arguments.
00363
00364
00365 ### Commands execution
00366
00367 If command registered to the server:
00368
00369 serv->RegisterCommand("/Folder/Start", "DoSomthing()");
00370
00371 It can be invoked with `cmd.json` request like:
00372
00373 [shell] wget http:
00374
00375 If command fails, `false` will be returned, otherwise result of gROOT->ProcessLineSync() execution.
00376
00377 If command definition include arguments:
00378
00379 serv->RegisterCommand("/ResetCounter", "DoReset(%arg1%,%arg2%)");
00380
00381 One could specify them in the URL string:
00382
00383 [shell] wget http:
00384
00385
00386
00387 ### Performing multiple requests at once
00388
00389 To minimize traffic between sever and client, one could submit several requests at once. This is especially useful when big number of small objects should be requestsed simultaneosely. For this purposes `multi.bin` or `multi.json` requests could be used.
00390 Both require string as POST data which format as:
00391
00392 subfolder/item1/root.json\n
00393 subfolder/item2/root.json\n
00394 subfolder/item1/exe.json?method=GetTitle\n
00395
00396 If such requests saved in 'req.txt' file, one could submit it with command:
00397
00398 [shell] wget http:
00399
00400 For `multi.json` request one could use only requests, returning JSON format (like `root.json` or `exe.json`). Result will be JSON array.
00401 For `multi.bin` any kind of requests can be used. It returns binary buffer with following content:
00402
00403 [size1 (little endian), 4 bytes] + [request1 result, size1 bytes]
00404 [size2 (little endian), 4 bytes] + [request2 result, size2 bytes]
00405 [size3 (little endian), 4 bytes] + [request3 result, size3 bytes]
00406
00407 While POST data in request used to transfer list of multiple reqeusts, it is not possible to submit
00408 such kind of requests, which themselvs require data from POST block.