6 #include "http-server.h"
10 #if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
11 #include "static-routing.h"
17 #define PRINTF(...) printf(__VA_ARGS__)
18 #define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
19 #define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
22 #define PRINT6ADDR(addr)
23 #define PRINTLLADDR(addr)
27 init_response(http_response_t* response)
29 response->status_code = OK_200;
30 response->status_string =
NULL;
31 response->headers =
NULL;
32 response->payload =
NULL;
33 response->payload_len = 0;
37 init_request(http_request_t* request)
39 request->request_type = 0;
42 request->query =
NULL;
43 request->query_len = 0;
44 request->headers =
NULL;
45 request->payload =
NULL;
46 request->payload_len = 0;
53 init_connection(connection_state_t* conn_state)
55 conn_state->state = STATE_WAITING;
57 init_request(&conn_state->request);
58 init_response(&conn_state->response);
62 http_set_status(http_response_t* response, status_code_t status)
64 response->status_code = status;
68 allocate_header(uint16_t variable_len)
70 PRINTF(
"sizeof http_header_t %u variable size %u\n",
sizeof(http_header_t), variable_len);
71 uint8_t* buffer = allocate_buffer(
sizeof(http_header_t) + variable_len);
73 http_header_t* option = (http_header_t*) buffer;
76 option->value = buffer +
sizeof(http_header_t);
84 http_set_res_header(http_response_t* response,
const char* name,
const char* value,
int copy)
86 PRINTF(
"http_set_res_header (copy:%d) %s:%s\n", copy, name, value);
88 http_header_t* current_header =
NULL;
89 http_header_t* head =
NULL;
92 size += strlen(value) + 1;
95 current_header = allocate_header(size);
98 current_header->name = (
char*)name;
100 strcpy(current_header->value, value);
102 current_header->value = (
char*)value;
105 head = response->headers;
106 response->headers = current_header;
108 current_header->next = head;
117 static const char* is_request_hdr_needed(
const char* header_name)
119 const char* header =
NULL;
121 if (strcmp(header_name, HTTP_HEADER_NAME_CONTENT_LENGTH) == 0) {
122 header = HTTP_HEADER_NAME_CONTENT_LENGTH;
123 }
else if (strcmp(header_name, HTTP_HEADER_NAME_CONTENT_TYPE) == 0) {
124 header = HTTP_HEADER_NAME_CONTENT_TYPE;
130 static service_callback service_cbk =
NULL;
133 http_set_service_callback(service_callback callback)
135 service_cbk = callback;
138 const char* content_types[] = {
146 "application/link-format",
147 "application/x-www-form-urlencoded",
151 http_get_content_type_string(content_type_t content_type)
153 return content_types[content_type];
157 get_default_status_string(status_code_t status_code)
160 switch(status_code) {
171 value =
"No Content";
174 value =
"Not Modified";
177 value =
"Bad Request" ;
180 value =
"Not Found" ;
183 value =
"Method Not Allowed" ;
186 value =
"Not Acceptable" ;
189 value =
"Request-URI Too Long" ;
192 value =
"Unsupported Media Type" ;
195 value =
"Internal Server Error" ;
198 value =
"Not Implemented" ;
201 value =
"Service Unavailable" ;
213 http_get_query_variable(http_request_t* request,
const char *name,
char* output, uint16_t output_size)
215 if (request->query) {
216 return get_variable(name, request->query, request->query_len, output, output_size, 0);
223 http_get_post_variable(http_request_t* request,
const char *name,
char* output, uint16_t output_size)
225 if (request->payload) {
226 return get_variable(name, request->payload, request->payload_len, output, output_size, 1);
233 is_method_handled(connection_state_t* conn_state,
const char* method)
236 if(strncmp(method, http_get_string, 3) == 0) {
237 conn_state->request.request_type = HTTP_METHOD_GET;
238 }
else if (strncmp(method, http_post_string, 4) == 0) {
239 conn_state->request.request_type = HTTP_METHOD_POST;
240 }
else if (strncmp(method, http_put_string, 3) == 0) {
241 conn_state->request.request_type = HTTP_METHOD_PUT;
242 }
else if (strncmp(method, http_delete_string, 3) == 0) {
243 conn_state->request.request_type = HTTP_METHOD_DELETE;
245 PRINTF(
"No Method supported : %s\nstate : %d\n", conn_state->inputbuf, conn_state->state);
253 parse_url(connection_state_t* conn_state,
char* url)
255 int error = HTTP_NO_ERROR;
256 int full_url_path = 0;
260 if (strncmp(url, http_string, 4) != 0 ) {
261 PRINTF(
"Url not valid : %s \n",url);
262 error = HTTP_URL_INVALID;
268 if (error == HTTP_NO_ERROR) {
269 char* url_buffer = url;
271 unsigned char num_of_slash = 0;
273 url_buffer = strchr( ++url_buffer,
'/' );
275 PRINTF(
"Buffer : %s %d\n", url_buffer, num_of_slash);
277 }
while (url_buffer && ++num_of_slash < 3);
280 PRINTF(
"Url found :%s\n", url_buffer);
283 if (url_buffer && ++url_buffer) {
284 conn_state->request.url = (
char*) copy_text_to_buffer(url_buffer);
285 conn_state->request.url_len = strlen(url_buffer);
287 if ((conn_state->request.query = strchr(conn_state->request.url,
'?'))) {
288 *(conn_state->request.query++) = 0;
290 conn_state->request.url_len = strlen(conn_state->request.url);
291 conn_state->request.query_len = strlen(conn_state->request.query);
294 PRINTF(
"url %s, url_len %u, query %s, query_len %u\n", conn_state->request.url, conn_state->request.url_len, conn_state->request.query, conn_state->request.query_len);
298 error = HTTP_URL_INVALID;
306 parse_header(connection_state_t* conn_state,
char* inputbuf)
308 PRINTF(
"parse_header --->\n");
309 const char* header_name =
NULL;
311 char* delimiter = strchr(inputbuf,
':');
315 header_name = is_request_hdr_needed(inputbuf);
316 if (header_name && delimiter) {
317 char* buffer = delimiter;
319 if (buffer[0] ==
' ') {
323 http_header_t* current_header =
NULL;
324 http_header_t* head =
NULL;
326 current_header = allocate_header(strlen(buffer));
328 if (current_header) {
329 current_header->name = (
char*)header_name;
330 strcpy(current_header->value, buffer);
333 head = conn_state->request.headers;
334 conn_state->request.headers = current_header;
336 current_header->next = head;
347 http_set_res_payload(http_response_t* response, uint8_t* payload, uint16_t size)
349 response->payload = copy_to_buffer(payload, size);
350 if (response->payload) {
351 response->payload_len = size;
359 get_header(http_header_t* headers,
const char* hdr_name)
361 for (;headers; headers = headers->next) {
362 if (strcmp(headers->name, hdr_name) == 0) {
363 return headers->value;
370 const char* http_get_req_header(http_request_t* request,
const char* name)
372 return get_header(request->headers, name);
375 content_type_t http_get_header_content_type(http_request_t* request)
377 const char* content_type_string = http_get_req_header(request, HTTP_HEADER_NAME_CONTENT_TYPE);
378 if (content_type_string) {
380 for(; i <
sizeof(content_types)/
sizeof(
const char*) ; i++) {
381 if (strcmp(content_types[i], content_type_string)) {
382 return (content_type_t)i;
387 return UNKNOWN_CONTENT_TYPE;
391 PT_THREAD(handle_request(connection_state_t* conn_state))
394 const char* content_len;
400 error = HTTP_NO_ERROR;
402 PRINTF(
"Request--->\n");
407 if (!is_method_handled(conn_state, conn_state->inputbuf)) {
409 http_set_status(&conn_state->response, SERVICE_UNAVAILABLE_503);
410 conn_state->state = STATE_OUTPUT;
416 if (conn_state->inputbuf[
PSOCK_DATALEN(&(conn_state->sin)) - 1] !=
' ' ) {
417 error = HTTP_URL_TOO_LONG;
420 conn_state->inputbuf[
PSOCK_DATALEN(&(conn_state->sin)) - 1] = 0;
422 PRINTF(
"Read URL:%s\n", conn_state->inputbuf);
424 if (error == HTTP_NO_ERROR) {
425 error = parse_url(conn_state, conn_state->inputbuf);
428 if (error != HTTP_NO_ERROR) {
429 if (error == HTTP_URL_TOO_LONG) {
430 http_set_status(&conn_state->response, REQUEST_URI_TOO_LONG_414);
432 http_set_status(&conn_state->response, BAD_REQUEST_400);
435 conn_state->state = STATE_OUTPUT;
440 PRINTF(
"After URL:%s\n", conn_state->inputbuf);
450 conn_state->inputbuf[
PSOCK_DATALEN(&(conn_state->sin)) - 1] = 0;
453 if (conn_state->inputbuf[0] == CARRIAGE_RETURN_CHAR || conn_state->inputbuf[0] == 0) {
454 PRINTF(
"Finished Headers!\n\n");
458 parse_header(conn_state, conn_state->inputbuf);
462 content_len = get_header(conn_state->request.headers, HTTP_HEADER_NAME_CONTENT_LENGTH);
464 conn_state->request.payload_len = atoi(content_len);
466 PRINTF(
"Post Data Size string: %s int: %d\n", content_len, conn_state->request.payload_len);
469 if (conn_state->request.payload_len) {
470 static uint16_t read_bytes = 0;
474 conn_state->request.payload = allocate_buffer(conn_state->request.payload_len + 1);
476 if (conn_state->request.payload) {
482 memcpy(conn_state->request.payload + read_bytes, conn_state->inputbuf,
PSOCK_DATALEN(&(conn_state->sin)));
486 }
while (read_bytes < conn_state->request.payload_len);
488 conn_state->request.payload[read_bytes++] = 0;
490 PRINTF(
"PostData => %s \n", conn_state->request.payload);
492 error = HTTP_MEMORY_ALLOC_ERR;
496 if (error == HTTP_NO_ERROR) {
498 service_cbk(&conn_state->request, &conn_state->response);
501 PRINTF(
"Error:%d\n",error);
502 http_set_status(&conn_state->response, INTERNAL_SERVER_ERROR_500);
505 conn_state->state = STATE_OUTPUT;
513 PT_THREAD(send_data(connection_state_t* conn_state))
516 http_response_t* response;
517 http_header_t* header;
522 PRINTF(
"send_data -> \n");
525 response = &conn_state->response;
526 header = response->headers;
527 buffer = allocate_buffer(200);
531 index += sprintf(buffer + index,
"%s %d %s%s", httpv1_1, response->status_code, response->status_string, line_end);
532 for (;header;header = header->next) {
533 PRINTF(
"header %u \n", (uint16_t)header);
534 index += sprintf(buffer + index,
"%s%s%s%s", header->name, header_delimiter, header->value, line_end);
536 index += sprintf(buffer + index,
"%s", line_end);
538 memcpy(buffer + index, response->payload, response->payload_len);
539 index += response->payload_len;
541 PRINTF(
"Sending Data(size %d): %s \n", index, buffer);
543 PSOCK_SEND(&(conn_state->sout), buffer, index);
545 PRINTF(
"BUFF ERROR: send_data!\n");
552 PT_THREAD(handle_response(connection_state_t* conn_state))
556 PRINTF(
"handle_response ->\n");
558 http_set_res_header(&conn_state->response, HTTP_HEADER_NAME_CONNECTION, close, 0);
559 http_set_res_header(&conn_state->response, HTTP_HEADER_NAME_SERVER, contiki, 0);
561 if (!(conn_state->response.status_string)) {
562 conn_state->response.status_string =
563 get_default_status_string(conn_state->response.status_code);
568 PRINTF(
"<-- handle_response\n\n\n");
572 PT_END(&(conn_state->outputpt));
576 handle_connection(connection_state_t* conn_state)
578 if (conn_state->state == STATE_WAITING) {
579 handle_request(conn_state);
582 if (conn_state->state == STATE_OUTPUT) {
583 handle_response(conn_state);
587 PROCESS(http_server,
"Httpd Process");
591 connection_state_t *conn_state;
596 #if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
597 set_global_address();
601 #ifdef CONTIKI_TARGET_SKY
602 PRINTF(
"##RF CHANNEL : %d##\n",RF_CHANNEL);
603 #endif //CONTIKI_TARGET_SKY
613 conn_state = (connection_state_t *)data;
616 PRINTF(
"##Connected##\n");
618 if(init_buffer(HTTP_DATA_BUFF_SIZE)) {
619 conn_state = (connection_state_t*)allocate_buffer(
sizeof(connection_state_t));
625 init_connection(conn_state);
628 PSOCK_INIT(&(conn_state->sin), (uint8_t*)conn_state->inputbuf,
sizeof(conn_state->inputbuf) - 1);
629 PSOCK_INIT(&(conn_state->sout), (uint8_t*)conn_state->inputbuf,
sizeof(conn_state->inputbuf) - 1);
630 PT_INIT(&(conn_state->outputpt));
632 handle_connection(conn_state);
634 PRINTF(
"Memory Alloc Error. Aborting!\n");
648 handle_connection(conn_state);
#define PT_WAIT_THREAD(pt, thread)
Block and wait until a child protothread completes.
#define PSOCK_READTO(psock, c)
Read data up to a specified character.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define PSOCK_BEGIN(psock)
Start the protosocket protothread in a function.
Representation of a uIP TCP connection.
#define uip_aborted()
Has the connection been aborted by the other end?
#define PSOCK_READBUF(psock)
Read data until the buffer is full.
#define NULL
The null pointer.
#define PT_INIT(pt)
Initialize a protothread.
#define PT_THREAD(name_args)
Declaration of a protothread.
#define uip_connected()
Has the connection just been connected?
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define PROCESS_END()
Define the end of a process.
#define uip_abort()
Abort the current connection.
#define PSOCK_INIT(psock, buffer, buffersize)
Initialize a protosocket.
CCIF uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
#define PSOCK_CLOSE(psock)
Close a protosocket.
#define PSOCK_SEND(psock, data, datalen)
Send data.
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
#define PSOCK_END(psock)
Declare the end of a protosocket's protothread.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
#define PROCESS(name, strname)
Declare a process.
process_event_t tcpip_event
The uIP event.
#define uip_timedout()
Has the connection timed out?
#define PT_END(pt)
Declare the end of a protothread.
CCIF void tcp_listen(uint16_t port)
Open a TCP port.
#define PSOCK_DATALEN(psock)
The length of the data that was previously read.
#define uip_closed()
Has the connection been closed by the other end?