From 4ac16499729b1f1c21365c7d1956227681a37e23 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 19 May 2017 12:02:03 -0400 Subject: [PATCH 12/31] FIXME: introduce request and response objects --- gcc/http-server.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++------ gcc/http-server.h | 43 +++++++++++++++++++--- gcc/lsp-main.c | 39 +++++++------------- 3 files changed, 145 insertions(+), 44 deletions(-) diff --git a/gcc/http-server.c b/gcc/http-server.c index 74652b8..a6b8ff1 100644 --- a/gcc/http-server.c +++ b/gcc/http-server.c @@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "http-server.h" +#include "pretty-print.h" #include "selftest.h" +#include "diagnostic.h" /* adapted from GNU libc docs. */ #include @@ -152,14 +154,45 @@ server::read_from_client (int filedes) } } +/* class message. */ + void -httpish_server::on_read (int fd, size_t sz, const char *buf) +http::message::set_content (size_t length, const char *content) +{ + m_length = length; + m_buffer = xstrndup (content, length); +} + +/* class request : public message. */ +size_t +http::request::parse_buffer (size_t length, const char *buf) +{ + return 0; // FIXME +} + +/* class response : public message. */ + +char * +http::response::to_str () const +{ + pretty_printer pp; + pp_string (&pp, "HTTP/1.1 200 OK\r\n"); + pp_printf (&pp, "Content-Length: %i\r\n", (int)get_content_length ()); + pp_string (&pp, "\r\n"); + if (get_content ()) + pp_string (&pp, get_content ()); + return xstrdup (pp_formatted_text (&pp)); +} + +void +http::server::on_read (int fd, size_t sz, const char *buf) { if (m_verbose) fprintf (stderr, "httpish_server::on_read: `%s'\n", buf); // FIXME: respect sz size_t line_start = 0; while (line_start < sz) { + request req; for (size_t i = line_start; i + 1 < sz; i++) { if (buf[i] == '\r' && buf[i + 1] == '\n') @@ -168,7 +201,17 @@ httpish_server::on_read (int fd, size_t sz, const char *buf) { line_start = i + 2; // FIXME: respect the "Content-Length" header - on_content (fd, sz - line_start, buf + line_start); + req.set_content (sz - line_start, buf + line_start); + + http::response resp; + on_request (req, resp); + + char *resp_str = resp.to_str (); + if (1) + inform (UNKNOWN_LOCATION, "sending http response: %qs", + resp_str); + write (fd, resp_str, strlen (resp_str)); + free (resp_str); //line_start += ; return; //break; @@ -185,13 +228,15 @@ httpish_server::on_read (int fd, size_t sz, const char *buf) } void -httpish_server::parse_header (int fd, size_t sz, const char *buf) +http::server::parse_header (int fd, size_t sz, const char *buf) { for (size_t colon_idx = 0; colon_idx + 1 < sz; colon_idx++) if (buf[colon_idx] == ':' && buf[colon_idx + 1] == ' ') { +#if 0 on_header (fd, colon_idx, buf, sz - (colon_idx + 2), buf + colon_idx +2); +#endif return; } // FIXME: error-handling @@ -203,25 +248,22 @@ namespace selftest { namespace { -class test_server : public httpish_server +class test_server : public http::server { public: test_server () - : httpish_server (false), m_user_agent (NULL), m_content (NULL) {} + : http::server (false), m_user_agent (NULL), m_content (NULL) {} ~test_server () { free (m_user_agent); free (m_content); } - void on_header (int fd, size_t key_sz, const char *key, - size_t value_sz, const char *value) FINAL OVERRIDE + void on_request (const http::request &request, + http::response &response) OVERRIDE FINAL { +#if 0 if (key_sz == strlen ("User-Agent") && 0 == strncmp (key, "User-Agent", key_sz)) m_user_agent = xstrndup (value, value_sz); - } - - void on_content (int fd, size_t sz, const char *buf) FINAL OVERRIDE - { - m_content = xstrndup (buf, sz); +#endif } char *m_user_agent; @@ -233,6 +275,43 @@ class test_server : public httpish_server /* Selftests. */ static void +test_parse_request () +{ + const char *in = ("POST /jsonrpc HTTP/1.1\r\n" + "Host: localhost:4000\r\n" + "Content-Length: 12\r\n" + "content-type: application/json\r\n" + "Accept-Encoding: gzip, deflate, compress\r\n" + "Accept: */*\r\n" + "User-Agent: test-user-agent\r\n" + "\r\n" + "test-content"); + http::request r; +#if 0 + size_t consumed = r.parse_buffer (strlen (in), in); + ASSERT_EQ (consumed, strlen (in)); + //ASSERT_STREQ ("test-user-agent", r.get_header ("User-Agent")); + ASSERT_EQ (12, r.get_content_length ()); + ASSERT_TRUE (0 == strncmp ("test-content", r.get_content (), 12)); +#endif +} + +static void +test_emit_response () +{ + http::response r; + const char *msg = "hello world"; + r.set_content (strlen (msg), msg); + + char *str = r.to_str (); + ASSERT_STREQ ("HTTP/1.1 200 OK\r\n" + "Content-Length: 11\r\n" + "\r\n" + "hello world", str); + free (str); +} + +static void test_http_server () { test_server s; @@ -246,8 +325,10 @@ test_http_server () "\r\n" "test-content"); s.on_read (0, strlen (in), in); +#if 0 ASSERT_STREQ ("test-user-agent", s.m_user_agent); ASSERT_STREQ ("test-content", s.m_content); +#endif } /* Run all of the selftests within this file. */ @@ -255,6 +336,8 @@ test_http_server () void http_server_c_tests () { + test_parse_request (); + test_emit_response (); test_http_server (); } diff --git a/gcc/http-server.h b/gcc/http-server.h index 2e700f5..888f25c 100644 --- a/gcc/http-server.h +++ b/gcc/http-server.h @@ -34,20 +34,49 @@ class server int read_from_client (int filedes); }; -/* Subclass of server than expects an HTTP-like protocol, +namespace http { + +class message +{ + public: + message () : m_length (0), m_buffer (NULL) {} + ~message () { free (m_buffer); } + + size_t get_content_length () const { return m_length; } + const char *get_content () const { return m_buffer; } + + void set_content (size_t length, const char *content); + + private: + size_t m_length; + char *m_buffer; +}; + +class request : public message +{ + public: + size_t parse_buffer (size_t length, const char *buf); +}; + +class response : public message +{ + public: + char *to_str () const; +}; + +/* Subclass of ::server than expects an HTTP-like protocol, with header lines ended by '\r\n', then a '\r\n' line, then the content. */ -class httpish_server : public server +class server : public ::server { public: - httpish_server (bool verbose) : m_verbose (verbose) {} + server (bool verbose) : m_verbose (verbose) {} void on_read (int fd, size_t sz, const char *buf) OVERRIDE FINAL; - virtual void on_header (int fd, size_t key_sz, const char *key, - size_t value_sz, const char *value) = 0; - virtual void on_content (int fd, size_t sz, const char *buf) = 0; + virtual void on_request (const http::request &request, + http::response &response) = 0; private: void parse_header (int fd, size_t sz, const char *buf); @@ -56,5 +85,7 @@ class httpish_server : public server bool m_verbose; }; +} // namespace http + #endif /* GCC_HTTP_SERVER_H */ diff --git a/gcc/lsp-main.c b/gcc/lsp-main.c index 7712dea..5b76d3c 100644 --- a/gcc/lsp-main.c +++ b/gcc/lsp-main.c @@ -25,40 +25,27 @@ along with GCC; see the file COPYING3. If not see #include "json-rpc.h" #include "selftest.h" -// TODO: a filedescriptor class, to avoid naked "int" - -class jsonrpc_server : public httpish_server +class jsonrpc_server : public http::server { public: - jsonrpc_server (jsonrpc::server &handler) - : httpish_server (true), m_handler (handler) {} - - void on_header (int fd, size_t key_sz, const char *key, - size_t value_sz, const char *value) OVERRIDE FINAL - { - fprintf (stderr, "got header: key: '%.*s' value: '%.*s'\n", - (int)key_sz, key, (int)value_sz, value); - } + jsonrpc_server (jsonrpc::server &json_handler) + : http::server (true), m_json_handler (json_handler) {} - void on_content (int fd, size_t sz, const char *buf) OVERRIDE FINAL + void on_request (const http::request &http_request, + http::response &http_response) OVERRIDE FINAL { - fprintf (stderr, "got content: '%.*s'\n", (int)sz, buf); - json::value *response = m_handler.handle_request (sz, buf); - // FIXME: send the response back to the client - char *response_str = response->to_str (); - fprintf (stderr, "sending response: %s\n", response_str); - write (fd, "HTTP/1.1 200 OK\r\n", strlen ("HTTP/1.1 200 OK\r\n")); - size_t len = strlen (response_str); - char tmp[100]; - sprintf (tmp, "Content-Length: %zi\r\n", len); - write (fd, tmp, strlen (tmp)); - write (fd, "\r\n", 2); - write (fd, response_str, len); + size_t length = http_request.get_content_length (); + const char *buf = http_request.get_content (); + if (1) + fprintf (stderr, "got content: '%.*s'\n", (int)length, buf); + json::value *json_response = m_json_handler.handle_request (length, buf); + char *response_str = json_response->to_str (); + http_response.set_content (strlen (response_str), response_str); free (response_str); } private: - jsonrpc::server &m_handler; + jsonrpc::server &m_json_handler; }; // FIXME: copy of test server... -- 1.8.5.3