LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/sandesh/library/cpp - sandesh_http.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 115 179 64.2 %
Date: 2026-08-03 02:19:58 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : //
       6             : // sandesh_http.cc
       7             : //
       8             : // Implementation of SandeshHttp
       9             : //
      10             : // - Register each .sandesh file for generating webpage with all Requests
      11             : // - API for Registering Sandesh Requests so they can be served by HttpServer
      12             : // - Init and Uninit of HttpServer
      13             : //
      14             : 
      15             : #include <cstring>
      16             : #include <cstdlib>
      17             : #include <mutex>
      18             : 
      19             : #include "io/event_manager.h"
      20             : #include "http/http_server.h"
      21             : #include <boost/bind/bind.hpp>
      22             : #include <boost/tokenizer.hpp>
      23             : 
      24             : #include <sandesh/sandesh_types.h>
      25             : #include <sandesh/sandesh.h>
      26             : #include <sandesh/sandesh_http.h>
      27             : #include <sandesh/transport/TBufferTransports.h>
      28             : #include <sandesh/protocol/TXMLProtocol.h>
      29             : #include "sandesh_client.h"
      30             : #include <sandesh/sandesh_trace.h>
      31             : #include <sandesh/sandesh_trace_types.h>
      32             : 
      33             : #include "http/http_request.h"
      34             : #include "http/http_server.h"
      35             : #include "http/http_session.h"
      36             : 
      37             : #include "css_bootstrap_min_css.cpp"
      38             : #include "css_DT_bootstrap_css.cpp"
      39             : #include "css_images_sort_asc_png.cpp"
      40             : #include "css_images_sort_asc_disabled_png.cpp"
      41             : #include "css_images_sort_both_png.cpp"
      42             : #include "css_images_sort_desc_png.cpp"
      43             : #include "css_images_sort_desc_disabled_png.cpp"
      44             : #include "css_style_css.cpp"
      45             : #include "js_bootstrap_min_js.cpp"
      46             : #include "js_DT_bootstrap_js.cpp"
      47             : #include "js_jquery_2_0_3_min_js.cpp"
      48             : #include "js_jquery_dataTables_min_js.cpp"
      49             : #include "js_util_js.cpp"
      50             : #include "universal_parse_xsl.cpp"
      51             : 
      52             : 
      53             : static int kEncodeBufferSize = 4096;
      54             : 
      55             : using namespace contrail::sandesh::protocol;
      56             : using namespace std;
      57             : using namespace boost::placeholders;
      58             : 
      59             : using contrail::sandesh::transport::TMemoryBuffer;
      60             : 
      61             : SandeshHttp::map_type* SandeshHttp::map_ = NULL;
      62             : HttpServer* SandeshHttp::hServ_ = NULL;
      63             : string SandeshHttp::index_str_;
      64             : SandeshHttp::HtmlInfo *SandeshHttp::index_hti_ = NULL;
      65             : 
      66             : 
      67             : #define SESSION_SEND(buf) \
      68             :     HttpSession::SendSession(context,reinterpret_cast<const u_int8_t *>(buf), strlen(buf), NULL)
      69             : 
      70             : enum HttpXMLState {
      71             :     HXMLInvalid,
      72             :     HXMLNew,
      73             :     HXMLIncomplete,
      74             :     HXMLMax
      75             : };
      76             : 
      77             : // Helper function for forming HTTP headers and sending a bytestream
      78             : // for XML
      79             : //
      80             : // Arguments:
      81             : //   context : handle to Session on which to send bytestream
      82             : //   buf : Buffer that contains XML payload
      83             : //   len : length of buffer
      84             : //   name : Name of Sandesh Module
      85             : //   more : This is true if there is more content coming for this response
      86             : //
      87             : static void
      88          10 : HttpSendXML(const std::string& context, const u_int8_t * buf, uint32_t len,
      89             :             const char * name, bool more) {
      90             : 
      91             :     char buffer_str[100];
      92             :     char length_str[80];
      93             :     static const char xsl_response[] =
      94             : "HTTP/1.1 200 OK\r\n"
      95             : "Content-Type: text/xml\r\n"
      96             : ;
      97             :     static const char chunk_response[] =
      98             : "HTTP/1.1 200 OK\r\n"
      99             : "Content-Type: text/xml\r\n"
     100             : "Transfer-Encoding: chunked\r\n\r\n"
     101             : ;
     102             :     char resp_name[40];
     103          10 :     int loc = strcspn(reinterpret_cast<const char *>(buf)," ");
     104          10 :     strncpy(resp_name, reinterpret_cast<const char *>(buf + 1), loc - 1);
     105          10 :     resp_name[loc - 1] = 0;
     106             : 
     107             :     static std::mutex hmutex;
     108             :     static int seq = 0;
     109          10 :     std::scoped_lock lock(hmutex);
     110          10 :     std::string client_ctx;
     111          10 :     seq++;
     112             : 
     113          10 :     client_ctx = HttpSession::get_client_context(context);
     114             :     HttpXMLState state;
     115             : 
     116             :     // Calculate current state;
     117          10 :     if (!client_ctx.empty()) {
     118           0 :         state = HXMLIncomplete;
     119             :     } else {
     120          10 :         state = HXMLNew;
     121          10 :         client_ctx = resp_name;
     122             : 
     123             :         // If the session is gone, we can stop processing.
     124          10 :         if (!HttpSession::set_client_context(context, client_ctx))
     125           0 :             return;
     126             :     }
     127             : 
     128          10 :     if ((HXMLNew == state) && (!more)) {
     129             :         // This is the first and last chunk of this response
     130             : 
     131          10 :         SESSION_SEND(xsl_response);
     132             : 
     133          10 :         size_t total_len = len;
     134          10 :         sprintf(buffer_str,
     135             :             "<?xml-stylesheet type=\"text/xsl\" href=\"/universal_parse.xsl\"?>"
     136             :             );
     137          10 :         sprintf(length_str,
     138          10 :                 "Content-Length: %zu\r\n\r\n", total_len + strlen(buffer_str));
     139          10 :         SESSION_SEND(length_str);
     140          10 :         SESSION_SEND(buffer_str);
     141             : 
     142          10 :         HttpSession::SendSession(context, buf, len, NULL);
     143             : 
     144          10 :     } else if ((HXMLNew == state) && more) {
     145             :         // This is the first chunk of this response
     146           0 :         SESSION_SEND(chunk_response);
     147             : 
     148             :         // Calculation for Header
     149           0 :         sprintf(buffer_str,
     150             :             "<?xml-stylesheet type=\"text/xsl\" href=\"/universal_parse.xsl\"?>"
     151             :             );
     152           0 :         int hdr_len = strlen(buffer_str);
     153           0 :         sprintf(buffer_str,
     154             :             "<__%s_list type=\"slist\">\r\n", client_ctx.c_str());
     155           0 :         hdr_len += (strlen(buffer_str) - 2);
     156             : 
     157           0 :         sprintf(length_str, "%x\r\n", hdr_len);
     158           0 :         SESSION_SEND(length_str);
     159             : 
     160           0 :         sprintf(buffer_str,
     161             :             "<?xml-stylesheet type=\"text/xsl\" href=\"/universal_parse.xsl\"?>"
     162             :             );
     163           0 :         SESSION_SEND(buffer_str);
     164             : 
     165           0 :         sprintf(buffer_str,
     166             :             "<__%s_list type=\"slist\">\r\n", client_ctx.c_str());
     167           0 :         SESSION_SEND(buffer_str);
     168             : 
     169             : 
     170             :         // Calculation for Data
     171           0 :         sprintf(length_str, "%x\r\n", len);
     172           0 :         SESSION_SEND(length_str);
     173             : 
     174           0 :         HttpSession::SendSession(context, buf, len, NULL);
     175             : 
     176           0 :         sprintf(buffer_str,"\r\n");
     177           0 :         SESSION_SEND(buffer_str);
     178             : 
     179           0 :     } else if ((HXMLIncomplete == state) && !more) {
     180             :         // This is the last chunk of this response
     181             : 
     182             :         // Calculation for Data
     183           0 :         sprintf(length_str, "%x\r\n", len);
     184           0 :         SESSION_SEND(length_str);
     185             : 
     186           0 :         HttpSession::SendSession(context, buf, len, NULL);
     187             : 
     188           0 :         sprintf(buffer_str,"\r\n");
     189           0 :         SESSION_SEND(buffer_str);
     190             : 
     191             :         //Calculation for Footer
     192           0 :         sprintf(buffer_str,"</__%s_list>\r\n", client_ctx.c_str());
     193           0 :         sprintf(length_str, "%zx\r\n", strlen(buffer_str) - 2);
     194           0 :         SESSION_SEND(length_str);
     195           0 :         SESSION_SEND(buffer_str);
     196             : 
     197           0 :         sprintf(length_str, "0\r\n\r\n");
     198           0 :         SESSION_SEND(length_str);
     199           0 :     } else if ((HXMLIncomplete == state) && more) {
     200             :         // This is a middle chunk of the response
     201             : 
     202             :         // Calculation for Data
     203           0 :         sprintf(length_str, "%x\r\n", len);
     204           0 :         SESSION_SEND(length_str);
     205             : 
     206           0 :         HttpSession::SendSession(context, buf, len, NULL);
     207             : 
     208           0 :         sprintf(buffer_str,"\r\n");
     209           0 :         SESSION_SEND(buffer_str);
     210             :     }
     211             :     // Update context for other users
     212          10 :     if (!more) {
     213          10 :         client_ctx = resp_name;
     214          10 :         HttpSession::set_client_context(context,"");
     215             :     }
     216             : 
     217          10 : }
     218             : 
     219             : // Function for HTTP Server to call when HTTP Client Requests a .sandesh module
     220             : // or it's stylesheet
     221             : //
     222             : // Arguments:
     223             : //   hti : Buffer Ptr and length of HTTP payload to send
     224             : //   session : HttpSession on which to send
     225             : //   request : Contains the URL that was sent by the Client
     226             : //
     227             : static void
     228           0 : HttpSandeshFileCallback(SandeshHttp::HtmlInfo *hti,
     229             :         HttpSession *session,
     230             :         const HttpRequest *request) {
     231             : 
     232             :     char length_str[80];
     233             :     static const char html_response[] =
     234             : "HTTP/1.1 200 OK\r\n"
     235             : ;
     236             :     static const char json_response[] =
     237             : "HTTP/1.1 200 OK\r\n"
     238             : "Content-Type: application/json\r\n"
     239             : ;
     240             :     static const char xsl_response[] =
     241             : "HTTP/1.1 200 OK\r\n"
     242             : "Content-Type: text/xsl\r\n"
     243             : ;
     244             :     static const char xml_response[] =
     245             : "HTTP/1.1 200 OK\r\n"
     246             : "Content-Type: text/xml\r\n"
     247             : ;
     248             :     static const char css_response[] =
     249             : "HTTP/1.1 200 OK\r\n"
     250             : "Content-Type: text/css\r\n"
     251             : ;
     252             :     const char * response =
     253           0 :         ((request->UrlPath().find(".js")!=string::npos) ?
     254           0 :          json_response : ((request->UrlPath().find(".xsl")!=string::npos) ?
     255           0 :             xsl_response : ((request->UrlPath().find(".css")!=string::npos) ?
     256           0 :                 css_response : ((request->UrlPath().find(".xml")!=string::npos) ?
     257           0 :                     xml_response : html_response))));
     258             : 
     259           0 :     sprintf(length_str,
     260             :             "Content-Length: %d\r\n\r\n", hti->html_len());
     261           0 :     session->Send(reinterpret_cast<const u_int8_t *>(response),
     262             :             strlen(response), NULL);
     263           0 :     session->Send(reinterpret_cast<const u_int8_t *>(length_str),
     264             :             strlen(length_str), NULL);
     265           0 :     session->Send(hti->html_str(), hti->html_len(), NULL);
     266           0 :     delete request;
     267           0 : }
     268             : 
     269             : SandeshHttp::RequestCallbackFn httpreqcb;
     270             : 
     271             : // Function for HTTP Server to call when HTTP Client sends a Sandesh Request
     272             : //
     273             : // Arguments:
     274             : //   hs : Ptr to the HTTP Server
     275             : //   session : HttpSession on which to send
     276             : //   request : Contains the URL that was sent by the Client
     277             : //             This URL encodes the attributes of the Sandesh Request
     278             : //
     279             : static void
     280          10 : HttpSandeshRequestCallback(HttpServer *hs,
     281             :         HttpSession *session,
     282             :         const HttpRequest *request) {
     283             : 
     284          10 :     string snh_name = request->UrlPath().substr(5);
     285          10 :     Sandesh *sandesh = SandeshBaseFactory::CreateInstance(snh_name);
     286          10 :     if (sandesh == NULL) {
     287           0 :         SANDESH_LOG(DEBUG, __func__ << " Unknown sandesh:" <<
     288             :             snh_name << std::endl);
     289           0 :         return;
     290             :     }
     291          10 :     SandeshRequest *rsnh = dynamic_cast<SandeshRequest *>(sandesh);
     292          10 :     assert(rsnh);
     293          10 :     rsnh->RequestFromHttp(session->get_context(), request->UrlQuery());
     294          10 :     httpreqcb(rsnh);
     295          10 :     delete request;
     296          10 : }
     297             : 
     298             : // This function is called by the Sandesh Response handling code
     299             : // if the "context" of the Originating Sandesh Request indicates
     300             : // that the Request came from the HTTP Server
     301             : // We will form a HTTP/XML payload to send the contents of the Sandesh
     302             : // response back to the HTTP Client
     303             : //
     304             : // Arguments:
     305             : //   snh : Sandesh Response to send to the HTTP Client (base class)
     306             : //   context: Context that was in the Sandesh Request.
     307             : //            All HTTP Server-originated contexts start with "http%"
     308             : //
     309             : void
     310          10 : SandeshHttp::Response(Sandesh *snh, std::string context) {
     311          10 :     bool more = false;
     312             : 
     313          10 :     SandeshResponse * rsnh = dynamic_cast<SandeshResponse *>(snh);
     314          10 :     if (rsnh) {
     315          10 :         more = rsnh->get_more();
     316             :     } else {
     317           0 :         SandeshTrace * tsnh = dynamic_cast<SandeshTrace *>(snh);
     318           0 :         if (tsnh) {
     319           0 :             more = tsnh->get_more();
     320             :         } else {
     321           0 :             SandeshUVE * usnh = dynamic_cast<SandeshUVE *>(snh);
     322           0 :             assert(usnh);
     323           0 :             more = usnh->get_more();
     324             :         }
     325             :     }
     326          10 :     std::stringstream ss;
     327             :     uint8_t *buffer;
     328          10 :     uint32_t xfer = 0, offset;
     329             : 
     330             :     boost::shared_ptr<TMemoryBuffer> btrans =
     331             :             boost::shared_ptr<TMemoryBuffer>(
     332          10 :                     new TMemoryBuffer(kEncodeBufferSize));
     333             :     boost::shared_ptr<TXMLProtocol> prot =
     334             :             boost::shared_ptr<TXMLProtocol>(
     335          10 :                     new TXMLProtocol(btrans));
     336             :     // Write the sandesh
     337          10 :     xfer += snh->Write(prot);
     338             :     // Get the buffer
     339          10 :     btrans->getBuffer(&buffer, &offset);
     340          10 :     HttpSendXML(context, buffer, offset, snh->ModuleName().c_str(), more);
     341          10 :     buffer[offset] = 0;
     342          10 :     snh->Release();
     343          10 : }
     344             : 
     345             : // This function should be called during Sandesh Generator Initialization
     346             : // It initializes the HTTP Server and Registers callbacks for sandesh modules
     347             : // and sandesh requests.
     348             : //
     349             : // Arguments:
     350             : //   evm : EventManager that should be used by the HTTP Server
     351             : //   module : Name of module
     352             : //   port : Port number for HTTP Server (e.g. 8080)
     353             : //
     354             : bool
     355          87 : SandeshHttp::Init(EventManager *evm, const string module,
     356             :     short port, RequestCallbackFn reqcb, int *hport, const SandeshConfig &config) {
     357          87 :     if (hServ_) {
     358           0 :         *hport = hServ_->GetPort();
     359          87 :         return true;
     360             :     }
     361          87 :     ostringstream index_ss;
     362             : 
     363         174 :     SandeshTraceBufferPtr httpbuf(SandeshTraceBufferCreate("httpbuf", 100));
     364          87 :     SANDESH_TRACE_TEXT_TRACE(httpbuf, "<Initializing httpbuf");
     365          87 :     SANDESH_TRACE_TEXT_TRACE(httpbuf, "Size 100");
     366             : 
     367          87 :     uint8_t dscp = 0;
     368          87 :     SandeshClient *client = Sandesh::client();
     369          87 :     if (client) {
     370           0 :         dscp = client->dscp_value();
     371             :     }
     372          87 :     struct SslConfig sslConfig;
     373          87 :     sslConfig.ssl_enabled = config.introspect_ssl_enable;
     374          87 :     sslConfig.ca_cert = config.ca_cert;
     375          87 :     sslConfig.certfile = config.server_certfile;
     376          87 :     sslConfig.keyfile = config.server_keyfile;
     377          87 :     sslConfig.ssl_insecure = config.introspect_ssl_insecure;
     378          87 :     hServ_ = new HttpServer(evm, sslConfig, dscp);
     379          87 :     httpreqcb = reqcb;
     380             :     index_ss << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" <<
     381          87 :         " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" << endl;
     382          87 :     index_ss << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
     383             :     index_ss << "<head>" <<
     384             :         "<link href=\"css/style.css\" rel=\"stylesheet\" type=\"text/css\"/>" <<
     385          87 :         "<title>" << module << "</title></head><body>" << endl;
     386          87 :     index_ss << "<h1>Modules for " << module << "</h1>" << endl;
     387             : 
     388        1917 :     for (map_type::iterator it=map_->begin(); it!=map_->end(); it++) {
     389        1830 :         std::string regString = "/" + it->first;
     390        1830 :         hServ_->RegisterHandler(regString.c_str(),
     391        1830 :                 boost::bind(&HttpSandeshFileCallback, &it->second, _1, _2));
     392        1830 :         if (it->first.find(".xml")!=string::npos) {
     393        1224 :             index_ss << "<a href=\"" << it->first << "\">" <<
     394         612 :                 it->first << "</a><br/>" << endl;
     395             :         }
     396        1830 :     }
     397          87 :     index_ss << "</body></html>" << endl;
     398             : 
     399          87 :     index_str_ = index_ss.str();
     400          87 :     const char * index_str = index_str_.c_str();
     401          87 :     SANDESH_LOG(DEBUG, "HTTP Introspect Init");
     402             : 
     403          87 :     index_hti_ = new HtmlInfo(reinterpret_cast<const unsigned char *>(
     404          87 :                 index_str),strlen(index_str));
     405          87 :     hServ_->RegisterHandler("/index.html",
     406             :         boost::bind(&HttpSandeshFileCallback, index_hti_, _1, _2));
     407          87 :     hServ_->RegisterHandler("/",
     408             :         boost::bind(&HttpSandeshFileCallback, index_hti_, _1, _2));
     409             : 
     410          87 :     SandeshBaseFactory::map_type::const_iterator it= SandeshBaseFactory::Begin();
     411        6104 :     for (; it!=SandeshBaseFactory::End(); it++) {
     412        6017 :         std::string regString = "/Snh_" + (*it).first;
     413        6017 :         hServ_->RegisterHandler(regString.c_str(),
     414             :             boost::bind(&HttpSandeshRequestCallback, hServ_, _1, _2));
     415        6017 :     }
     416             : 
     417          87 :     boost::system::error_code ec;
     418             :     bool success;
     419             :     IpAddress http_ip =
     420          87 :         boost::asio::ip::address::from_string(config.http_server_ip, ec);
     421          87 :     if (!ec) {
     422          44 :         success = hServ_->Initialize(port, http_ip);
     423             :     } else {
     424          43 :         success = hServ_->Initialize(port);
     425             :     }
     426          87 :     hServ_->SetSocketOptions(config);
     427          87 :     if (success) {
     428          87 :         int lport(hServ_->GetPort());
     429          87 :         SANDESH_LOG(DEBUG, "Sandesh Http Server Port: " << lport);
     430          87 :         *hport = lport;
     431          87 :         return true;
     432             :     } else {
     433           0 :         SANDESH_LOG(ERROR, "Failed to initialize Sandesh Http Server Port: "
     434             :             << port);
     435           0 :         return false;
     436             :     }
     437             :     if (dscp) {
     438             :         hServ_->SetListenSocketDscp(dscp);
     439             :     }
     440         261 : }
     441             : 
     442             : // Function to shut down HTTP Server
     443             : void
     444          87 : SandeshHttp::Uninit(void) {
     445          87 :     if (!hServ_) return;
     446             : 
     447          87 :     index_str_.clear();
     448          87 :     delete index_hti_;
     449             : 
     450          87 :     hServ_->Shutdown();
     451          87 :     hServ_->ClearSessions();
     452          87 :     hServ_->WaitForEmpty();
     453             : 
     454             :     //
     455             :     // TODO TcpServer delete can only happen after all inflight sessions
     456             :     // have been properly deleted. ASIO threads can hold reference to
     457             :     // HttpSession objects
     458             :     //
     459          87 :     TcpServerManager::DeleteServer(hServ_);
     460          87 :     hServ_ = NULL;
     461             : }
     462             : 
     463             : void
     464           0 : SandeshHttp::UpdateDscp(uint8_t dscp) {
     465           0 :     if (!hServ_) return;
     466           0 :     hServ_->UpdateDscp(dscp);
     467           0 :     hServ_->UpdateSessionsDscp(dscp);
     468             : }

Generated by: LCOV version 1.14