LCOV - code coverage report
Current view: top level - extra/webserver/unix - SPWebUnixRoot.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 104 132 78.8 %
Date: 2024-05-12 00:16:13 Functions: 14 15 93.3 %

          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 "SPWebUnixRoot.h"
      24             : #include "SPWebUnixHost.h"
      25             : #include "SPWebUnixConnectionQueue.h"
      26             : #include "SPWebUnixRequest.h"
      27             : #include "SPWebRequest.h"
      28             : #include "SPThread.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::web {
      31             : 
      32          25 : SharedRc<UnixRoot> UnixRoot::create(Config &&cfg) {
      33          25 :         return SharedRc<UnixRoot>::create(SharedMode::Allocator, move(cfg));
      34             : }
      35             : 
      36          50 : UnixRoot::~UnixRoot() { }
      37             : 
      38          25 : UnixRoot::UnixRoot(pool_t *p) : Root(p) { }
      39             : 
      40          25 : bool UnixRoot::init(Config &&config) {
      41          50 :         return perform([&, this] {
      42          25 :                 size_t workers = std::thread::hardware_concurrency();
      43          25 :                 if (config.nworkers >= 2 && config.nworkers <= 256) {
      44          25 :                         workers = size_t(config.nworkers);
      45             :                 }
      46             : 
      47          50 :                 for (auto &it : config.hosts) {
      48          25 :                         auto p = pool::create(_rootPool);
      49          25 :                         pool::push(p);
      50             : 
      51          25 :                         auto host = new (p) UnixHostController(this, p, it);
      52             : 
      53          25 :                         _hosts.emplace(host->getHostInfo().hostname, host);
      54             : 
      55          25 :                         pool::pop();
      56             :                 }
      57             : 
      58          25 :                 initDatabases();
      59             : 
      60          25 :                 _queue = new (_rootPool) ConnectionQueue(this, _rootPool, workers, move(config));
      61             : 
      62          25 :                 std::unique_lock<std::mutex> lock(_mutex);
      63          25 :                 if (_queue->run()) {
      64          25 :                         _running = true;
      65             : 
      66          50 :                         for (auto &it : _hosts) {
      67          25 :                                 perform([&] {
      68          25 :                                         it.second->init(Host(it.second));
      69          50 :                                 }, _rootPool, config::TAG_HOST, it.second);
      70             :                         }
      71             : 
      72          50 :                         for (auto &it : _hosts) {
      73          25 :                                 perform([&] {
      74          25 :                                         Host(it.second).handleChildInit(_rootPool);
      75          50 :                                 }, _rootPool, config::TAG_HOST, it.second);
      76             :                         }
      77             : 
      78          25 :                         return true;
      79             :                 }
      80           0 :                 return false;
      81          75 :         }, _rootPool);
      82             : }
      83             : 
      84          25 : void UnixRoot::cancel() {
      85          25 :         if (!_running || !_queue) {
      86           0 :                 return;
      87             :         }
      88             : 
      89          25 :         _running = false;
      90          25 :         _queue->cancel();
      91          25 :         _queue->release();
      92          25 :         _queue = nullptr;
      93             : }
      94             : 
      95         100 : bool UnixRoot::performTask(const Host &host, AsyncTask *task, bool performFirst) {
      96         100 :         if (_queue) {
      97         100 :                 task->setHost(host);
      98         100 :                 _queue->pushTask(task);
      99         100 :                 return true;
     100             :         }
     101           0 :         return false;
     102             : }
     103             : 
     104           0 : bool UnixRoot::scheduleTask(const Host &host, AsyncTask *task, TimeInterval ival) {
     105           0 :         if (_queue) {
     106           0 :                 task->setHost(host);
     107           0 :                 _queue->pushTask(task);
     108           0 :                 return true;
     109             :         }
     110           0 :         return false;
     111             : }
     112             : 
     113          25 : void UnixRoot::foreachHost(const Callback<void(Host &)> &cb) {
     114          50 :         for (auto &it : _hosts) {
     115          25 :                 Host serv(it.second);
     116          25 :                 cb(serv);
     117             :         }
     118          25 : }
     119             : 
     120        3100 : Status UnixRoot::processRequest(RequestController *req) {
     121        3100 :         Status ret = DECLINED;
     122        3100 :         auto host = req->getInfo().url.host;
     123             : 
     124        3100 :         auto it = _hosts.find(host);
     125        3100 :         if (it != _hosts.end()) {
     126        3100 :                 req->bind(it->second);
     127             :         }
     128             : 
     129        3100 :         if (!req->init()) {
     130           0 :                 return ret;
     131             :         }
     132             : 
     133        3100 :         Request rctx(req);
     134             : 
     135        3100 :         ret = runPostReadRequest(rctx);
     136        3100 :         switch (ret) {
     137        3025 :         case OK:
     138             :                 // continue processing
     139        3025 :                 break;
     140          50 :         case DECLINED:
     141          50 :                 return runDefaultProcessing(rctx);
     142             :                 break;
     143          25 :         default:
     144          25 :                 return ret;
     145             :                 break;
     146             :         }
     147             : 
     148        3025 :         ret = runTranslateName(rctx);
     149        3025 :         switch (ret) {
     150         675 :         case OK:
     151             :                 // continue processing
     152         675 :                 break;
     153           0 :         case DECLINED:
     154           0 :                 return runDefaultProcessing(rctx);
     155             :                 break;
     156        2350 :         default:
     157        2350 :                 return ret;
     158             :                 break;
     159             :         }
     160             : 
     161         675 :         ret = runCheckAccess(rctx);
     162         675 :         switch (ret) {
     163         675 :         case OK:
     164             :                 // continue processing
     165         675 :                 break;
     166           0 :         case DECLINED:
     167           0 :                 return HTTP_FORBIDDEN;
     168             :                 break;
     169           0 :         default:
     170           0 :                 return ret;
     171             :                 break;
     172             :         }
     173             : 
     174         675 :         ret = runQuickHandler(rctx, 0);
     175         675 :         switch (ret) {
     176         675 :         case OK:
     177             :         case DECLINED:
     178             :                 // continue processing
     179         675 :                 break;
     180           0 :         default:
     181           0 :                 return ret;
     182             :                 break;
     183             :         }
     184             : 
     185         675 :         runInsertFilter(rctx);
     186             : 
     187         675 :         switch (req->getInfo().status) {
     188         675 :         case OK:
     189             :         case DECLINED:
     190             :         case SUSPENDED:
     191             :                 // continue processing
     192         675 :                 break;
     193           0 :         default:
     194           0 :                 return ret;
     195             :                 break;
     196             :         }
     197             : 
     198         675 :         ret = runHandler(rctx);
     199         675 :         switch (ret) {
     200         650 :         case OK:
     201         650 :                 if (rctx.getInputFilter()) {
     202         650 :                         return SUSPENDED;
     203             :                 }
     204           0 :                 return DONE;
     205             :                 break;
     206          25 :         case DECLINED:
     207          25 :                 if (rctx.getInputFilter()) {
     208           0 :                         return SUSPENDED;
     209             :                 } else {
     210          25 :                         return runDefaultProcessing(rctx);
     211             :                 }
     212             :                 break;
     213           0 :         default:
     214           0 :                 break;
     215             :         }
     216             : 
     217           0 :         return ret;
     218        3100 : }
     219             : 
     220          25 : bool UnixRoot::simulateWebsocket(UnixWebsocketSim *sim, StringView hostname, StringView url) {
     221          25 :         auto it = _hosts.find(hostname);
     222          25 :         if (it == _hosts.end()) {
     223           0 :                 return false;
     224             :         }
     225             : 
     226          25 :         return it->second->simulateWebsocket(sim, url);
     227             : }
     228             : 
     229          75 : Status UnixRoot::runDefaultProcessing(Request &rctx) {
     230          75 :         auto &info = rctx.getInfo();
     231          75 :         auto filename = info.filename;
     232          75 :         if (filename.empty()) {
     233          50 :                 rctx.setFilename(filepath::merge<Interface>(info.documentRoot, info.url.path), true);
     234             :         }
     235             : 
     236          75 :         if (info.filename.empty() || info.stat.isDir) {
     237          25 :                 return HTTP_NOT_FOUND;
     238             :         } else {
     239          50 :                 if (info.contentType.empty()) {
     240          25 :                         if (runTypeChecker(rctx) == DECLINED) {
     241           0 :                                 return HTTP_NOT_FOUND;
     242             :                         }
     243             :                 }
     244             : 
     245          50 :                 if (runCheckAccess(rctx) != OK) {
     246           0 :                         return HTTP_FORBIDDEN;
     247             :                 }
     248          50 :                 return DONE;
     249             :         }
     250             : }
     251             : 
     252             : }

Generated by: LCOV version 1.14