Do not test for avr family.
[bertos.git] / bertos / net / http.c
index bd8f3946379886f0393759710ab5ff6623b9de21..f994079b0faf324cb4ccedb2e2cb429f6dcedbd7 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"
 #define LOG_VERBOSITY     HTTP_LOG_FORMAT
 #include <cfg/log.h>
 
-#include <drv/sd.h>
-
-#include <fs/fat.h>
-
 #include <stdio.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 HttpCGI *cgi_table;
+static http_handler_t http_callback;
+
+/**
+ * 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 void get_fileName(const char *revc_buf, size_t recv_len, char *name, size_t len)
 {
@@ -80,7 +99,7 @@ static void get_fileName(const char *revc_buf, size_t recv_len, char *name, size
        char *p = strstr(revc_buf, "GET");
        if (p)
        {
-               //Find the end of the page request.
+               /* Find the end of the page request. */
                char *stop = strstr(revc_buf, "HTTP");
                if (!stop)
                {
@@ -89,7 +108,7 @@ static void get_fileName(const char *revc_buf, size_t recv_len, char *name, size
                        return;
                }
 
-               //skip the "/" in get string request
+               /* skip the "/" in get string request */
                p += sizeof("GET") + 1;
 
                while (p != stop)
@@ -104,7 +123,7 @@ static void get_fileName(const char *revc_buf, size_t recv_len, char *name, size
                }
        }
 
-       //Trail white space in the string.
+       /* Trail white space in the string. */
        while ( --i >= 0 )
                if (name[i] != ' ' && name[i] != '\t' && name[i] != '\n')
                        break;
@@ -112,30 +131,58 @@ static void get_fileName(const char *revc_buf, size_t recv_len, char *name, size
        name[i + 1] = '\0';
 }
 
-static http_gci_handler_t cgi_search(const char *name,  HttpCGI *table)
+INLINE const char *get_ext(const char *name)
+{
+       const char *ext = strstr(name, ".");
+       if(ext && (ext + 1))
+               return (ext + 1);
+
+       return NULL;
+}
+
+static http_handler_t cgi_search(const char *name,  HttpCGI *table)
 {
-       for (int i = 0; table[i].name; i++)
+       if (!table)
+               return NULL;
+
+       int i = 0;
+       const char *ext = get_ext(name);
+       LOG_INFO("EXT %s\n", ext);
+       while(table[i].name)
        {
-               if (!strcmp(table[i].name, name))
-                       return table[i].handler;
+               if (ext && table[i].type == CGI_MATCH_EXT)
+               {
+                       LOG_INFO("Match all ext %s\n", ext);
+                       if (!strcmp(table[i].name, ext))
+                               break;
+               }
+               else /* (table[i].type == CGI_MATCH_NAME) */
+               {
+                       LOG_INFO("Match all name %s\n", name);
+                       if (!strcmp(table[i].name, name))
+                               break;
+               }
+
+               i++;
        }
-       return NULL;
+
+       return table[i].handler;
 }
 
-static uint8_t tx_buf[2048];
-static char file_name[80];
+static char req_string[80];
 
-void http_server(struct netconn *server, struct HttpCGI *table)
+/**
+ * Http polling function.
+ *
+ * Call this functions to process each client connections.
+ *
+ */
+void http_poll(struct netconn *server)
 {
-       // SD fat filesystem context
-       Sd sd;
-       FATFS fs;
-       FatFile in_file;
        struct netconn *client;
        struct netbuf *rx_buf_conn;
        char *rx_buf;
-       u16_t len;
-       FRESULT result;
+       uint16_t len;
 
        client = netconn_accept(server);
        if (!client)
@@ -145,73 +192,28 @@ void http_server(struct netconn *server, struct HttpCGI *table)
        if (rx_buf_conn)
        {
                netbuf_data(rx_buf_conn, (void **)&rx_buf, &len);
-
                if (rx_buf)
                {
-                       memset(file_name, 0, sizeof(file_name));
-                       get_fileName(rx_buf, len, file_name, sizeof(file_name));
+                       memset(req_string, 0, sizeof(req_string));
+                       get_fileName(rx_buf, len, req_string, sizeof(req_string));
 
-                       LOG_INFO("Search %s\n", file_name);
-                       if (file_name[0] == '\0')
-                               strcpy(file_name, HTTP_DEFAULT_PAGE);
+                       LOG_INFO("Search %s\n", req_string);
+                       if (req_string[0] == '\0')
+                               strcpy(req_string, HTTP_DEFAULT_PAGE);
 
-                       http_gci_handler_t cgi = cgi_search(file_name,  table);
+                       http_handler_t cgi = cgi_search(req_string, cgi_table);
                        if (cgi)
                        {
-                               cgi(client, rx_buf, len);
-                       }
-                       else if (SD_CARD_PRESENT())
-                       {
-                               bool sd_ok = sd_init(&sd, NULL, 0);
-                               if (sd_ok)
+                               if (cgi(client, req_string, rx_buf, len) < 0)
                                {
-                                       LOG_INFO("Mount FAT filesystem.\n");
-                                       result = f_mount(0, &fs);
-                                       if (result != FR_OK)
-                                       {
-                                               LOG_ERR("Mounting FAT volumes error[%d]\n", result);
-                                               sd_ok = false;
-                                               f_mount(0, NULL);
-                                       }
-
-                                       if (sd_ok)
-                                       {
-                                               result = fatfile_open(&in_file, file_name,  FA_OPEN_EXISTING | FA_READ);
-
-                                               size_t count = 0;
-                                               if (result == FR_OK)
-                                               {
-                                                       LOG_INFO("Opened file '%s' size %ld\n", file_name, in_file.fat_file.fsize);
-
-                                                       http_sendOk(client);
-
-                                                       while (count < in_file.fat_file.fsize)
-                                                       {
-                                                               int len = kfile_read(&in_file.fd, tx_buf, sizeof(tx_buf));
-                                                               netconn_write(client, tx_buf, len, NETCONN_COPY);
-                                                               count += len;
-                                                       }
-
-                                                       kfile_flush(&in_file.fd);
-                                                       kfile_close(&in_file.fd);
-
-                                                       LOG_INFO("Sent: %d\n", count);
-                                               }
-                                               else
-                                               {
-                                                       LOG_ERR("Unable to open file: '%s' error[%d]\n",  file_name, result);
-                                                       http_sendFileNotFound(client);
-                                                       netconn_write(client, http_file_not_found, http_file_not_found_len - 1, NETCONN_NOCOPY);
-                                               }
-                                       }
+                                       LOG_ERR("Internal server error\n");
+                                       http_sendInternalErr(client);
+                                       netconn_write(client, http_server_error, http_server_error_len - 1, NETCONN_NOCOPY);
                                }
-                               f_mount(0, NULL);
-                               LOG_INFO("Umount FAT filesystem.\n");
                        }
                        else
                        {
-                               http_sendFileNotFound(client);
-                               netconn_write(client, http_sd_not_present, http_sd_not_present_len, NETCONN_NOCOPY);
+                               http_callback(client, req_string, rx_buf, len);
                        }
                }
                netconn_close(client);
@@ -219,3 +221,24 @@ void http_server(struct netconn *server, struct HttpCGI *table)
        }
        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);
+
+       cgi_table = table;
+       http_callback = default_callback;
+}
+