olsrd: jsoninfo: HTTP headers with CORS (if requested)
authorSaverio Proto <zioproto@gmail.com>
Sat, 17 May 2014 17:10:12 +0000 (19:10 +0200)
committerSaverio Proto <zioproto@gmail.com>
Sat, 17 May 2014 17:10:12 +0000 (19:10 +0200)
olsrd/patches/004-jsonplugin-http-headers.patch [new file with mode: 0644]

diff --git a/olsrd/patches/004-jsonplugin-http-headers.patch b/olsrd/patches/004-jsonplugin-http-headers.patch
new file mode 100644 (file)
index 0000000..cd76006
--- /dev/null
@@ -0,0 +1,211 @@
+commit b342385531c18b8afb42db64c7a38d7879668566
+Author: Alessio Caiazza <nolith@abisso.org>
+Date:   Fri May 16 12:53:15 2014 +0200
+
+    jsoninfo: HTTP headers with CORS (if requested)
+    
+    The new "httpheaders" parameter prepends HTTP headers to the reply.
+    If not set it will default to "no" and have the same behaviour as before.
+    Cross-origin resource sharing headers (CORS) are included in reply allowing the
+    json retrieval by javascript applications not served by olsrd itself.
+    This will allow to easily develop js applications running directly in the
+    browser.
+    
+    Reviewed-by: Ferry Huberts <ferry.huberts@pelagic.nl>
+
+diff --git a/lib/jsoninfo/README_JSONINFO b/lib/jsoninfo/README_JSONINFO
+index 709c975..8311ade 100644
+--- a/lib/jsoninfo/README_JSONINFO
++++ b/lib/jsoninfo/README_JSONINFO
+@@ -73,6 +73,14 @@ LoadPlugin "olsrd_jsoninfo.so.0.0"
+     # if you set it to 0.0.0.0, it will accept all connections
+     #PlParam      "accept" "0.0.0.0"
++    # The "httpheaders" parameter prepends HTTP headers to the reply.
++    # If not set it will default to "no" and have the same behaviour as before.
++    # Among with a minimal set of headers also Cross-origin resource sharing
++    # headers (CORS) are included in reply allowing the json retrieval by
++    # javascript applications not served by olsrd itself.
++    # You can enable it uncommenting the following line:
++    #PlParam      "httpheaders" "yes"
++
+     # specify a UUID for this node to track it for debugging
+     #PlParam      "UUIDFile" "/etc/olsrd/olsrd.uuid"
+ }
+diff --git a/lib/jsoninfo/src/olsrd_jsoninfo.c b/lib/jsoninfo/src/olsrd_jsoninfo.c
+index 817c64a..f29a37c 100644
+--- a/lib/jsoninfo/src/olsrd_jsoninfo.c
++++ b/lib/jsoninfo/src/olsrd_jsoninfo.c
+@@ -96,6 +96,9 @@
+ static int ipc_socket;
++/* Response types */
++#define HTTP_200 "HTTP/1.1 200 OK"
++
+ /* IPC initialization function */
+ static int plugin_ipc_init(void);
+@@ -126,6 +129,18 @@ static void ipc_print_interfaces(struct autobuf *);
+ static void ipc_print_plugins(struct autobuf *);
+ static void ipc_print_olsrd_conf(struct autobuf *abuf);
++static size_t build_http_header(const char *status, const char *mime,
++  uint32_t msgsize, char *buf, uint32_t bufsize);
++
++/*
++ * this is the size of the buffer used for build_http_header
++ * the amount of data written into the buffer will be less than
++ * 400 bytes approximatively.
++ * The size may vary because the Content-Length header contains
++ * the length of the json data
++ */
++#define MAX_HTTPHEADER_SIZE 512
++
+ #define TXT_IPC_BUFSIZE 256
+ /* these provide all of the runtime status info */
+@@ -1282,6 +1297,9 @@ static void
+ send_info(unsigned int send_what, int the_socket)
+ {
+   struct autobuf abuf;
++  size_t header_len = 0;
++  char header_buf[MAX_HTTPHEADER_SIZE];
++  const char *content_type = "application/json";
+   /* global variables for tracking when to put a comma in for JSON */
+   entrynumber[0] = 0;
+@@ -1320,12 +1338,17 @@ send_info(unsigned int send_what, int the_socket)
+     ipc_print_olsrd_conf(&abuf);
+   }
+-  outbuffer[outbuffer_count] = olsr_malloc(abuf.len, "txt output buffer");
+-  outbuffer_size[outbuffer_count] = abuf.len;
++  if(http_headers) {
++    header_len = build_http_header(HTTP_200, content_type, abuf.len, header_buf, sizeof(header_buf));
++  }
++
++  outbuffer[outbuffer_count] = olsr_malloc(header_len + abuf.len, "json output buffer");
++  outbuffer_size[outbuffer_count] = header_len + abuf.len;
+   outbuffer_written[outbuffer_count] = 0;
+   outbuffer_socket[outbuffer_count] = the_socket;
+-  memcpy(outbuffer[outbuffer_count], abuf.buf, abuf.len);
++  memcpy(outbuffer[outbuffer_count], header_buf, header_len);
++  memcpy((outbuffer[outbuffer_count]) + header_len, abuf.buf, abuf.len);
+   outbuffer_count++;
+   if (outbuffer_count == 1) {
+@@ -1340,6 +1363,53 @@ send_info(unsigned int send_what, int the_socket)
+   abuf_free(&abuf);
+ }
++static size_t
++build_http_header(const char *status, const char *mime, uint32_t msgsize,
++  char *buf, uint32_t bufsize)
++{
++  time_t currtime;
++  size_t size;
++
++  size = snprintf(buf, bufsize, "%s\r\n", status);
++
++  /* Date */
++  time(&currtime);
++  size += strftime(&buf[size], bufsize - size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
++
++  /* Server version */
++  size += snprintf(&buf[size], bufsize - size, "Server: OLSRD JSONInfo plugin\r\n");
++
++  /* connection-type */
++  size += snprintf(&buf[size], bufsize - size, "Connection: closed\r\n");
++
++  /* MIME type */
++  if(mime != NULL) {
++    size += snprintf(&buf[size], bufsize - size, "Content-type: %s\r\n", mime);
++  }
++
++  /* CORS data */
++  /**No needs to be strict here, access control is based on source IP*/
++  size += snprintf(&buf[size], bufsize - size, "Access-Control-Allow-Origin: *\r\n");
++  size += snprintf(&buf[size], bufsize - size, "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n");
++  size += snprintf(&buf[size], bufsize - size, "Access-Control-Allow-Headers: Accept, Origin, X-Requested-With\r\n");
++  size += snprintf(&buf[size], bufsize - size, "Access-Control-Max-Age: 1728000\r\n");
++
++  /* Content length */
++  if (msgsize > 0) {
++    size += snprintf(&buf[size], bufsize - size, "Content-length: %i\r\n", msgsize);
++  }
++
++  /* Cache-control
++   * No caching dynamic pages
++   */
++  size += snprintf(&buf[size], bufsize - size, "Cache-Control: no-cache\r\n");
++
++  /* End header */
++  size += snprintf(&buf[size], bufsize - size, "\r\n");
++
++  return size;
++}
++
+ /*
+  * Local Variables:
+  * mode: c
+diff --git a/lib/jsoninfo/src/olsrd_jsoninfo.h b/lib/jsoninfo/src/olsrd_jsoninfo.h
+index 8478f62..56acb70 100644
+--- a/lib/jsoninfo/src/olsrd_jsoninfo.h
++++ b/lib/jsoninfo/src/olsrd_jsoninfo.h
+@@ -62,6 +62,7 @@ extern union olsr_ip_addr jsoninfo_accept_ip;
+ extern union olsr_ip_addr jsoninfo_listen_ip;
+ extern int ipc_port;
+ extern int nompr;
++extern bool http_headers;
+ int olsrd_plugin_interface_version(void);
+ int olsrd_plugin_init(void);
+diff --git a/lib/jsoninfo/src/olsrd_plugin.c b/lib/jsoninfo/src/olsrd_plugin.c
+index 36550a8..03aa45f 100644
+--- a/lib/jsoninfo/src/olsrd_plugin.c
++++ b/lib/jsoninfo/src/olsrd_plugin.c
+@@ -64,6 +64,7 @@ union olsr_ip_addr jsoninfo_accept_ip;
+ union olsr_ip_addr jsoninfo_listen_ip;
+ int ipc_port;
+ int nompr;
++bool http_headers;
+ static void my_init(void) __attribute__ ((constructor));
+ static void my_fini(void) __attribute__ ((destructor));
+@@ -79,6 +80,7 @@ my_init(void)
+   /* defaults for parameters */
+   ipc_port = 9090;
++  http_headers = false;
+   if (olsr_cnf->ip_version == AF_INET) {
+     jsoninfo_accept_ip.v4.s_addr = htonl(INADDR_LOOPBACK);
+     jsoninfo_listen_ip.v4.s_addr = htonl(INADDR_ANY);
+@@ -120,11 +122,26 @@ store_string(const char *value, void *data, set_plugin_parameter_addon addon __a
+   return 0;
+ }
++static int
++store_boolean(const char *value, void *data, set_plugin_parameter_addon addon __attribute__ ((unused)))
++{
++  bool *dest = data;
++  if(strcmp(value, "yes") == 0)
++    *dest = true;
++  else if (strcmp(value, "no") == 0)
++    *dest = false;
++  else
++    return 1; //error
++
++  return 0;
++}
++
+ static const struct olsrd_plugin_parameters plugin_parameters[] = {
+   {.name = "port",.set_plugin_parameter = &set_plugin_port,.data = &ipc_port},
+   {.name = "accept",.set_plugin_parameter = &set_plugin_ipaddress,.data = &jsoninfo_accept_ip},
+   {.name = "listen",.set_plugin_parameter = &set_plugin_ipaddress,.data = &jsoninfo_listen_ip},
+   {.name = "uuidfile",.set_plugin_parameter = &store_string,.data = uuidfile},
++  {.name = "httpheaders",.set_plugin_parameter = &store_boolean,.data = &http_headers},
+ };
+ void