Check if the return buffer is biggest enough.
[bertos.git] / bertos / net / http.c
index 7967bb30f34a323f41303126d79174bbaf5d2f24..dd4ee4fd22ffdcdda57f3efba7174f47b39c06d5 100644 (file)
@@ -38,6 +38,8 @@
  * the cases where SD is not present or page not found, using embedded pages.
  * Quering from browser the /status page, the server return a json dictionary where are store
  * some board status info, like board temperature, up-time, etc.
+ *
+ * notest: avr
  */
 
 #include "http.h"
@@ -53,6 +55,7 @@
 #include <cfg/log.h>
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 
@@ -64,57 +67,75 @@ static HttpCGI *cgi_table;
 static http_handler_t http_callback;
 
 
-void http_sendOk(struct netconn *client)
+static char http_hexToAscii(char first, char second)
 {
-       netconn_write(client, http_html_hdr_200, sizeof(http_html_hdr_200) - 1, NETCONN_NOCOPY);
+       char hex[5], *stop;
+       hex[0] = '0';
+       hex[1] = 'x';
+       hex[2] = first;
+       hex[3] = second;
+       hex[4] = 0;
+       return strtol(hex, &stop, 16);
 }
 
-void http_sendFileNotFound(struct netconn *client)
+void http_decodeUri(const char *raw_buf, size_t raw_len, char *decodec_buf, size_t len)
 {
-       netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY);
-}
+       char value;
+       for (size_t i = 0; i < raw_len; i++)
+       {
+               if (!len)
+                       return;
 
-void http_sendInternalErr(struct netconn *client)
-{
-       netconn_write(client, http_html_hdr_500, sizeof(http_html_hdr_500) - 1, NETCONN_NOCOPY);
+               if (raw_buf[i] == '%')
+               {
+                       if (i + 2 < raw_len)
+                       {
+                               /* convert hex value after % */
+                               value = http_hexToAscii(raw_buf[i + 1], raw_buf[i + 2]);
+                               if (value)
+                               {
+                                       *decodec_buf++ = value;
+                                       len--;
+                                       i += 2;
+                                       continue;
+                               }
+                       }
+               }
+               *decodec_buf++ = raw_buf[i];
+               len--;
+       }
 }
 
-static void get_fileName(const char *revc_buf, size_t recv_len, char *name, size_t len)
+void http_getPageName(const char *recv_buf, size_t recv_len, char *page_name, size_t len)
 {
        int i = 0;
-       char *p = strstr(revc_buf, "GET");
-       if (p)
-       {
-               //Find the end of the page request.
-               char *stop = strstr(revc_buf, "HTTP");
-               if (!stop)
-               {
-                       LOG_ERR("Bad GET request\n");
-                       name[0] = '\0';
-                       return;
-               }
-
-               //skip the "/" in get string request
-               p += sizeof("GET") + 1;
+       bool str_ok = false;
 
-               while (p != stop)
-               {
-                       if ((size_t)i == len || (size_t)i >= recv_len)
+       if (recv_buf && (recv_len > sizeof("GET /")))
+       {
+               if (*recv_buf++ == 'G' &&
+                       *recv_buf++ == 'E' && *recv_buf++ == 'T')
                        {
-                               name[i] = '\0';
-                               break;
+                               str_ok = true;
+                               /* skip the space and "/" */
+                               recv_buf += 2;
                        }
+       }
 
-                       name[i++] = *(p++);
+       if (str_ok)
+       {
+               while ((size_t)i < recv_len)
+               {
+                       char ch = *(recv_buf++);
+                       if (ch == ' ' || ch == '\t' || ch == '\n')
+                               break;
+                       if((size_t)i == len - 1)
+                               break;
+                       page_name[i++] = ch;
                }
        }
 
-       //Trail white space in the string.
-       while ( --i >= 0 )
-               if (name[i] != ' ' && name[i] != '\t' && name[i] != '\n')
-                       break;
-
-       name[i + 1] = '\0';
+       page_name[i] = '\0';
 }
 
 INLINE const char *get_ext(const char *name)
@@ -126,6 +147,35 @@ INLINE const char *get_ext(const char *name)
        return NULL;
 }
 
+
+/**
+ * Send on \param client socket
+ * the 200 Ok http header
+ */
+void http_sendOk(struct netconn *client)
+{
+       netconn_write(client, http_html_hdr_200, sizeof(http_html_hdr_200) - 1, NETCONN_NOCOPY);
+}
+
+
+/**
+ * Send on \param client socket
+ * the 404 File not found http header
+ */
+void http_sendFileNotFound(struct netconn *client)
+{
+       netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY);
+}
+
+/**
+ * Send on \param client socket
+ * the 500 internal server error http header
+ */
+void http_sendInternalErr(struct netconn *client)
+{
+       netconn_write(client, http_html_hdr_500, sizeof(http_html_hdr_500) - 1, NETCONN_NOCOPY);
+}
+
 static http_handler_t cgi_search(const char *name,  HttpCGI *table)
 {
        if (!table)
@@ -142,9 +192,15 @@ static http_handler_t cgi_search(const char *name,  HttpCGI *table)
                        if (!strcmp(table[i].name, ext))
                                break;
                }
-               else /* (table[i].type == CGI_MATCH_NAME) */
+               else if (table[i].type == CGI_MATCH_NAME)
                {
                        LOG_INFO("Match all name %s\n", name);
+                       if (strstr(name, table[i].name) != NULL)
+                               break;
+               }
+               else /* (table[i].type == CGI_MATCH_WORD) */
+               {
+                       LOG_INFO("Match all word %s\n", name);
                        if (!strcmp(table[i].name, name))
                                break;
                }
@@ -157,6 +213,12 @@ static http_handler_t cgi_search(const char *name,  HttpCGI *table)
 
 static char req_string[80];
 
+/**
+ * Http polling function.
+ *
+ * Call this functions to process each client connections.
+ *
+ */
 void http_poll(struct netconn *server)
 {
        struct netconn *client;
@@ -175,7 +237,7 @@ void http_poll(struct netconn *server)
                if (rx_buf)
                {
                        memset(req_string, 0, sizeof(req_string));
-                       get_fileName(rx_buf, len, req_string, sizeof(req_string));
+                       http_getPageName(rx_buf, len, req_string, sizeof(req_string));
 
                        LOG_INFO("Search %s\n", req_string);
                        if (req_string[0] == '\0')
@@ -202,6 +264,18 @@ void http_poll(struct netconn *server)
        netconn_delete(client);
 }
 
+/**
+ * Init the http server.
+ *
+ * The simply http server call for each client request the default_callback function. The
+ * user should define this callback to manage the client request, i.e. reading site's page
+ * from SD card. The user can define the cgi_table, where associate one callback to the user string.
+ * In this way the user could filter some client request and redirect they to custom callback, i.e.
+ * the client could request status of the device only loading the particular page name.
+ *
+ * \param default_callback fuction that server call for all request, that does'nt match cgi table.
+ * \param table of callcack to call when client request a particular page.
+ */
 void http_init(http_handler_t default_callback, struct HttpCGI *table)
 {
        ASSERT(default_callback);