LCOV - code coverage report
Current view: top level - extra/webserver/webserver/server - SPWebRoot.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 299 540 55.4 %
Date: 2024-05-12 00:16:13 Functions: 50 77 64.9 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "SPWebRoot.h"
      24             : #include "SPWebInputFilter.h"
      25             : #include "SPWebRequest.h"
      26             : #include "SPWebRequestHandler.h"
      27             : #include "SPWebRequestController.h"
      28             : #include "SPWebWebsocketConnection.h"
      29             : #include "SPWebHostController.h"
      30             : 
      31             : #include "SPPlatformUnistd.h"
      32             : #include "SPLog.h"
      33             : #include "SPDbUser.h"
      34             : 
      35             : #if LINUX
      36             : #include <signal.h>
      37             : #endif
      38             : 
      39             : namespace STAPPLER_VERSIONIZED stappler::web {
      40             : 
      41         125 : static Root *getRootFromContext(pool_t *p, uint32_t tag, const void *ptr) {
      42         125 :         switch (tag) {
      43           0 :         case uint32_t(config::TAG_HOST): return ((HostController *)ptr)->getRoot(); break;
      44          25 :         case uint32_t(config::TAG_REQUEST): return ((RequestController *)ptr)->getHost()->getRoot(); break;
      45         100 :         case uint32_t(config::TAG_WEBSOCKET): return ((WebsocketConnection *)ptr)->getHost().getRoot(); break;
      46             :         }
      47           0 :         return nullptr;
      48             : }
      49             : 
      50         125 : Root *Root::getCurrent() {
      51         125 :         Root *ret = nullptr;
      52         125 :         pool::foreach_info(&ret, [] (void *ud, pool_t *p, uint32_t tag, const void *data) -> bool {
      53         125 :                 auto ptr = getRootFromContext(p, tag, data);
      54         125 :                 if (ptr) {
      55         125 :                         *((Root **)ud) = ptr;
      56         125 :                         return false;
      57             :                 }
      58           0 :                 return true;
      59             :         });
      60             : 
      61         125 :         return ret;
      62             : }
      63             : 
      64           0 : void Root::parseParameterList(Map<StringView, StringView> &target, StringView str) {
      65           0 :         StringView r(str);
      66           0 :         r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
      67           0 :         while (!r.empty()) {
      68           0 :                 StringView params, n, v;
      69           0 :                 if (r.is('"')) {
      70           0 :                         ++ r;
      71           0 :                         params = r.readUntil<StringView::Chars<'"'>>();
      72           0 :                         if (r.is('"')) {
      73           0 :                                 ++ r;
      74             :                         }
      75             :                 } else {
      76           0 :                         params = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
      77             :                 }
      78             : 
      79           0 :                 if (!params.empty()) {
      80           0 :                         n = params.readUntil<StringView::Chars<'='>>();
      81           0 :                         ++ params;
      82           0 :                         v = params;
      83             : 
      84           0 :                         if (!n.empty() && ! v.empty()) {
      85           0 :                                 target.emplace(n.pdup(target.get_allocator()), v.pdup(target.get_allocator()));
      86             :                         }
      87             :                 }
      88             : 
      89           0 :                 r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
      90             :         }
      91           0 : }
      92             : 
      93         249 : void Root::setErrorNotification(pool_t *p, Function<void(Value &&)> errorCb, Function<void(Value &&)> debugCb) {
      94         249 :         perform([&] {
      95         249 :                 ErrorNotificator *err = nullptr;
      96         249 :                 pool::userdata_get((void **)&err, ErrorNotificatorKey, p);
      97         249 :                 if (err) {
      98           0 :                         err->error = move(errorCb);
      99           0 :                         err->debug = move(debugCb);
     100             :                 } else {
     101         249 :                         err = new (p) ErrorNotificator;
     102         249 :                         err->error = move(errorCb);
     103         249 :                         err->debug = move(debugCb);
     104         249 :                         pool::userdata_set(err, ErrorNotificatorKey, nullptr, p);
     105             :                 }
     106         249 :         }, p);
     107         249 : }
     108             : 
     109          50 : void Root::dumpCurrentState(StringView filepath) {
     110          50 :         String tmpPath;
     111          50 :         if (filepath.empty()) {
     112          50 :                 if (auto host = Host::getCurrent()) {
     113          50 :                         auto &hostInfo = host.getHostInfo();
     114          50 :                         auto root = hostInfo.documentRoot;
     115          50 :                         tmpPath = toString(root, "/.reports/crash.", Time::now().toMicros(), ".txt");
     116          50 :                         filepath = tmpPath;
     117             :                 }
     118             :         }
     119             : 
     120          50 :         if (filepath.empty()) {
     121           0 :                 return;
     122             :         }
     123             : 
     124          50 :         if (auto f = ::fopen(filepath.data(), "w+")) {
     125          50 :                 if (auto host = Host::getCurrent()) {
     126          50 :                         auto &hostInfo = host.getHostInfo();
     127          50 :                         auto root = hostInfo.documentRoot;
     128          50 :                         ::fputs("Server:\n\tDocumentRoot: ", f);
     129          50 :                         ::fputs(root.data(), f);
     130          50 :                         ::fputs("\n\tName: ", f);
     131          50 :                         ::fputs(hostInfo.hostname.data(), f);
     132          50 :                         ::fputs("\n\tDate: ", f);
     133          50 :                         ::fputs(Time::now().toHttp<Interface>().data(), f);
     134             : 
     135          50 :                         if (auto req = Request::getCurrent()) {
     136          50 :                                 auto &reqInfo = req.getInfo();
     137          50 :                                 ::fputs("\nRequest:\n", f);
     138          50 :                                 ::fprintf(f, "\tUrl: %s%s\n", reqInfo.url.host.data(), reqInfo.unparserUri.data());
     139          50 :                                 ::fprintf(f, "\tRequest: %s\n", reqInfo.requestLine.data());
     140          50 :                                 ::fprintf(f, "\tIp: %s\n", reqInfo.useragentIp.data());
     141             : 
     142          50 :                                 ::fputs("\tHeaders:\n", f);
     143          50 :                                 req.foreachRequestHeaders([&] (StringView key, StringView value) {
     144         300 :                                         ::fprintf(f, "\t\t%s: %s\n", key.data(), value.data());
     145         300 :                                 });
     146          50 :                         }
     147             : 
     148          50 :                         ::fputs("\nBacktrace:\n", f);
     149             : 
     150          50 :                         getBacktrace(2, [&] (StringView str) {
     151        1400 :                                 ::fprintf(f, "\t%s\n", str.data());
     152        1400 :                         });
     153             : 
     154          50 :                         ::fclose(f);
     155             :                 }
     156             :         }
     157          50 : }
     158             : 
     159          25 : Root::~Root() {
     160          25 :         pool::destroy(_workerPool);
     161          25 : }
     162             : 
     163          25 : Root::Root(pool_t *p) : _rootPool(p) {
     164          25 :         _workerPool = pool::create(p);
     165             : 
     166          25 :         _serverNameLine = StringView(
     167          50 :                         toString("Stappler/", getStapplerVersionString(), " ", "Webserver/", config::getWebserverVersionString())).pdup(_rootPool);
     168          25 : }
     169             : 
     170          25 : Root::Stat Root::getStat() const {
     171             :         return Stat{
     172          25 :                 _requestsReceived.load(),
     173          50 :                 _heartbeatCounter.load(),
     174          50 :                 _dbQueriesReleased.load(),
     175          50 :                 _dbQueriesPerformed.load()
     176         100 :         };
     177             : }
     178             : 
     179          50 : void Root::setDebugEnabled(bool val) {
     180          50 :         _debug = val;
     181          50 : }
     182             : 
     183           0 : bool Root::isSecureConnection(const Request &) const {
     184           0 :         return false;
     185             : }
     186             : 
     187          25 : db::sql::Driver * Root::getDbDriver(StringView driver) {
     188          25 :         auto it = _dbDrivers.find(driver);
     189          25 :         if (it != _dbDrivers.end()) {
     190          25 :                 return it->second;
     191             :         } else {
     192           0 :                 auto d = createDbDriver(driver);
     193           0 :                 _dbDrivers.emplace(driver, d);
     194           0 :                 return d;
     195             :         }
     196             : }
     197             : 
     198           0 : db::sql::Driver::Handle Root::dbdOpen(pool_t *, const Host &serv) {
     199           0 :         log::error("web::Root", "Root::dbdOpen is not implemented");
     200           0 :         return db::sql::Driver::Handle(nullptr);
     201             : }
     202             : 
     203           0 : void Root::dbdClose(const Host &serv, db::sql::Driver::Handle) {
     204           0 :         log::error("web::Root", "Root::dbdClose is not implemented");
     205           0 : }
     206             : 
     207           0 : db::sql::Driver::Handle Root::dbdAcquire(const Request &req) {
     208           0 :         log::error("web::Root", "Root::dbdAcquire is not implemented");
     209           0 :         return db::sql::Driver::Handle(nullptr);
     210             : }
     211             : 
     212        3100 : Status Root::runPostReadRequest(Request &r) {
     213        6200 :         return perform([&, this] {
     214        3100 :                 _requestsReceived += 1;
     215             :                 //OutputFilter::insert(r);
     216             : 
     217        3100 :                 Request request(r);
     218        3100 :                 Host host = request.host();
     219             : 
     220        3100 :                 auto ret = host.handleRequest(request);
     221        3100 :                 if (ret > 0 || ret == DONE) {
     222           0 :                         return ret;
     223             :                 }
     224             : 
     225        3100 :                 RequestHandler *rhdl = request.getRequestHandler();
     226        3100 :                 if (rhdl) {
     227        3050 :                         return rhdl->onPostReadRequest(request);
     228             :                 }
     229             : 
     230          50 :                 return DECLINED;
     231       12400 :         }, r.pool(), config::TAG_REQUEST, r.config());
     232             : }
     233             : 
     234        3025 : Status Root::runTranslateName(Request &r) {
     235        6050 :         return perform([&] () {
     236        3025 :                 Request request(r);
     237             : 
     238        3025 :                 RequestHandler *rhdl = request.getRequestHandler();
     239        3025 :                 if (rhdl) {
     240        3025 :                         if (!rhdl->isRequestPermitted(request)) {
     241          25 :                                 auto status = request.getInfo().status;
     242          25 :                                 if (status == 0 || status == 200) {
     243           0 :                                         return HTTP_FORBIDDEN;
     244             :                                 }
     245          25 :                                 return status;
     246             :                         }
     247        3000 :                         auto res = rhdl->onTranslateName(request);
     248        3000 :                         if (res == DECLINED
     249         525 :                                         && request.getInfo().method != RequestMethod::Post
     250         150 :                                         && request.getInfo().method != RequestMethod::Put
     251           0 :                                         && request.getInfo().method != RequestMethod::Patch
     252        3525 :                                         && request.getInfo().method != RequestMethod::Options) {
     253           0 :                                 request.setRequestHandler(nullptr);
     254        3000 :                         } else if (res == DECLINED) {
     255         525 :                                 res = OK;
     256             :                         }
     257        3000 :                         return res;
     258             :                 }
     259             : 
     260           0 :                 return DECLINED;
     261       12100 :         }, r.pool(), config::TAG_REQUEST, r.config());
     262             : }
     263             : 
     264         725 : Status Root::runCheckAccess(Request &r) {
     265        1450 :         return perform([&] {
     266         725 :                 Request request(r);
     267         725 :                 RequestHandler *rhdl = request.getRequestHandler();
     268         725 :                 if (rhdl) {
     269         700 :                         return OK; // already checked by serenity
     270             :                 }
     271          25 :                 if (!request.getInfo().filename.empty()) {
     272          25 :                         if (StringView(request.getInfo().filename).starts_with(StringView(request.getInfo().documentRoot))) {
     273          25 :                                 return OK;
     274             :                         }
     275             :                 }
     276           0 :                 return DECLINED;
     277        2900 :         }, r.pool(), config::TAG_REQUEST, r.config());
     278             : }
     279             : 
     280         675 : Status Root::runQuickHandler(Request &r, int v) {
     281        1350 :         return perform([&] () -> Status {
     282         675 :                 Request request(r);
     283         675 :                 RequestHandler *rhdl = request.getRequestHandler();
     284         675 :                 if (rhdl) {
     285         675 :                         return rhdl->onQuickHandler(request, v);
     286             :                 }
     287           0 :                 return DECLINED;
     288        2700 :         }, r.pool(), config::TAG_REQUEST, r.config());
     289             : }
     290             : 
     291         675 : void Root::runInsertFilter(Request &r) {
     292         675 :         perform([&] {
     293         675 :                 Request request(r);
     294             : 
     295         675 :                 RequestHandler *rhdl = request.getRequestHandler();
     296         675 :                 if (rhdl) {
     297         675 :                         rhdl->onInsertFilter(request);
     298             :                 }
     299        1350 :         }, r.pool(), config::TAG_REQUEST, r.config());
     300         675 : }
     301             : 
     302         675 : Status Root::runHandler(Request &r) {
     303        1350 :         return perform([&] () -> Status {
     304         675 :                 Request request(r);
     305             : 
     306         675 :                 RequestHandler *rhdl = request.getRequestHandler();
     307         675 :                 if (rhdl) {
     308         675 :                         return rhdl->onHandler(request);
     309             :                 }
     310             : 
     311           0 :                 return DECLINED;
     312        2700 :         }, r.pool(), config::TAG_REQUEST, r.config());
     313             : }
     314             : 
     315         650 : void Root::handleFilterInit(InputFilter *f) {
     316         650 :         RequestHandler *rhdl = f->getRequest().getRequestHandler();
     317         650 :         if (rhdl) {
     318         650 :                 rhdl->onFilterInit(f);
     319             :         }
     320         650 : }
     321         825 : void Root::handleFilterUpdate(InputFilter *f) {
     322         825 :         RequestHandler *rhdl = f->getRequest().getRequestHandler();
     323         825 :         if (rhdl) {
     324         825 :                 rhdl->onFilterUpdate(f);
     325             :         }
     326         825 : }
     327         650 : void Root::handleFilterComplete(InputFilter *f) {
     328         650 :         RequestHandler *rhdl = f->getRequest().getRequestHandler();
     329         650 :         if (rhdl) {
     330         650 :                 rhdl->onFilterComplete(f);
     331             :         }
     332         650 : }
     333             : 
     334           0 : void Root::addDb(StringView str) {
     335           0 :         perform([&, this] {
     336           0 :                 emplace_ordered(_dbs, str.pdup(_rootPool));
     337           0 :         }, _rootPool);
     338           0 : }
     339             : 
     340           0 : void Root::setDbParams(StringView str) {
     341           0 :         perform([&, this] {
     342           0 :                 parseParameterList(_dbParams, str);
     343           0 :         }, _rootPool);
     344           0 : }
     345             : 
     346           0 : void Root::setThreadsCount(StringView init, StringView max) {
     347           0 :         _initThreads = std::max(size_t(init.readInteger(10).get(1)), size_t(1));
     348           0 :         _maxThreads = std::max(size_t(max.readInteger(10).get(1)), _initThreads);
     349           0 : }
     350             : 
     351           0 : void Root::handleHeartbeat(pool_t *pool) {
     352           0 :         foreachHost([&] (Host &serv) {
     353           0 :                 perform([&] {
     354           0 :                         serv.handleHeartBeat(pool);
     355           0 :                 }, pool, config::TAG_HOST, serv.getController());
     356           0 :         });
     357           0 : }
     358             : 
     359           0 : void Root::handleBroadcast(const Value &res) {
     360           0 :         if (res.getBool("system")) {
     361           0 :                 auto &option = res.getString("option");
     362           0 :                 if (!option.empty()) {
     363           0 :                         if (option == "debug") {
     364           0 :                                 _debug = res.getBool("debug");
     365             :                         }
     366             :                 }
     367           0 :                 return;
     368           0 :         } else if (res.getBool("local")) {
     369           0 :                 foreachHost([&] (Host &serv) {
     370           0 :                         perform([&] {
     371           0 :                                 serv.handleBroadcast(res);
     372           0 :                         }, serv.getThreadPool(), config::TAG_HOST, serv.getController());
     373           0 :                 });
     374             :         }
     375             : }
     376             : 
     377           0 : void Root::handleChildInit(pool_t *p) {
     378           0 :         perform([&, this] {
     379           0 :                 initDatabases();
     380             : 
     381           0 :                 initSignals();
     382             : 
     383           0 :                 _pending = new Vector<PendingTask>();
     384             : 
     385           0 :                 foreachHost([&, this] (Host &host) {
     386           0 :                         host.handleChildInit(_configPool);
     387           0 :                 });
     388             : 
     389             :                 // start threads only after all initialization is done
     390           0 :                 initThreads();
     391           0 :         }, p);
     392           0 : }
     393             : 
     394          25 : Status Root::runTypeChecker(Request &r) {
     395          25 :         auto &info = r.getInfo();
     396          25 :         if (info.stat.isDir) {
     397           0 :                 r.setContentType(config::DIR_MIME_TYPE);
     398           0 :                 return OK;
     399             :         }
     400             : 
     401          25 :         if (info.filename.empty()) {
     402           0 :                 return DECLINED;
     403             :         }
     404             : 
     405          25 :         StringView contentType;
     406          25 :         StringView charset;
     407          25 :         Vector<StringView> contentEncoding;
     408             : 
     409          75 :         auto onTypeCheckerExtension = [&, this] (StringView fileName, StringView ext) {
     410          25 :                 auto ct = filesystem::detectMimeType(fileName);
     411          25 :                 if (!ct.empty()) {
     412          25 :                         contentType = ct;
     413             :                 } else {
     414           0 :                         ct = findTypeCheckerContentType(r,  ext);
     415           0 :                         if (!ct.empty()) {
     416           0 :                                 contentType = ct;
     417             :                         }
     418             :                 }
     419             : 
     420          25 :                 auto cs = findTypeCheckerCharset(r, ext);
     421          25 :                 if (!cs.empty()) {
     422           0 :                         charset = cs;
     423             :                 }
     424             : 
     425          25 :                 auto ce = findTypeCheckerContentEncoding(r, ext);
     426          25 :                 if (!ce.empty()) {
     427           0 :                         contentEncoding.emplace_back(ce);
     428             :                 }
     429          25 :         };
     430             : 
     431          25 :         StringView fileName = filepath::lastComponent(info.filename);
     432          25 :         fileName.skipChars<StringView::Chars<'.'>>();
     433             : 
     434          25 :         auto tmp = fileName;
     435          25 :         tmp.skipUntil<StringView::Chars<'.'>>();
     436          25 :         if (tmp.size() < 2 || !tmp.is('.') ) {
     437           0 :                 return DECLINED;
     438             :         }
     439             : 
     440          50 :         while (!tmp.empty()) {
     441          25 :                 if (tmp.is('.')) {
     442          25 :                         tmp.skipChars<StringView::Chars<'.'>>();
     443          25 :                         auto ext = tmp.readUntil<StringView::Chars<'.'>>();
     444          25 :                         if (!ext.empty()) {
     445          25 :                                 auto tmpStr = ext.str<Interface>();
     446          25 :                                 string::apply_tolower_c(tmpStr);
     447          25 :                                 onTypeCheckerExtension(fileName, tmpStr);
     448          25 :                         }
     449             :                 } else {
     450           0 :                         tmp.skipUntil<StringView::Chars<'.'>>();
     451             :                 }
     452             :         }
     453             : 
     454          25 :         if (!contentEncoding.empty()) {
     455           0 :             if (info.contentEncoding.empty() && contentEncoding.size() == 1) {
     456           0 :                 r.setContentEncoding(contentEncoding.front());
     457             :             } else {
     458           0 :                         StringStream stream;
     459             : 
     460           0 :                         bool start = true;
     461           0 :                         if (!info.contentEncoding.empty()) {
     462           0 :                                 stream << info.contentEncoding;
     463           0 :                                 start = false;
     464             :                         }
     465             : 
     466           0 :                         for (auto &it : contentEncoding) {
     467           0 :                                 if (start) {
     468           0 :                                         start = false;
     469             :                                 } else {
     470           0 :                                         stream << ", ";
     471             :                                 }
     472           0 :                                 stream << it;
     473             :                         }
     474             : 
     475           0 :                         r.setContentEncoding(stream.weak());
     476           0 :             }
     477             :         }
     478             : 
     479          25 :     if (!contentType.empty()) {
     480          25 :         auto v = extractCharset(contentType);
     481          25 :                 if (!charset.empty()) {
     482           0 :                         if (v.empty()) {
     483           0 :                                 StringStream stream;
     484           0 :                                 stream << contentType << "; charset=" << charset;
     485           0 :                                 r.setContentType(stream.weak());
     486           0 :                         } else {
     487           0 :                                 StringView start = StringView(contentType, v.data() - contentType.data());
     488           0 :                                 StringView end = StringView(v.data() + v.size(), contentType.size() - (v.data() - contentType.data() + v.size()));
     489             : 
     490           0 :                                 StringStream stream;
     491           0 :                                 stream << start << charset << end;
     492           0 :                                 r.setContentType(stream.weak());
     493           0 :                         }
     494             :                 } else {
     495          25 :                         r.setContentType(contentType);
     496             :                 }
     497             :     }
     498             : 
     499          25 :     if (info.contentType.empty()) {
     500           0 :         return DECLINED;
     501             :     }
     502             : 
     503          25 :     return OK;
     504          25 : }
     505             : 
     506           0 : StringView Root::findTypeCheckerContentType(Request &r, StringView ext) const {
     507           0 :         return StringView();
     508             : }
     509             : 
     510          25 : StringView Root::findTypeCheckerCharset(Request &r, StringView ext) const {
     511          25 :         return StringView();
     512             : }
     513             : 
     514           0 : StringView Root::findTypeCheckerContentLanguage(Request &r, StringView ext) const {
     515           0 :         return StringView();
     516             : }
     517             : 
     518          25 : StringView Root::findTypeCheckerContentEncoding(Request &r, StringView ext) const {
     519          25 :         return StringView();
     520             : }
     521             : 
     522          25 : void Root::initDatabases() {
     523          25 :         perform([&, this] {
     524          25 :                 Map<db::sql::Driver *, Vector<StringView>> databases;
     525             : 
     526          25 :                 if (!_dbParams.empty()) {
     527           0 :                         StringView driver;
     528           0 :                         StringView dbname;
     529             : 
     530           0 :                         for (auto &it : _dbParams) {
     531           0 :                                 if (it.first == "driver") {
     532           0 :                                         driver = it.second;
     533           0 :                                 } else if (it.first == "dbname") {
     534           0 :                                         dbname = it.second;
     535             :                                 }
     536             :                         }
     537             : 
     538           0 :                         if (driver.empty()) {
     539           0 :                                 driver = StringView("pgsql");
     540             :                         }
     541             : 
     542           0 :                         if (auto d = createDbDriver(driver)) {
     543           0 :                                 _dbDrivers.emplace(driver, d);
     544           0 :                                 auto dit = databases.emplace(d, Vector<StringView>()).first;
     545           0 :                                 if (!dbname.empty()) {
     546           0 :                                         emplace_ordered(dit->second, dbname);
     547             :                                 }
     548           0 :                                 if (!_dbs.empty()) {
     549           0 :                                         for (auto &it : _dbs) {
     550           0 :                                                 emplace_ordered(dit->second, it);
     551             :                                         }
     552             :                                 }
     553           0 :                                 _primaryDriver = d;
     554             :                         }
     555             :                 }
     556             : 
     557          25 :                 foreachHost([&, this] (Host &host) {
     558          25 :                         auto config = host.getController();
     559          25 :                         if (!config->getDbParams().empty()) {
     560          25 :                                 StringView driver;
     561          25 :                                 StringView dbname;
     562         175 :                                 for (auto &it : config->getDbParams()) {
     563         150 :                                         if (it.first == "driver") {
     564          25 :                                                 driver = it.second;
     565         125 :                                         } else if (it.first == "dbname") {
     566          25 :                                                 dbname = it.second;
     567             :                                         }
     568             :                                 }
     569             : 
     570          25 :                                 if (!driver.empty()) {
     571          25 :                                         auto iit = _dbDrivers.find(driver);
     572          25 :                                         if (iit == _dbDrivers.end()) {
     573          25 :                                                 if (auto d = createDbDriver(driver)) {
     574          25 :                                                         iit = _dbDrivers.emplace(driver, d).first;
     575             :                                                 }
     576             :                                         }
     577             : 
     578          25 :                                         if (!dbname.empty()) {
     579          25 :                                                 auto dit = databases.find(iit->second);
     580          25 :                                                 if (dit != databases.end()) {
     581           0 :                                                         emplace_ordered(dit->second, dbname);
     582             :                                                 }
     583             :                                         }
     584             :                                 }
     585             :                         }
     586          25 :                 });
     587             : 
     588          25 :                 if (_primaryDriver && !_dbParams.empty()) {
     589           0 :                         bool init = false;
     590           0 :                         auto dIt = databases.find(_primaryDriver);
     591           0 :                         if (dIt != databases.end()) {
     592           0 :                                 if (!dIt->second.empty()) {
     593           0 :                                         auto handle = _primaryDriver->connect(_dbParams);
     594           0 :                                         if (handle.get()) {
     595           0 :                                                 _primaryDriver->init(handle, dIt->second);
     596           0 :                                                 _primaryDriver->finish(handle);
     597           0 :                                                 init = true;
     598             :                                         }
     599             :                                 }
     600             :                         }
     601           0 :                         if (!init) {
     602           0 :                                 auto handle = _primaryDriver->connect(_dbParams);
     603           0 :                                 if (handle.get()) {
     604           0 :                                         _primaryDriver->init(handle, Vector<StringView>());
     605           0 :                                         _primaryDriver->finish(handle);
     606           0 :                                         init = true;
     607             :                                 }
     608             :                         }
     609             :                 }
     610          25 :         }, _workerPool);
     611          25 :         pool::clear(_workerPool);
     612          25 : }
     613             : 
     614             : #if LINUX
     615             : static struct sigaction s_sharedSigAction;
     616             : static struct sigaction s_sharedSigOldAction;
     617             : 
     618           0 : static void s_sigAction(int sig, siginfo_t *info, void *ucontext) {
     619           0 :         if (auto host = Host::getCurrent()) {
     620           0 :                 auto &hostInfo = host.getHostInfo();
     621           0 :                 auto root = hostInfo.documentRoot;
     622           0 :                 Root::dumpCurrentState(toString(root, "/.reports/crash.", Time::now().toMicros(), ".txt"));
     623             :         }
     624             : 
     625           0 :         if ((s_sharedSigOldAction.sa_flags & SA_SIGINFO) != 0) {
     626           0 :                 if (s_sharedSigOldAction.sa_sigaction) {
     627           0 :                         s_sharedSigOldAction.sa_sigaction(sig, info, ucontext);
     628             :                 }
     629             :         } else {
     630           0 :                 if (s_sharedSigOldAction.sa_handler == SIG_DFL) {
     631           0 :                         if (SIGURG == sig || SIGWINCH == sig || SIGCONT == sig) return;
     632             : 
     633             :                         static struct sigaction tmpSig;
     634           0 :                         tmpSig.sa_handler = SIG_DFL;
     635           0 :                         ::sigemptyset(&tmpSig.sa_mask);
     636           0 :                     ::sigaction(sig, &tmpSig, nullptr);
     637           0 :                     ::kill(getpid(), sig);
     638           0 :                         ::sigaction(sig, &s_sharedSigAction, nullptr);
     639           0 :                 } else if (s_sharedSigOldAction.sa_handler == SIG_IGN) {
     640           0 :                         return;
     641           0 :                 } else if (s_sharedSigOldAction.sa_handler) {
     642           0 :                         s_sharedSigOldAction.sa_handler(sig);
     643             :                 }
     644             :         }
     645             : }
     646             : #endif
     647             : 
     648           0 : void Root::initSignals() {
     649             : #if LINUX
     650           0 :         ::setenv("GNUTLS_NO_IMPLICIT_INIT", "1", 0);
     651             : 
     652           0 :         memset(&s_sharedSigAction, 0, sizeof(s_sharedSigAction));
     653           0 :         s_sharedSigAction.sa_sigaction = &s_sigAction;
     654           0 :         s_sharedSigAction.sa_flags = SA_SIGINFO;
     655           0 :         sigemptyset(&s_sharedSigAction.sa_mask);
     656             :         //sigaddset(&s_sharedSigAction.sa_mask, SIGSEGV);
     657             : 
     658           0 :     ::sigaction(SIGSEGV, &s_sharedSigAction, &s_sharedSigOldAction);
     659             : #endif
     660           0 : }
     661             : 
     662           0 : void Root::initThreads() {
     663             : 
     664           0 : }
     665             : 
     666          25 : db::sql::Driver *Root::createDbDriver(StringView driverName) {
     667          25 :         if (auto d = db::sql::Driver::open(_rootPool, this, driverName)) {
     668          25 :                 d->setDbCtrl([this] (bool complete) {
     669           0 :                         if (complete) {
     670           0 :                                 _dbQueriesReleased += 1;
     671             :                         } else {
     672           0 :                                 _dbQueriesPerformed += 1;
     673             :                         }
     674           0 :                 });
     675          25 :                 return d;
     676             :         }
     677             : 
     678           0 :         log::error("web::Root", "Fail to initialize driver: ", driverName);
     679           0 :         return nullptr;
     680             : }
     681             : 
     682          50 : void Root::pushErrorMessage(Value &&val) const {
     683          50 :         if (auto serv = Host::getCurrent()) {
     684          50 :                 serv.reportError(val);
     685             :         }
     686             : 
     687          50 :         if (isDebugEnabled()) {
     688             :                 Value bcast{
     689           0 :                         std::make_pair("message", Value(true)),
     690           0 :                         std::make_pair("level", Value("error")),
     691           0 :                         std::make_pair("data", Value(val)),
     692           0 :                 };
     693           0 :                 if (auto a = db::Adapter::FromContext(this)) {
     694           0 :                         a.broadcast(bcast);
     695             :                 }
     696           0 :         }
     697             : 
     698             : #if DEBUG
     699          50 :         log::error("web::Root", data::EncodeFormat::Pretty, val);
     700             : #endif
     701             : 
     702          50 :         if (auto req = Request::getCurrent()) {
     703          50 :                 req.getController()->pushErrorMessage(move(val));
     704          50 :                 return;
     705          50 :         }
     706             : 
     707           0 :         auto pool = pool::acquire();
     708           0 :         ErrorNotificator *err = nullptr;
     709           0 :         pool::userdata_get((void **)&err, ErrorNotificatorKey, pool);
     710           0 :         if (err && err->error) {
     711           0 :                 err->error(std::move(val));
     712             :         }
     713             : 
     714           0 :         log::error("web::Root", "Unhandled error: ", data::EncodeFormat::Pretty, val);
     715             : }
     716             : 
     717          25 : void Root::pushDebugMessage(Value &&val) const {
     718          25 :         if (auto serv = Host::getCurrent()) {
     719          25 :                 serv.reportError(val);
     720             :         }
     721             : 
     722          25 :         if (isDebugEnabled()) {
     723             :                 Value bcast{
     724           0 :                         std::make_pair("message", Value(true)),
     725           0 :                         std::make_pair("level", Value("debug")),
     726           0 :                         std::make_pair("data", Value(val)),
     727           0 :                 };
     728           0 :                 if (auto a = db::Adapter::FromContext(this)) {
     729           0 :                         a.broadcast(bcast);
     730             :                 }
     731           0 :         }
     732             : 
     733             : #if DEBUG
     734          25 :         log::error("web::Root", data::EncodeFormat::Pretty, val);
     735             : #endif
     736             : 
     737          25 :         if (auto req = Request::getCurrent()) {
     738          25 :                 req.getController()->pushDebugMessage(move(val));
     739          25 :                 return;
     740          25 :         }
     741             : 
     742           0 :         auto pool = pool::acquire();
     743           0 :         ErrorNotificator *err = nullptr;
     744           0 :         pool::userdata_get((void **)&err, ErrorNotificatorKey, pool);
     745           0 :         if (err && err->debug) {
     746           0 :                 err->debug(std::move(val));
     747           0 :                 return;
     748             :         }
     749             : 
     750           0 :         log::debug("web::Root", "Unhandled debug message: ", data::EncodeFormat::Pretty, val);
     751             : }
     752             : 
     753           0 : db::Adapter Root::getAdapterFromContext() const {
     754           0 :         if (auto p = pool::acquire()) {
     755           0 :                 db::BackendInterface *h = nullptr;
     756           0 :                 stappler::memory::pool::userdata_get((void **)&h, db::config::STORAGE_INTERFACE_KEY.data(), p);
     757           0 :                 if (h) {
     758           0 :                         return db::Adapter(h, this);
     759             :                 }
     760             :         }
     761             : 
     762           0 :         if (auto req = Request::getCurrent()) {
     763           0 :                 return req.getController()->acquireDatabase();
     764           0 :         }
     765           0 :         return db::Adapter(nullptr, nullptr);
     766             : }
     767             : 
     768          25 : void Root::scheduleAyncDbTask(const Callback<Function<void(const db::Transaction &)>(pool_t *)> &setupCb) const {
     769          25 :         if (auto serv = Host::getCurrent()) {
     770          25 :                 AsyncTask::perform(serv, [&] (AsyncTask &task) {
     771          25 :                         auto cb = setupCb(task.pool());
     772          25 :                         task.addExecuteFn([cb = std::move(cb)] (const AsyncTask &task) -> bool {
     773          25 :                                 task.performWithStorage([&] (const db::Transaction &t) {
     774          25 :                                         t.performAsSystem([&] () -> bool {
     775          50 :                                                 cb(t);
     776          25 :                                                 return true;
     777             :                                         });
     778          25 :                                 });
     779          25 :                                 return true;
     780             :                         });
     781          25 :                 });
     782             :         }
     783          25 : }
     784             : 
     785         300 : StringView Root::getDocumentRoot() const {
     786         300 :         if (auto req = Request::getCurrent()) {
     787         275 :                 return req.getInfo().documentRoot;
     788         300 :         }
     789             : 
     790          25 :         if (auto serv = Host::getCurrent()) {
     791          25 :                 return serv.getHostInfo().documentRoot;
     792             :         }
     793             : 
     794           0 :         return StringView();
     795             : }
     796             : 
     797         775 : const db::Scheme *Root::getFileScheme() const {
     798         775 :         if (auto serv = Host::getCurrent()) {
     799         775 :                 return serv.getFileScheme();
     800             :         }
     801           0 :         return nullptr;
     802             : }
     803             : 
     804        1000 : const db::Scheme *Root::getUserScheme() const {
     805        1000 :         if (auto serv = Host::getCurrent()) {
     806        1000 :                 return serv.getUserScheme();
     807             :         }
     808           0 :         return nullptr;
     809             : }
     810             : 
     811         550 : db::RequestData Root::getRequestData() const {
     812         550 :         db::RequestData ret;
     813             : 
     814         550 :         if (auto req = Request::getCurrent()) {
     815         550 :                 ret.exists = true;
     816         550 :                 ret.address = req.getInfo().useragentIp;
     817         550 :                 ret.hostname = req.getInfo().url.host;
     818         550 :                 ret.uri = req.getInfo().unparserUri;
     819         550 :         }
     820             : 
     821         550 :         return ret;
     822             : }
     823             : 
     824        3425 : void Root::initTransaction(db::Transaction &t) const {
     825        3425 :         if (auto req = Request::getCurrent()) {
     826        2850 :                 t.setRole(req.getAccessRole());
     827             :         } else {
     828         575 :                 t.setRole(db::AccessRoleId::Nobody);
     829        3425 :         }
     830             : 
     831        3425 :         if (auto serv = Host::getCurrent()) {
     832        3425 :                 serv.initTransaction(t);
     833             :         }
     834        3425 : }
     835             : 
     836         100 : db::InputFile *Root::getFileFromContext(int64_t id) const {
     837         100 :         return InputFilter::getFileFromContext(id);
     838             : }
     839             : 
     840        3200 : int64_t Root::getUserIdFromContext() const {
     841        3200 :         if (auto req = Request::getCurrent()) {
     842        2100 :                 if (auto user = req.getAuthorizedUser()) {
     843         450 :                         return user->getObjectId();
     844             :                 } else {
     845        1650 :                         return req.getUserId();
     846             :                 }
     847        3200 :         }
     848        1100 :         return 0;
     849             : }
     850             : 
     851             : }

Generated by: LCOV version 1.14