Refactor to use new protocol module and sipo.
[bertos.git] / bertos / net / http.c
index 05d8e1b2bb6072a60dda060e4e1cdd0f5878e926..29146d405161d2f379298451a5fb6aeb9995ff52 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-
-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 struct {        const char *key; const char *content; } http_content_type[] =
+{
+       {"",    "Content-type: application/json\r\n\r\n"},
+       {"htm", "Content-type: text/html\r\n\r\n"},
+       {"css", "Content-type: text/css\r\n\r\n"},
+       {"js",  "Content-type: text/javascript\r\n\r\n"},
+       {"png", "Content-type: image/png\r\n\r\n"},
+       {"jpg", "Content-type: image/jpeg\r\n\r\n"},
+       {"gif", "Content-type: image/gif\r\n\r\n"},
+       {"txt", "Content-type: text/plain\r\n\r\n"},
+};
+
+static const char http_html_hdr_200[] = "HTTP/1.0 200 OK\r\n";
+static const char http_html_hdr_404[] = "HTTP/1.0 404 Not Found\r\n";
+static const char http_html_hdr_500[] = "HTTP/1.0 500 Internal Server Error\r\n";
 
 static HttpCGI *cgi_table;
 static http_handler_t http_callback;
+static char decoded_str[80];
 
 /**
  * Get key value from tokenized buffer
@@ -81,24 +93,27 @@ int http_getValue(char *tolenized_buf, size_t tolenized_buf_len, const char *key
 
        for (size_t i = 0; i < tolenized_buf_len; i++)
        {
-               if (!strcmp(key, p))
+               size_t token_len = strlen(p);
+               http_decodeUrl(p, token_len, decoded_str, sizeof(decoded_str));
+
+               if (!strcmp(key, decoded_str))
                {
                        /* skip key */
-                       size_t jump = strlen(p) + 1;
-                       p += jump;
+                       p += token_len + 1;
+
+                       value_len = http_decodeUrl(p, strlen(p), decoded_str, sizeof(decoded_str));
 
-                       value_len = strlen(p);
                        if (value_len >= len)
                                return -1;
 
-                       strcpy(value, p);
-                       break;
+                       strcpy(value, decoded_str);
+                       return value_len;
                }
                /* jump to next pair */
-               p += strlen(p) + 1;
+               p += token_len + 1;
        }
 
-       return value_len;
+       return -1;
 }
 
 /**
@@ -134,13 +149,18 @@ static char http_hexToAscii(char first, char second)
        return strtol(hex, &stop, 16);
 }
 
-void http_decodeUri(const char *raw_buf, size_t raw_len, char *decodec_buf, size_t len)
+size_t http_decodeUrl(const char *raw_buf, size_t raw_len, char *decodec_buf, size_t len)
 {
+       ASSERT(decodec_buf);
+
        char value;
-       for (size_t i = 0; i < raw_len; i++)
+       size_t i;
+       memset(decodec_buf, 0, len);
+
+       for (i = 0; i < raw_len; i++)
        {
-               if (!len)
-                       return;
+               if (len <= 1)
+                       return i;
 
                if (raw_buf[i] == '%')
                {
@@ -152,14 +172,19 @@ void http_decodeUri(const char *raw_buf, size_t raw_len, char *decodec_buf, size
                                {
                                        *decodec_buf++ = value;
                                        len--;
+                                       /* decoded two digit of hex value, go to next value*/
                                        i += 2;
                                        continue;
                                }
                        }
                }
-               *decodec_buf++ = raw_buf[i];
+
+               /* Manage special case of '+', that it should be convert in space */
+               *decodec_buf++ = (raw_buf[i] == '+' ? ' ' : raw_buf[i]);
                len--;
        }
+
+       return i;
 }
 
 void http_getPageName(const char *recv_buf, size_t recv_len, char *page_name, size_t len)
@@ -169,13 +194,12 @@ void http_getPageName(const char *recv_buf, size_t recv_len, char *page_name, si
        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 (*p++ == 'G' && *p++ == 'E' && *p++ == 'T')
+               {
+                       str_ok = true;
+                       /* skip the space and "/" */
+                       p += 2;
+               }
        }
 
        if (str_ok)
@@ -197,39 +221,74 @@ void http_getPageName(const char *recv_buf, size_t recv_len, char *page_name, si
 INLINE const char *get_ext(const char *name)
 {
        const char *ext = strstr(name, ".");
-       if(ext && (ext + 1))
+       if(ext != NULL && ext[1] != '\0')
                return (ext + 1);
 
        return NULL;
 }
 
+int http_searchContentType(const char *name)
+{
+       if (!name)
+               return 0;
+
+       const char *ext = get_ext(name);
+       LOG_INFO("Ext: %s\n", !ext ? "none" : ext);
+
+       if (!ext)
+               return 0;
+
+       if (!strcmp(ext, "ico"))
+               return HTTP_CONTENT_JPEG;
+
+       for (int i = 0; i < HTTP_CONTENT_CNT; i++)
+       {
+               if (!strcmp(ext, http_content_type[i].key))
+                       return i;
+       }
+
+       return 0;
+}
+
 
 /**
- * Send on \param client socket
- * the 200 Ok http header
+ * Send on \param client socket the 200 Ok http header with
+ * select \param content_type
  */
-void http_sendOk(struct netconn *client)
+void http_sendOk(struct netconn *client, int content_type)
 {
+       ASSERT(content_type < HTTP_CONTENT_CNT);
+
        netconn_write(client, http_html_hdr_200, sizeof(http_html_hdr_200) - 1, NETCONN_NOCOPY);
+       netconn_write(client, http_content_type[content_type].content,
+                       strlen(http_content_type[content_type].content), NETCONN_NOCOPY);
 }
 
 
 /**
- * Send on \param client socket
- * the 404 File not found http header
+ * Send on \param client socket the 404 File not found http header with
+ * select \param content_type
  */
-void http_sendFileNotFound(struct netconn *client)
+void http_sendFileNotFound(struct netconn *client, int content_type)
 {
+       ASSERT(content_type < HTTP_CONTENT_CNT);
+
        netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY);
+       netconn_write(client, http_content_type[content_type].content,
+                       strlen(http_content_type[content_type].content), NETCONN_NOCOPY);
 }
 
 /**
- * Send on \param client socket
- * the 500 internal server error http header
+ * Send on \param client socket the 500 internal server error http header with
+ * select \param content_type
  */
-void http_sendInternalErr(struct netconn *client)
+void http_sendInternalErr(struct netconn *client, int content_type)
 {
+       ASSERT(content_type < HTTP_CONTENT_CNT);
+
        netconn_write(client, http_html_hdr_500, sizeof(http_html_hdr_500) - 1, NETCONN_NOCOPY);
+       netconn_write(client, http_content_type[content_type].content,
+                       strlen(http_content_type[content_type].content), NETCONN_NOCOPY);
 }
 
 static http_handler_t cgi_search(const char *name,  HttpCGI *table)
@@ -239,26 +298,35 @@ 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);
+
        while(table[i].name)
        {
                if (ext && table[i].type == CGI_MATCH_EXT)
                {
-                       LOG_INFO("Match all ext %s\n", ext);
+
                        if (!strcmp(table[i].name, ext))
+                       {
+                               LOG_INFO("Match ext: %s\n", ext);
                                break;
+                       }
                }
                else if (table[i].type == CGI_MATCH_NAME)
                {
-                       LOG_INFO("Match all name %s\n", name);
+
                        if (strstr(name, table[i].name) != NULL)
+                       {
+                               LOG_INFO("Match string: %s\n", name);
                                break;
+                       }
                }
                else /* (table[i].type == CGI_MATCH_WORD) */
                {
-                       LOG_INFO("Match all word %s\n", name);
+
                        if (!strcmp(table[i].name, name))
+                       {
+                               LOG_INFO("Word match: %s\n", name);
                                break;
+                       }
                }
 
                i++;
@@ -295,7 +363,6 @@ void http_poll(struct netconn *server)
                        memset(req_string, 0, 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')
                                strcpy(req_string, HTTP_DEFAULT_PAGE);
 
@@ -305,7 +372,7 @@ void http_poll(struct netconn *server)
                                if (cgi(client, req_string, rx_buf, len) < 0)
                                {
                                        LOG_ERR("Internal server error\n");
-                                       http_sendInternalErr(client);
+                                       http_sendInternalErr(client, HTTP_CONTENT_HTML);
                                        netconn_write(client, http_server_error, http_server_error_len - 1, NETCONN_NOCOPY);
                                }
                        }