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
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)