From 58c5c2f6885df65087cd3fc0be6c932f36d4bd53 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 19 May 2017 12:59:48 -0400
Subject: [PATCH 15/31] FIXME: flesh out http::request

---
 gcc/http-server.c | 167 ++++++++++++++++++++++++++----------------------------
 gcc/http-server.h |  13 ++++-
 2 files changed, 90 insertions(+), 90 deletions(-)

diff --git a/gcc/http-server.c b/gcc/http-server.c
index 1906500..ba5fc13 100644
--- a/gcc/http-server.c
+++ b/gcc/http-server.c
@@ -25,7 +25,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "selftest.h"
 #include "diagnostic.h"
 
-/* class message.  */
+/* class http::message.  */
+
+/* FIXME.  */
 
 void
 http::message::set_content (size_t length, const char *content)
@@ -34,38 +36,37 @@ http::message::set_content (size_t length, const char *content)
   m_buffer = xstrndup (content, length);
 }
 
-/* class request : public message.  */
+/* class http::request : public http::message.  */
 
-size_t
-http::request::parse_buffer (size_t length, const char *buf)
+http::request::~request()
 {
-  return 0; // FIXME
+  for (header_map_t::iterator it = m_header_map.begin ();
+       it != m_header_map.end (); ++it)
+    {
+      free (const_cast <char *>((*it).first));
+      free (const_cast <char *>((*it).second));
+    }
 }
 
-/* class response : public message.  */
+/* FIXME.  */
 
-char *
-http::response::to_str () const
+const char *
+http::request::get_header (const char *header) 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));
+  char **slot = const_cast <request*> (this)->m_header_map.get (header);
+  if (slot)
+    return *slot;
+  return NULL;
 }
 
-void
-http::server::on_read (file_descriptor fd, size_t length, const char *buf)
+/* FIXME.  */
+
+size_t
+http::request::parse_buffer (size_t length, const char *buf)
 {
-  if (m_verbose)
-    inform (UNKNOWN_LOCATION, "received http request: %qs",
-	    buf); // FIXME respect length
   size_t line_start = 0;
   while (line_start < length)
     {
-      request req;
       for (size_t i = line_start; i + 1 < length; i++)
 	{
 	  if (buf[i] == '\r' && buf[i + 1] == '\n')
@@ -74,79 +75,90 @@ http::server::on_read (file_descriptor fd, size_t length, const char *buf)
 		{
 		  line_start = i + 2;
 		  // FIXME: respect the "Content-Length" header
-		  req.set_content (length - 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.m_fd, resp_str, strlen (resp_str));
-		  free (resp_str);
-		  //line_start += ;
-		  return;
-		  //break;
+		  set_content (length - line_start, buf + line_start);
+		  return line_start + get_content_length ();
 		}
 	      else
 		{
-		  parse_header (fd, i - line_start, buf + line_start);
+		  parse_header (i - line_start, buf + line_start);
 		  line_start = i + 2;
 		  break;
 		}
 	    }
 	}
     }
+
+  return line_start;
 }
 
+/* FIXME.  */
+
 void
-http::server::parse_header (file_descriptor fd, size_t length, const char *buf)
+http::request::parse_header (size_t length, const char *buf)
 {
   for (size_t colon_idx = 0; colon_idx + 1 < length; colon_idx++)
     if (buf[colon_idx] == ':' && buf[colon_idx + 1] == ' ')
       {
-#if 0
-	on_header (fd, colon_idx, buf,
-		   length - (colon_idx + 2), buf + colon_idx +2);
-#endif
+	char *key = xstrndup (buf, colon_idx);
+	char *value = xstrndup (buf + colon_idx + 2,
+				length - (colon_idx + 2));
+	m_header_map.put (key, value);
 	return;
       }
   // FIXME: error-handling
 }
 
-#if CHECKING_P
-
-namespace selftest {
+/* class http::response : public http::message.  */
 
-namespace {
+/* FIXME.  */
 
-class test_server : public http::server
+char *
+http::response::to_str () const
 {
- public:
-  test_server ()
-  : http::server (false), m_user_agent (NULL), m_content (NULL) {}
+  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));
+}
 
-  ~test_server () { free (m_user_agent); free (m_content); }
+/* FIXME.  */
 
-  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);
-#endif
-  }
+void
+http::server::on_read (file_descriptor fd, size_t length, const char *buf)
+{
+  if (m_verbose)
+    inform (UNKNOWN_LOCATION, "received http request: %qs",
+	    buf); // FIXME respect length
 
-  char *m_user_agent;
-  char *m_content;
-};
+  /* FIXME: this assumes we have a full request i.e. two "\r\n\r\n"
+     If we don't we should read more until we do.  */
+  size_t req_start = 0;
+  while (req_start < length)
+    {
+      request req;
+      req_start += req.parse_buffer (length, buf);
+      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.m_fd, resp_str, strlen (resp_str));
+      free (resp_str);
+    }
+}
 
-} // anonymous namespace
+#if CHECKING_P
+
+namespace selftest {
 
 /* Selftests.  */
 
+/* FIXME.  */
+
 static void
 test_parse_request ()
 {
@@ -160,15 +172,17 @@ test_parse_request ()
 		    "\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_STREQ ("test-user-agent", r.get_header ("User-Agent"));
+  ASSERT_STREQ ("12", r.get_header ("Content-Length"));
+  ASSERT_EQ (NULL, r.get_header ("Not-A-Header"));
   ASSERT_EQ (12, r.get_content_length ());
   ASSERT_TRUE (0 == strncmp ("test-content", r.get_content (), 12));
-#endif
 }
 
+/* Verify http::response::to_str.  */
+
 static void
 test_emit_response ()
 {
@@ -184,26 +198,6 @@ test_emit_response ()
   free (str);
 }
 
-static void
-test_http_server ()
-{
-  test_server s;
-  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");
-  s.on_read (file_descriptor (2), 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.  */
 
 void
@@ -211,7 +205,6 @@ http_server_c_tests ()
 {
   test_parse_request ();
   test_emit_response ();
-  test_http_server ();
 }
 
 } // namespace selftest
diff --git a/gcc/http-server.h b/gcc/http-server.h
index 4983a42..8a28ce8 100644
--- a/gcc/http-server.h
+++ b/gcc/http-server.h
@@ -43,7 +43,17 @@ class message
 class request : public message
 {
  public:
+  ~request();
+
+  const char *get_header (const char *header) const;
   size_t parse_buffer (size_t length, const char *buf);
+
+ private:
+  void parse_header (size_t sz, const char *buf);
+
+  typedef hash_map <char *, char *,
+    simple_hashmap_traits<nofree_string_hash, char *> > header_map_t;
+  header_map_t m_header_map;
 };
 
 class response : public message
@@ -68,9 +78,6 @@ class server : public ::server
 			   http::response &response) = 0;
 
  private:
-  void parse_header (file_descriptor fd, size_t sz, const char *buf);
-
- private:
   bool m_verbose;
 };
 
-- 
1.8.5.3

