Clean up. Return error also when we don't found key in query string.
[bertos.git] / bertos / net / http.c
index e3fc8085790e661dc556e571b068d76142426582..f15af4d7ab3190aa822c98eec25904111e8b3b97 100644 (file)
 #include <cfg/log.h>
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 
-static const char http_html_hdr_200[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
-static const char http_html_hdr_404[] = "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n";
-static const char http_html_hdr_500[] = "HTTP/1.1 500 Internal Server Error\r\nContent-type: text/html\r\n\r\n";
+static const char http_html_hdr_200[] = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n";
+static const char http_html_hdr_404[] = "HTTP/1.0 404 Not Found\r\nContent-type: text/html\r\n\r\n";
+static const char http_html_hdr_500[] = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\n\r\n";
 
 static HttpCGI *cgi_table;
 static http_handler_t http_callback;
+static char decoded_str[80];
 
 /**
- * Send on \param client socket
- * the 200 Ok http header
+ * Get key value from tokenized buffer
  */
-void http_sendOk(struct netconn *client)
+int http_getValue(char *tolenized_buf, size_t tolenized_buf_len, const char *key, char *value, size_t len)
 {
-       netconn_write(client, http_html_hdr_200, sizeof(http_html_hdr_200) - 1, NETCONN_NOCOPY);
-}
+       if (!tolenized_buf || !key || !value)
+               return -1;
+
+       char *p = tolenized_buf;
+       size_t value_len = 0;
+
+       memset(value, 0, len);
+
+       for (size_t i = 0; i < tolenized_buf_len; i++)
+       {
+               size_t token_len = strlen(p);
+               http_decodeUrl(p, token_len, decoded_str, sizeof(decoded_str));
+
+               if (!strcmp(key, decoded_str))
+               {
+                       /* skip key */
+                       p += token_len + 1;
 
+                       http_decodeUrl(p, strlen(p), decoded_str, sizeof(decoded_str));
+                       value_len = strlen(decoded_str);
+
+                       if (value_len >= len)
+                               return -1;
+
+                       strcpy(value, decoded_str);
+                       return value_len;
+               }
+               /* jump to next pair */
+               p += token_len + 1;
+       }
+
+       return -1;
+}
 
 /**
- * Send on \param client socket
- * the 404 File not found http header
+ * tokenize a buffer
  */
-void http_sendFileNotFound(struct netconn *client)
+int http_tokenizeGetRequest(char *raw_buf, size_t raw_len)
 {
-       netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY);
+       size_t token = 0;
+
+    for(size_t i = 0; (i < raw_len) && raw_buf; i++)
+       {
+               if (raw_buf[i] == '&')
+               {
+                       token++;
+                       raw_buf[i] = '\0';
+               }
+
+               if (raw_buf[i] == '=')
+                       raw_buf[i] = '\0';
+    }
+
+    return token + 1;
 }
 
-/**
- * Send on \param client socket
- * the 500 internal server error http header
- */
-void http_sendInternalErr(struct netconn *client)
+static char http_hexToAscii(char first, char second)
 {
-       netconn_write(client, http_html_hdr_500, sizeof(http_html_hdr_500) - 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_getPageName(const char *revc_buf, size_t recv_len, char *page_name, size_t len)
+void http_decodeUrl(const char *raw_buf, size_t raw_len, char *decodec_buf, size_t len)
 {
-       int i = 0;
-       bool str_ok = false;
+       ASSERT(decodec_buf);
 
-       if (revc_buf && (recv_len > sizeof("GET /")))
+       char value;
+       memset(decodec_buf, 0, len);
+
+       for (size_t i = 0; i < raw_len; i++)
        {
-               if (*revc_buf++ == 'G' &&
-                       *revc_buf++ == 'E' && *revc_buf++ == 'T')
+               if (!len)
+                       return;
+
+               if (raw_buf[i] == '%')
+               {
+                       if (i + 2 < raw_len)
                        {
-                               str_ok = true;
-                               revc_buf += 2;
+                               /* convert hex value after % */
+                               value = http_hexToAscii(raw_buf[i + 1], raw_buf[i + 2]);
+                               if (value)
+                               {
+                                       *decodec_buf++ = value;
+                                       len--;
+                                       /* decoded two digit of hex value, go to next value*/
+                                       i += 2;
+                                       continue;
+                               }
                        }
+               }
+
+               /* Manage special case of '+', that it should be convert in space */
+               *decodec_buf++ = (raw_buf[i] == '+' ? ' ' : raw_buf[i]);
+               len--;
+       }
+}
+
+void http_getPageName(const char *recv_buf, size_t recv_len, char *page_name, size_t len)
+{
+       int i = 0;
+       bool str_ok = false;
+       const char *p = recv_buf;
+       if (p && (recv_len > sizeof("GET /")))
+       {
+               if (*p++ == 'G' && *p++ == 'E' && *p++ == 'T')
+               {
+                       str_ok = true;
+                       /* skip the space and "/" */
+                       p += 2;
+               }
        }
 
        if (str_ok)
        {
                while ((size_t)i < recv_len)
                {
-                       char ch = *(revc_buf++);
+                       char ch = *(p++);
                        if (ch == ' ' || ch == '\t' || ch == '\n')
                                break;
                        if((size_t)i == len - 1)
@@ -133,6 +214,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)
@@ -140,7 +250,7 @@ static http_handler_t cgi_search(const char *name,  HttpCGI *table)
 
        int i = 0;
        const char *ext = get_ext(name);
-       LOG_INFO("EXT %s\n", ext);
+       LOG_INFO("EXT %s\n", ext ? "none" : ext);
        while(table[i].name)
        {
                if (ext && table[i].type == CGI_MATCH_EXT)
@@ -149,9 +259,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;
                }