]> sourceware.org Git - systemtap.git/commitdiff
Add httpd server updates.
authorDavid Smith <dsmith@redhat.com>
Fri, 12 May 2017 16:36:24 +0000 (11:36 -0500)
committerDavid Smith <dsmith@redhat.com>
Fri, 12 May 2017 16:36:24 +0000 (11:36 -0500)
* httpd/server.cxx (server::access_handler): Save regexp matches.
  (server::queue_response): Add response headers.
* httpd/main.cxx: Add initial support for build info.
* httpd/Makefile.am: Link with the json-c library.
* httpd/server.h (struct request): Add 'matches' variable.
* configure.ac: Add the json-c library as a requirement of the httpd
  server.
* config.in: Regenerated.
* configure: Ditto.
* httpd/Makefile.in: Ditto.

config.in
configure
configure.ac
httpd/Makefile.am
httpd/Makefile.in
httpd/main.cxx
httpd/server.cxx
httpd/server.h

index a3351251b0a696823feb9f741d601c6ea23a046a..eb1de5b9860fb8b27808ef89fa3727c9d2954d33 100644 (file)
--- a/config.in
+++ b/config.in
@@ -86,9 +86,6 @@
 /* Define to 1 if libxml2 development libraries are installed */
 #undef HAVE_LIBXML2
 
-/* Define to 1 if you have the <linux/bpf.h> header file. */
-#undef HAVE_LINUX_BPF_H
-
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
index d0f8d938add8072b468f4dab3ed242c786de2f29..a86a167f45de3d5efa105dfdad9e0c1cc8744a01 100755 (executable)
--- a/configure
+++ b/configure
@@ -12743,7 +12743,7 @@ $as_echo "yes" >&6; }
        have_libuuid=true
 fi
 
-         if test "x$have_libmicrohttpd" == "xtrue" -a "x$have_libuuid" == "xtrue"; then :
+         if test "x$have_libmicrohttpd" == "xtrue" -a "x$have_libuuid" == "xtrue" -a "x$have_jsonc" == "xyes"; then :
   have_http_support=yes
 fi
 fi
index b4222913b78dae60ace846e3b348f4cf4d866681..5192df7c56468925f6c6de55b7985cd7d108a66a 100644 (file)
@@ -908,9 +908,9 @@ AS_IF([test "x$enable_http" != "xno"],
    dnl Do we have the uuid library?
    PKG_CHECK_MODULES([uuid], [uuid >= 2.17.0], [have_libuuid=true], [have_libuuid=false])
 
-   dnl If we have both libraries, we could build the httpd web
-   dnl complilation service.
-   AS_IF([test "x$have_libmicrohttpd" == "xtrue" -a "x$have_libuuid" == "xtrue"], [have_http_support=yes])])
+   dnl If we have both libraries (and the json-c library), we could
+   dnl build the httpd web complilation service.
+   AS_IF([test "x$have_libmicrohttpd" == "xtrue" -a "x$have_libuuid" == "xtrue" -a "x$have_jsonc" == "xyes"], [have_http_support=yes])])
 
 AS_IF([test "x$have_http_support" = "xyes"],
   [AC_DEFINE([HAVE_HTTP_SUPPORT], [1],
index 784ace2e40062d89ed6cd1d2379bf1a758215551..e4de56030b0f0275ec7e6744c68564e899cab8be 100644 (file)
@@ -20,7 +20,7 @@ stap_httpd_SOURCES = main.cxx server.cxx ../util.cxx
 stap_httpd_CFLAGS = $(AM_CFLAGS)
 stap_httpd_CXXFLAGS = $(AM_CXXFLAGS)
 stap_httpd_CPPFLAGS = $(AM_CPPFLAGS)
-stap_httpd_LDADD = -lpthread -lmicrohttpd -luuid
+stap_httpd_LDADD = -lpthread -lmicrohttpd -luuid -ljson-c
 stap_httpd_LDFLAGS =  $(AM_LDFLAGS)
 endif
 
index 506ff7fc9c74dc61a24385f3f2c4a68dbe54f326..1e683b286e15ac90cf8293130ac17d9de2676b0e 100644 (file)
@@ -389,7 +389,7 @@ AM_LDFLAGS = @PIELDFLAGS@
 @HAVE_HTTP_SUPPORT_TRUE@stap_httpd_CFLAGS = $(AM_CFLAGS)
 @HAVE_HTTP_SUPPORT_TRUE@stap_httpd_CXXFLAGS = $(AM_CXXFLAGS)
 @HAVE_HTTP_SUPPORT_TRUE@stap_httpd_CPPFLAGS = $(AM_CPPFLAGS)
-@HAVE_HTTP_SUPPORT_TRUE@stap_httpd_LDADD = -lpthread -lmicrohttpd -luuid
+@HAVE_HTTP_SUPPORT_TRUE@stap_httpd_LDADD = -lpthread -lmicrohttpd -luuid -ljson-c
 @HAVE_HTTP_SUPPORT_TRUE@stap_httpd_LDFLAGS = $(AM_LDFLAGS)
 
 # Arrange for the top-level git_version.h to be regenerated at every "make".
index 0da4ed45da1324d0d2823af5a04887812f8865ed..3ce9cc703b1e97c87c254c3200a0a9d1efb42993 100644 (file)
@@ -7,6 +7,9 @@
 // later version.
 
 #include "server.h"
+#include "iostream"
+#include "iomanip"
+#include <sstream>
 
 extern "C" {
 #include <unistd.h>
@@ -14,21 +17,156 @@ extern "C" {
 #include <signal.h>
 #include <errno.h>
 #endif
+#include <uuid/uuid.h>
+#include <json-c/json_object.h>
 }
-//using namespace std;
 
-#define PAGE "<html><head><title>Error</title></head><body>Bad data</body></html>"
+string get_uuid_representation(const uuid_t uuid)
+{
+    ostringstream os;
+
+    os << hex << setfill('0');
+    for (const unsigned char *ptr = uuid; ptr < uuid + sizeof(uuid_t); ptr++)
+        os << setw(2) << (unsigned int)*ptr;
+    return os.str();
+}
+
+struct build_info
+{
+    uuid_t uuid;
+    string uuid_str;
+    string uri;
+
+    string kver;
+    string arch;
+    string cmdline;
+
+    build_info() {
+       uuid_generate(uuid);
+       uuid_str = get_uuid_representation(uuid);
+       uri = "/builds/" + uuid_str;
+    }
+
+    string content();
+};
+
+string build_info::content()
+{
+    ostringstream os;
+    os << "{" << endl;
+    os << "  \"uuid\": \"" << uuid_str << "\"" << endl;
+    os << "  \"kver\": \"" << kver << "\"" << endl;
+    os << "  \"arch\": \"" << arch << "\"" << endl;
+
+    struct json_object *j = json_object_new_string(cmdline.c_str());
+    if (j) {
+       os << "  \"cmdline\": "
+          << json_object_to_json_string_ext(j, JSON_C_TO_STRING_PLAIN) << endl;
+    }
+
+    os << "}" << endl;
+    return os.str();
+}
+
+mutex builds_mutex;
+vector<build_info *> build_infos;
+
+class build_collection : public request_handler
+{
+public:
+    response POST(const request &req);
+
+    build_collection(string n) : request_handler(n) {}
+};
+
+response build_collection::POST(const request &req)
+{
+    // Create a build with the information we've gathered.
+    build_info *b = new build_info;
+    for (auto it = req.params.begin(); it != req.params.end(); it++) {
+       if (it->first == "kver") {
+           b->kver = it->second;
+       }
+       else if (it->first == "arch") {
+           b->arch = it->second;
+       }
+       else if (it->first == "cmdline") {
+           b->cmdline = it->second;
+       }
+    }
+
+    // Make sure we've got everything we need.
+    if (b->kver.empty() || b->arch.empty() || b->cmdline.empty()) {
+       // Return an error.
+       clog << "400 - bad request" << endl;
+       response error400(400);
+       error400.content = "<h1>Bad request</h1>";
+       return error400;
+    }
+
+    {
+       // Use a lock_guard to ensure the mutex gets released even if an
+       // exception is thrown.
+       lock_guard<mutex> lock(builds_mutex);
+       build_infos.push_back(b);
+    }
+
+    clog << "Returning a 202" << endl;
+    response resp(202);
+    resp.headers["Location"] = b->uri;
+    resp.headers["Retry-After"] = "20";
+    return resp;
+}
+
+class individual_build : public request_handler
+{
+public:
+    response GET(const request &req);
+
+    individual_build(string n) : request_handler(n) {}
+};
+
+response individual_build::GET(const request &req)
+{
+    clog << "individual_build::GET" << endl;
+
+    // matches[0] is the entire string '/builds/XXXX'. matches[1] is
+    // just the buildid 'XXXX'.
+    string buildid = req.matches[1];
+    build_info *b = NULL;
+    {
+       // Use a lock_guard to ensure the mutex gets released even if an
+       // exception is thrown.
+       lock_guard<mutex> lock(builds_mutex);
+       for (auto it = build_infos.begin(); it != build_infos.end(); it++) {
+           clog << "Comparing '" << buildid << "'to '" << (*it)->uuid_str << "'" << endl;
+           if (buildid == (*it)->uuid_str) {
+               b = *it;
+               break;
+           }
+       }
+    }
+
+    if (b == NULL) {
+       clog << "Couldn't find build '" << buildid << "'" << endl;
+       return get_404_response();
+    }
+
+    response rsp(200, "application/json");
+    rsp.content = b->content();
+    return rsp;
+}
 
-class request_handler build_collection("build collection");
-class request_handler build("individual build");
+build_collection builds("build collection");
+individual_build build("individual build");
 
 int
 main(int /*argc*/, char *const /*argv*/[])
 {
     server httpd(1234);
 
-    httpd.add_request_handler("/builds$", build_collection);
-    httpd.add_request_handler("/builds/[0-9]+$", build);
+    httpd.add_request_handler("/builds$", builds);
+    httpd.add_request_handler("/builds/([0-9a-f]+)$", build);
     // FIXME: Should this be pthread_cond_wait()/pthread_cond_timedwait()?
     while (1) {
        sleep(1);
index dd47af2171925cd35f7c53dd80fee64cf1fe5054..72e541a521dc23fa8c03e65cc2ef870d4e7c9bcc 100644 (file)
@@ -101,7 +101,7 @@ connection_info::postdataiterator(enum MHD_ValueKind kind,
     return MHD_YES;
 }
 
-static response
+response
 get_404_response()
 {
     response error404(404);
@@ -209,6 +209,7 @@ server::access_handler(struct MHD_Connection *connection,
        return queue_response(get_404_response(), connection);
     }
 
+    struct request rq_info;
     request_handler *rh = NULL;
     clog << "Looking for a matching request handler match with '"
         << url_str << "'..." << endl;
@@ -221,8 +222,7 @@ server::access_handler(struct MHD_Connection *connection,
        for (auto it = request_handlers.begin();
             it != request_handlers.end(); it++) {
            string url_path_re = get<0>(*it);
-           vector<string> matches;
-           if (regexp_match(url_str, url_path_re, matches) == 0) {
+           if (regexp_match(url_str, url_path_re, rq_info.matches) == 0) {
                rh = get<1>(*it);
                clog << "Found a match with '" << rh->name << "'" << endl;
                break;
@@ -236,7 +236,6 @@ server::access_handler(struct MHD_Connection *connection,
 
     // Prepare to call the appropriate request handler method by
     // gathering up all the request info.
-    struct request rq_info;
     enum MHD_ValueKind kind = ((rq_method == request_method::POST)
                               ? MHD_POSTDATA_KIND
                               : MHD_GET_ARGUMENT_KIND);
@@ -292,13 +291,13 @@ server::queue_response(const response &response, MHD_Connection *connection)
        return MHD_NO;
     }
 
-#if 0
-    for (const auto &header : response.headers) {
-        MHD_add_response_header(mhd_response, header.first.c_str(),
-                               header.second.c_str());
+    for (auto it = response.headers.begin(); it != response.headers.end();
+        it++) {
+        MHD_add_response_header(mhd_response, it->first.c_str(),
+                               it->second.c_str());
     }
-#endif
-    MHD_add_response_header(mhd_response, MHD_HTTP_HEADER_CONTENT_TYPE, response.content_type.c_str());
+    MHD_add_response_header(mhd_response, MHD_HTTP_HEADER_CONTENT_TYPE,
+                           response.content_type.c_str());
 
 //    MHD_add_response_header(mhd_response, MHD_HTTP_HEADER_SERVER, server_identifier_.c_str());
     int ret = MHD_queue_response(connection, response.status_code,
index 5333d68e6b9c97f0979ee2f3592ef6f6d5fa626a..ada8472da436c9d011b6d5cff1ed37436214179f 100644 (file)
@@ -17,6 +17,7 @@ using namespace std;
 struct response
 {
     unsigned int status_code;
+    map<string, string> headers;
     string content;
     string content_type;
 
@@ -27,12 +28,12 @@ struct response
     }
 };
 
+extern response get_404_response();
+
 struct request
 {
-#if 0
-    endpoint_matches matches;
-#endif
     map<string, string> params;
+    vector<string> matches;
 #if 0
     request_headers headers;
     std::string body;
This page took 0.056633 seconds and 5 git commands to generate.