index_mon_page.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include "index_mon_page.h"
  2. #include <util/generic/cast.h>
  3. #include <util/string/ascii.h>
  4. using namespace NMonitoring;
  5. void TIndexMonPage::OutputIndexPage(IMonHttpRequest& request) {
  6. request.Output() << HTTPOKHTML;
  7. request.Output() << "<html>\n";
  8. OutputHead(request.Output());
  9. OutputBody(request);
  10. request.Output() << "</html>\n";
  11. }
  12. void TIndexMonPage::Output(IMonHttpRequest& request) {
  13. TStringBuf pathInfo = request.GetPathInfo();
  14. if (pathInfo.empty() || pathInfo == TStringBuf("/")) {
  15. OutputIndexPage(request);
  16. return;
  17. }
  18. Y_VERIFY(pathInfo.StartsWith('/'));
  19. TMonPagePtr found;
  20. // analogous to CGI PATH_INFO
  21. {
  22. TGuard<TMutex> g(Mtx);
  23. TStringBuf pathTmp = request.GetPathInfo();
  24. for (;;) {
  25. TPagesByPath::iterator i = PagesByPath.find(pathTmp);
  26. if (i != PagesByPath.end()) {
  27. found = i->second;
  28. pathInfo = request.GetPathInfo().substr(pathTmp.size());
  29. Y_VERIFY(pathInfo.empty() || pathInfo.StartsWith('/'));
  30. break;
  31. }
  32. size_t slash = pathTmp.find_last_of('/');
  33. Y_VERIFY(slash != TString::npos);
  34. pathTmp = pathTmp.substr(0, slash);
  35. if (!pathTmp) {
  36. break;
  37. }
  38. }
  39. }
  40. if (found) {
  41. THolder<IMonHttpRequest> child(request.MakeChild(found.Get(), TString{pathInfo}));
  42. found->Output(*child);
  43. } else {
  44. request.Output() << HTTPNOTFOUND;
  45. }
  46. }
  47. void TIndexMonPage::OutputIndex(IOutputStream& out, bool pathEndsWithSlash) {
  48. TGuard<TMutex> g(Mtx);
  49. for (auto& Page : Pages) {
  50. IMonPage* page = Page.Get();
  51. if (page->IsInIndex()) {
  52. TString pathToDir = "";
  53. if (!pathEndsWithSlash) {
  54. pathToDir = this->GetPath() + "/";
  55. }
  56. out << "<a href='" << pathToDir << page->GetPath() << "'>" << page->GetTitle() << "</a><br/>\n";
  57. }
  58. }
  59. }
  60. void TIndexMonPage::Register(TMonPagePtr page) {
  61. TGuard<TMutex> g(Mtx);
  62. auto insres = PagesByPath.insert(std::make_pair("/" + page->GetPath(), page));
  63. if (insres.second) {
  64. // new unique page just inserted, update Pages
  65. Pages.push_back(page);
  66. } else {
  67. // a page with the given path is already present, replace it with the new page
  68. // find old page, sorry for O(n)
  69. auto it = std::find(Pages.begin(), Pages.end(), insres.first->second);
  70. *it = page;
  71. // this already present, replace it
  72. insres.first->second = page;
  73. }
  74. page->Parent = this;
  75. }
  76. TIndexMonPage* TIndexMonPage::RegisterIndexPage(const TString& path, const TString& title) {
  77. TGuard<TMutex> g(Mtx);
  78. TIndexMonPage* page = VerifyDynamicCast<TIndexMonPage*>(FindPage(path));
  79. if (page) {
  80. return page;
  81. }
  82. page = new TIndexMonPage(path, title);
  83. Register(page);
  84. return VerifyDynamicCast<TIndexMonPage*>(page);
  85. }
  86. IMonPage* TIndexMonPage::FindPage(const TString& relativePath) {
  87. TGuard<TMutex> g(Mtx);
  88. Y_VERIFY(!relativePath.StartsWith('/'));
  89. TPagesByPath::iterator i = PagesByPath.find("/" + relativePath);
  90. if (i == PagesByPath.end()) {
  91. return nullptr;
  92. } else {
  93. return i->second.Get();
  94. }
  95. }
  96. TIndexMonPage* TIndexMonPage::FindIndexPage(const TString& relativePath) {
  97. return VerifyDynamicCast<TIndexMonPage*>(FindPage(relativePath));
  98. }
  99. void TIndexMonPage::OutputCommonJsCss(IOutputStream& out) {
  100. out << "<link rel='stylesheet' href='https://yastatic.net/bootstrap/3.3.1/css/bootstrap.min.css'>\n";
  101. out << "<script language='javascript' type='text/javascript' src='https://yastatic.net/jquery/2.1.3/jquery.min.js'></script>\n";
  102. out << "<script language='javascript' type='text/javascript' src='https://yastatic.net/bootstrap/3.3.1/js/bootstrap.min.js'></script>\n";
  103. }
  104. void TIndexMonPage::OutputHead(IOutputStream& out) {
  105. out << "<head>\n";
  106. OutputCommonJsCss(out);
  107. out << "<title>" << Title << "</title>\n";
  108. out << "</head>\n";
  109. }
  110. void TIndexMonPage::OutputBody(IMonHttpRequest& req) {
  111. auto& out = req.Output();
  112. out << "<body>\n";
  113. // part of common navbar
  114. OutputNavBar(out);
  115. out << "<div class='container'>\n"
  116. << "<h2>" << Title << "</h2>\n";
  117. OutputIndex(out, req.GetPathInfo().EndsWith('/'));
  118. out << "<div>\n"
  119. << "</body>\n";
  120. }
  121. void TIndexMonPage::SortPages() {
  122. TGuard<TMutex> g(Mtx);
  123. std::sort(Pages.begin(), Pages.end(), [](const TMonPagePtr& a, const TMonPagePtr& b) {
  124. return AsciiCompareIgnoreCase(a->GetTitle(), b->GetTitle()) < 0;
  125. });
  126. }
  127. void TIndexMonPage::ClearPages() {
  128. TGuard<TMutex> g(Mtx);
  129. Pages.clear();
  130. PagesByPath.clear();
  131. }