http.c
Go to the documentation of this file.
00001
00045 #include "http.h"
00046
00047 #include "hw/hw_sd.h"
00048 #include "hw/hw_http.h"
00049
00050 #include "cfg/cfg_http.h"
00051
00052 // Define logging setting (for cfg/log.h module).
00053 #define LOG_LEVEL         HTTP_LOG_LEVEL
00054 #define LOG_VERBOSITY     HTTP_LOG_FORMAT
00055 #include <cfg/log.h>
00056
00057 #include <stdio.h>
00058 #include <stdlib.h>
00059 #include <string.h>
00060
00061 static struct { const char *key; const char *content; } http_content_type[] =
00062 {
00063     {"",    "Content-type: application/json\r\n\r\n"},
00064     {"htm", "Content-type: text/html\r\n\r\n"},
00065     {"css", "Content-type: text/css\r\n\r\n"},
00066     {"js",  "Content-type: text/javascript\r\n\r\n"},
00067     {"png", "Content-type: image/png\r\n\r\n"},
00068     {"jpg", "Content-type: image/jpeg\r\n\r\n"},
00069     {"gif", "Content-type: image/gif\r\n\r\n"},
00070     {"txt", "Content-type: text/plain\r\n\r\n"},
00071 };
00072
00073 static const char http_html_hdr_200[] = "HTTP/1.0 200 OK\r\n";
00074 static const char http_html_hdr_404[] = "HTTP/1.0 404 Not Found\r\n";
00075 static const char http_html_hdr_500[] = "HTTP/1.0 500 Internal Server Error\r\n";
00076
00077 static HttpCGI *cgi_table;
00078 static http_handler_t http_callback;
00079 static char decoded_str[80];
00080
00084 int http_getValue(char *tolenized_buf, size_t tolenized_buf_len, const char *key, char *value, size_t len)
00085 {
00086     if (!tolenized_buf || !key || !value)
00087         return -1;
00088
00089     char *p = tolenized_buf;
00090     size_t value_len = 0;
00091
00092     memset(value, 0, len);
00093
00094     for (size_t i = 0; i < tolenized_buf_len; i++)
00095     {
00096         size_t token_len = strlen(p);
00097         http_decodeUrl(p, token_len, decoded_str, sizeof(decoded_str));
00098
00099         if (!strcmp(key, decoded_str))
00100         {
00101             /* skip key */
00102             p += token_len + 1;
00103
00104             value_len = http_decodeUrl(p, strlen(p), decoded_str, sizeof(decoded_str));
00105
00106             if (value_len >= len)
00107                 return -1;
00108
00109             strcpy(value, decoded_str);
00110             return value_len;
00111         }
00112         /* jump to next pair */
00113         p += token_len + 1;
00114     }
00115
00116     return -1;
00117 }
00118
00122 int http_tokenizeGetRequest(char *raw_buf, size_t raw_len)
00123 {
00124     size_t token = 0;
00125
00126     for(size_t i = 0; (i < raw_len) && raw_buf; i++)
00127     {
00128         if (raw_buf[i] == '&')
00129         {
00130             token++;
00131             raw_buf[i] = '\0';
00132         }
00133
00134         if (raw_buf[i] == '=')
00135             raw_buf[i] = '\0';
00136     }
00137
00138     return token + 1;
00139 }
00140
00141 static char http_hexToAscii(char first, char second)
00142 {
00143     char hex[5], *stop;
00144     hex[0] = '0';
00145     hex[1] = 'x';
00146     hex[2] = first;
00147     hex[3] = second;
00148     hex[4] = 0;
00149     return strtol(hex, &stop, 16);
00150 }
00151
00152 size_t http_decodeUrl(const char *raw_buf, size_t raw_len, char *decodec_buf, size_t len)
00153 {
00154     ASSERT(decodec_buf);
00155
00156     char value;
00157     size_t i;
00158     memset(decodec_buf, 0, len);
00159
00160     for (i = 0; i < raw_len; i++)
00161     {
00162         if (len <= 1)
00163             return i;
00164
00165         if (raw_buf[i] == '%')
00166         {
00167             if (i + 2 < raw_len)
00168             {
00169                 /* convert hex value after % */
00170                 value = http_hexToAscii(raw_buf[i + 1], raw_buf[i + 2]);
00171                 if (value)
00172                 {
00173                     *decodec_buf++ = value;
00174                     len--;
00175                     /* decoded two digit of hex value, go to next value*/
00176                     i += 2;
00177                     continue;
00178                 }
00179             }
00180         }
00181
00182         /* Manage special case of '+', that it should be convert in space */
00183         *decodec_buf++ = (raw_buf[i] == '+' ? ' ' : raw_buf[i]);
00184         len--;
00185     }
00186
00187     return i;
00188 }
00189
00190 void http_getPageName(const char *recv_buf, size_t recv_len, char *page_name, size_t len)
00191 {
00192     int i = 0;
00193     bool str_ok = false;
00194     const char *p = recv_buf;
00195     if (p && (recv_len > sizeof("GET /")))
00196     {
00197         if (*p++ == 'G' && *p++ == 'E' && *p++ == 'T')
00198         {
00199             str_ok = true;
00200             /* skip the space and "/" */
00201             p += 2;
00202         }
00203     }
00204
00205     if (str_ok)
00206     {
00207         while ((size_t)i < recv_len)
00208         {
00209             char ch = *(p++);
00210             if (ch == ' ' || ch == '\t' || ch == '\n')
00211                 break;
00212             if((size_t)i == len - 1)
00213                 break;
00214             page_name[i++] = ch;
00215         }
00216     }
00217
00218     page_name[i] = '\0';
00219 }
00220
00221 INLINE const char *get_ext(const char *name)
00222 {
00223     const char *ext = strstr(name, ".");
00224     if(ext != NULL && ext[1] != '\0')
00225         return (ext + 1);
00226
00227     return NULL;
00228 }
00229
00230 int http_searchContentType(const char *name)
00231 {
00232     if (!name)
00233         return 0;
00234
00235     const char *ext = get_ext(name);
00236     LOG_INFO("Ext: %s\n", !ext ? "none" : ext);
00237
00238     if (!ext)
00239         return 0;
00240
00241     if (!strcmp(ext, "ico"))
00242         return HTTP_CONTENT_JPEG;
00243
00244     for (int i = 0; i < HTTP_CONTENT_CNT; i++)
00245     {
00246         if (!strcmp(ext, http_content_type[i].key))
00247             return i;
00248     }
00249
00250     return 0;
00251 }
00252
00253
00258 void http_sendOk(struct netconn *client, int content_type)
00259 {
00260     ASSERT(content_type < HTTP_CONTENT_CNT);
00261
00262     netconn_write(client, http_html_hdr_200, sizeof(http_html_hdr_200) - 1, NETCONN_NOCOPY);
00263     netconn_write(client, http_content_type[content_type].content,
00264             strlen(http_content_type[content_type].content), NETCONN_NOCOPY);
00265 }
00266
00267
00272 void http_sendFileNotFound(struct netconn *client, int content_type)
00273 {
00274     ASSERT(content_type < HTTP_CONTENT_CNT);
00275
00276     netconn_write(client, http_html_hdr_404, sizeof(http_html_hdr_404) - 1, NETCONN_NOCOPY);
00277     netconn_write(client, http_content_type[content_type].content,
00278             strlen(http_content_type[content_type].content), NETCONN_NOCOPY);
00279 }
00280
00285 void http_sendInternalErr(struct netconn *client, int content_type)
00286 {
00287     ASSERT(content_type < HTTP_CONTENT_CNT);
00288
00289     netconn_write(client, http_html_hdr_500, sizeof(http_html_hdr_500) - 1, NETCONN_NOCOPY);
00290     netconn_write(client, http_content_type[content_type].content,
00291             strlen(http_content_type[content_type].content), NETCONN_NOCOPY);
00292 }
00293
00294 static http_handler_t cgi_search(const char *name,  HttpCGI *table)
00295 {
00296     if (!table)
00297         return NULL;
00298
00299     int i = 0;
00300     const char *ext = get_ext(name);
00301
00302     while(table[i].name)
00303     {
00304         if (ext && table[i].type == CGI_MATCH_EXT)
00305         {
00306
00307             if (!strcmp(table[i].name, ext))
00308             {
00309                 LOG_INFO("Match ext: %s\n", ext);
00310                 break;
00311             }
00312         }
00313         else if (table[i].type == CGI_MATCH_NAME)
00314         {
00315
00316             if (strstr(name, table[i].name) != NULL)
00317             {
00318                 LOG_INFO("Match string: %s\n", name);
00319                 break;
00320             }
00321         }
00322         else /* (table[i].type == CGI_MATCH_WORD) */
00323         {
00324
00325             if (!strcmp(table[i].name, name))
00326             {
00327                 LOG_INFO("Word match: %s\n", name);
00328                 break;
00329             }
00330         }
00331
00332         i++;
00333     }
00334
00335     return table[i].handler;
00336 }
00337
00338 static char req_string[80];
00339
00346 void http_poll(struct netconn *server)
00347 {
00348     struct netconn *client;
00349     struct netbuf *rx_buf_conn;
00350     char *rx_buf;
00351     uint16_t len;
00352
00353     client = netconn_accept(server);
00354     if (!client)
00355         return;
00356
00357     rx_buf_conn = netconn_recv(client);
00358     if (rx_buf_conn)
00359     {
00360         netbuf_data(rx_buf_conn, (void **)&rx_buf, &len);
00361         if (rx_buf)
00362         {
00363             memset(req_string, 0, sizeof(req_string));
00364             http_getPageName(rx_buf, len, req_string, sizeof(req_string));
00365
00366             if (req_string[0] == '\0')
00367                 strcpy(req_string, HTTP_DEFAULT_PAGE);
00368
00369             http_handler_t cgi = cgi_search(req_string, cgi_table);
00370             if (cgi)
00371             {
00372                 if (cgi(client, req_string, rx_buf, len) < 0)
00373                 {
00374                     LOG_ERR("Internal server error\n");
00375                     http_sendInternalErr(client, HTTP_CONTENT_HTML);
00376                     netconn_write(client, http_server_error, http_server_error_len - 1, NETCONN_NOCOPY);
00377                 }
00378             }
00379             else
00380             {
00381                 http_callback(client, req_string, rx_buf, len);
00382             }
00383         }
00384         netconn_close(client);
00385         netbuf_delete(rx_buf_conn);
00386     }
00387     netconn_delete(client);
00388 }
00389
00402 void http_init(http_handler_t default_callback, struct HttpCGI *table)
00403 {
00404     ASSERT(default_callback);
00405
00406     cgi_table = table;
00407     http_callback = default_callback;
00408 }
00409