// $Id$
// Author: Sergey Linev   21/12/2013

#include "TCivetweb.h"

#include "../civetweb/civetweb.h"

#include <stdlib.h>

#include "THttpServer.h"
#include "TUrl.h"

static int begin_request_handler(struct mg_connection *conn)
{
   TCivetweb *engine = (TCivetweb *) mg_get_request_info(conn)->user_data;
   if (engine == 0) return 0;
   THttpServer *serv = engine->GetServer();
   if (serv == 0) return 0;

   const struct mg_request_info *request_info = mg_get_request_info(conn);

   THttpCallArg arg;

   TString filename;

   Bool_t execres = kTRUE;

   if (serv->IsFileRequested(request_info->uri, filename)) {
      if ((filename.Index(".js")!=kNPOS) || (filename.Index(".css")!=kNPOS)) {
         Int_t length = 0;
         char *buf = THttpServer::ReadFileContent(filename.Data(), length);
         if (buf==0) {
            arg.Set404();
         } else {
            arg.SetContentType(THttpServer::GetMimeType(filename.Data()));
            arg.SetBinData(buf, length);
            arg.AddHeader("Cache-Control", "max-age=3600");
            arg.SetZipping(2);
         }
      } else {
         arg.SetFile(filename.Data());
      }
   } else {
      arg.SetPathAndFileName(request_info->uri); // path and file name
      arg.SetQuery(request_info->query_string);  //! additional arguments
      arg.SetTopName(engine->GetTopName());

      execres = serv->ExecuteHttp(&arg);
   }

   if (!execres || arg.Is404()) {
      TString hdr;
      arg.FillHttpHeader(hdr, "HTTP/1.1");
      mg_printf(conn, "%s", hdr.Data());
   } else
   if (arg.IsFile()) {
      mg_send_file(conn, (const char *) arg.GetContent());
   } else {

      Bool_t dozip = arg.GetZipping() > 0;
      switch (arg.GetZipping()) {
         case 2: if (arg.GetContentLength() < 10000) { dozip = kFALSE; break; }
         case 1:
            // check if request header has Accept-Encoding
            dozip = kFALSE;
            for (int n=0;n<request_info->num_headers;n++) {
               TString name = request_info->http_headers[n].name;
               if (name.Index("Accept-Encoding", 0, TString::kIgnoreCase)!=0) continue;
               TString value = request_info->http_headers[n].value;
               dozip = (value.Index("gzip", 0, TString::kIgnoreCase)!=kNPOS);
               break;
            }

            break;
         case 3: dozip = kTRUE; break;
      }

      if (dozip) arg.CompressWithGzip();

      TString hdr;
      arg.FillHttpHeader(hdr, "HTTP/1.1");
      mg_printf(conn, "%s", hdr.Data());

      if (arg.GetContentLength() > 0)
         mg_write(conn, arg.GetContent(), (size_t) arg.GetContentLength());
   }

   // Returning non-zero tells civetweb that our function has replied to
   // the client, and civetweb should not send client any more data.
   return 1;
}


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TCivetweb                                                            //
//                                                                      //
// http server implementation, based on civetweb embedded server        //
// It is default kind of engine, created for THttpServer                //
//                                                                      //
// Following additional options can be specified                        //
//    top=foldername - name of top folder, seen in the browser          //
//    thrds=N - use N threads to run civetweb server (default 5)        //
//    auth_file - global authentication file                            //
//    auth_domain - domain name, used for authentication                //
//                                                                      //
// Example:                                                             //
//    new THttpServer("http:8080?top=MyApp&thrds=3");                   //
//                                                                      //
// Authentication:                                                      //
//    When auth_file and auth_domain parameters are specified, access   //
//    to running http server will be possible only after user           //
//    authentication, using so-call digest method. To generate          //
//    authentication file, htdigest routine should be used:             //
//                                                                      //
//        [shell] htdigest -c .htdigest domain_name user                //
//                                                                      //
//    When creating server, parameters should be:                       //
//                                                                      //
//       new THttpServer("http:8080?auth_file=.htdigets&auth_domain=domain_name");  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


//______________________________________________________________________________
TCivetweb::TCivetweb() :
   THttpEngine("civetweb", "compact embedded http server"),
   fCtx(0),
   fCallbacks(0),
   fTopName()
{
   // constructor
}

//______________________________________________________________________________
TCivetweb::~TCivetweb()
{
   // destructor

   if (fCtx != 0) mg_stop((struct mg_context *) fCtx);
   if (fCallbacks != 0) free(fCallbacks);
   fCtx = 0;
   fCallbacks = 0;
}

//______________________________________________________________________________
Bool_t TCivetweb::Create(const char *args)
{
   // Creates embedded civetweb server
   // As argument, http port should be specified in form "8090"
   // One could provide extra parameters after '?' (like URL parameters)
   //    thrds=N   - there N is number of threads used by the civetweb (default is 5)
   //    top=name  - configure top name, visible at the web browser
   //    auth_file=filename  - authentication file name, created with htdigets utility
   //    auth_domain=domain   - authentication domain

   fCallbacks = malloc(sizeof(struct mg_callbacks));
   memset(fCallbacks, 0, sizeof(struct mg_callbacks));
   ((struct mg_callbacks *) fCallbacks)->begin_request = begin_request_handler;

   TString sport = "8080";
   TString num_threads = "5";
   TString auth_file, auth_domain;

   // extract arguments
   if ((args != 0) && (strlen(args) > 0)) {

      // first extract port number
      sport = "";
      while ((*args!=0) && (*args>='0') && (*args<='9'))
         sport.Append(*args++);

      // than search for extra parameters
      while ((*args!=0) && (*args!='?')) args++;

      if (*args=='?') {
         TUrl url(TString::Format("http://localhost/folder%s", args));

         if (url.IsValid()) {
            url.ParseOptions();

            const char *top = url.GetValueFromOptions("top");
            if (top != 0) fTopName = top;

            Int_t thrds = url.GetIntValueFromOptions("thrds");
            if (thrds > 0) num_threads.Form("%d", thrds);

            const char *afile = url.GetValueFromOptions("auth_file");
            if (afile != 0) auth_file = afile;

            const char *adomain = url.GetValueFromOptions("auth_domain");
            if (adomain != 0) auth_domain = adomain;
         }
      }
   }

   const char *options[100];
   int op(0);

   Info("Create", "Starting HTTP server on port %s", sport.Data());

   options[op++] = "listening_ports";
   options[op++] = sport.Data();
   options[op++] = "num_threads";
   options[op++] = num_threads.Data();

   if ((auth_file.Length() > 0) && (auth_domain.Length() > 0)) {
      options[op++] = "global_auth_file";
      options[op++] = auth_file.Data();
      options[op++] = "authentication_domain";
      options[op++] = auth_domain.Data();
   }

   options[op++] = 0;

   // Start the web server.
   fCtx = mg_start((struct mg_callbacks *) fCallbacks, this, options);

   return kTRUE;
}

 TCivetweb.cxx:1
 TCivetweb.cxx:2
 TCivetweb.cxx:3
 TCivetweb.cxx:4
 TCivetweb.cxx:5
 TCivetweb.cxx:6
 TCivetweb.cxx:7
 TCivetweb.cxx:8
 TCivetweb.cxx:9
 TCivetweb.cxx:10
 TCivetweb.cxx:11
 TCivetweb.cxx:12
 TCivetweb.cxx:13
 TCivetweb.cxx:14
 TCivetweb.cxx:15
 TCivetweb.cxx:16
 TCivetweb.cxx:17
 TCivetweb.cxx:18
 TCivetweb.cxx:19
 TCivetweb.cxx:20
 TCivetweb.cxx:21
 TCivetweb.cxx:22
 TCivetweb.cxx:23
 TCivetweb.cxx:24
 TCivetweb.cxx:25
 TCivetweb.cxx:26
 TCivetweb.cxx:27
 TCivetweb.cxx:28
 TCivetweb.cxx:29
 TCivetweb.cxx:30
 TCivetweb.cxx:31
 TCivetweb.cxx:32
 TCivetweb.cxx:33
 TCivetweb.cxx:34
 TCivetweb.cxx:35
 TCivetweb.cxx:36
 TCivetweb.cxx:37
 TCivetweb.cxx:38
 TCivetweb.cxx:39
 TCivetweb.cxx:40
 TCivetweb.cxx:41
 TCivetweb.cxx:42
 TCivetweb.cxx:43
 TCivetweb.cxx:44
 TCivetweb.cxx:45
 TCivetweb.cxx:46
 TCivetweb.cxx:47
 TCivetweb.cxx:48
 TCivetweb.cxx:49
 TCivetweb.cxx:50
 TCivetweb.cxx:51
 TCivetweb.cxx:52
 TCivetweb.cxx:53
 TCivetweb.cxx:54
 TCivetweb.cxx:55
 TCivetweb.cxx:56
 TCivetweb.cxx:57
 TCivetweb.cxx:58
 TCivetweb.cxx:59
 TCivetweb.cxx:60
 TCivetweb.cxx:61
 TCivetweb.cxx:62
 TCivetweb.cxx:63
 TCivetweb.cxx:64
 TCivetweb.cxx:65
 TCivetweb.cxx:66
 TCivetweb.cxx:67
 TCivetweb.cxx:68
 TCivetweb.cxx:69
 TCivetweb.cxx:70
 TCivetweb.cxx:71
 TCivetweb.cxx:72
 TCivetweb.cxx:73
 TCivetweb.cxx:74
 TCivetweb.cxx:75
 TCivetweb.cxx:76
 TCivetweb.cxx:77
 TCivetweb.cxx:78
 TCivetweb.cxx:79
 TCivetweb.cxx:80
 TCivetweb.cxx:81
 TCivetweb.cxx:82
 TCivetweb.cxx:83
 TCivetweb.cxx:84
 TCivetweb.cxx:85
 TCivetweb.cxx:86
 TCivetweb.cxx:87
 TCivetweb.cxx:88
 TCivetweb.cxx:89
 TCivetweb.cxx:90
 TCivetweb.cxx:91
 TCivetweb.cxx:92
 TCivetweb.cxx:93
 TCivetweb.cxx:94
 TCivetweb.cxx:95
 TCivetweb.cxx:96
 TCivetweb.cxx:97
 TCivetweb.cxx:98
 TCivetweb.cxx:99
 TCivetweb.cxx:100
 TCivetweb.cxx:101
 TCivetweb.cxx:102
 TCivetweb.cxx:103
 TCivetweb.cxx:104
 TCivetweb.cxx:105
 TCivetweb.cxx:106
 TCivetweb.cxx:107
 TCivetweb.cxx:108
 TCivetweb.cxx:109
 TCivetweb.cxx:110
 TCivetweb.cxx:111
 TCivetweb.cxx:112
 TCivetweb.cxx:113
 TCivetweb.cxx:114
 TCivetweb.cxx:115
 TCivetweb.cxx:116
 TCivetweb.cxx:117
 TCivetweb.cxx:118
 TCivetweb.cxx:119
 TCivetweb.cxx:120
 TCivetweb.cxx:121
 TCivetweb.cxx:122
 TCivetweb.cxx:123
 TCivetweb.cxx:124
 TCivetweb.cxx:125
 TCivetweb.cxx:126
 TCivetweb.cxx:127
 TCivetweb.cxx:128
 TCivetweb.cxx:129
 TCivetweb.cxx:130
 TCivetweb.cxx:131
 TCivetweb.cxx:132
 TCivetweb.cxx:133
 TCivetweb.cxx:134
 TCivetweb.cxx:135
 TCivetweb.cxx:136
 TCivetweb.cxx:137
 TCivetweb.cxx:138
 TCivetweb.cxx:139
 TCivetweb.cxx:140
 TCivetweb.cxx:141
 TCivetweb.cxx:142
 TCivetweb.cxx:143
 TCivetweb.cxx:144
 TCivetweb.cxx:145
 TCivetweb.cxx:146
 TCivetweb.cxx:147
 TCivetweb.cxx:148
 TCivetweb.cxx:149
 TCivetweb.cxx:150
 TCivetweb.cxx:151
 TCivetweb.cxx:152
 TCivetweb.cxx:153
 TCivetweb.cxx:154
 TCivetweb.cxx:155
 TCivetweb.cxx:156
 TCivetweb.cxx:157
 TCivetweb.cxx:158
 TCivetweb.cxx:159
 TCivetweb.cxx:160
 TCivetweb.cxx:161
 TCivetweb.cxx:162
 TCivetweb.cxx:163
 TCivetweb.cxx:164
 TCivetweb.cxx:165
 TCivetweb.cxx:166
 TCivetweb.cxx:167
 TCivetweb.cxx:168
 TCivetweb.cxx:169
 TCivetweb.cxx:170
 TCivetweb.cxx:171
 TCivetweb.cxx:172
 TCivetweb.cxx:173
 TCivetweb.cxx:174
 TCivetweb.cxx:175
 TCivetweb.cxx:176
 TCivetweb.cxx:177
 TCivetweb.cxx:178
 TCivetweb.cxx:179
 TCivetweb.cxx:180
 TCivetweb.cxx:181
 TCivetweb.cxx:182
 TCivetweb.cxx:183
 TCivetweb.cxx:184
 TCivetweb.cxx:185
 TCivetweb.cxx:186
 TCivetweb.cxx:187
 TCivetweb.cxx:188
 TCivetweb.cxx:189
 TCivetweb.cxx:190
 TCivetweb.cxx:191
 TCivetweb.cxx:192
 TCivetweb.cxx:193
 TCivetweb.cxx:194
 TCivetweb.cxx:195
 TCivetweb.cxx:196
 TCivetweb.cxx:197
 TCivetweb.cxx:198
 TCivetweb.cxx:199
 TCivetweb.cxx:200
 TCivetweb.cxx:201
 TCivetweb.cxx:202
 TCivetweb.cxx:203
 TCivetweb.cxx:204
 TCivetweb.cxx:205
 TCivetweb.cxx:206
 TCivetweb.cxx:207
 TCivetweb.cxx:208
 TCivetweb.cxx:209
 TCivetweb.cxx:210
 TCivetweb.cxx:211
 TCivetweb.cxx:212
 TCivetweb.cxx:213
 TCivetweb.cxx:214
 TCivetweb.cxx:215
 TCivetweb.cxx:216
 TCivetweb.cxx:217
 TCivetweb.cxx:218
 TCivetweb.cxx:219
 TCivetweb.cxx:220
 TCivetweb.cxx:221