31 #include "contiki-net.h"
32 #include "ip64-addr.h"
33 #include "http-socket.h"
38 #define MAX_PATHLEN 80
39 #define MAX_HOSTLEN 40
40 PROCESS(http_socket_process,
"HTTP socket process");
43 static void removesocket(
struct http_socket *s);
46 call_callback(
struct http_socket *s, http_socket_event_t e,
47 const uint8_t *data, uint16_t datalen)
49 if(s->callback !=
NULL) {
50 s->callback(s, s->callbackptr, e,
56 parse_header_init(
struct http_socket *s)
62 parse_header_byte(
struct http_socket *s,
char c)
66 memset(&s->header, -1,
sizeof(s->header));
76 s->header.status_code = 0;
77 for(s->header_chars = 0; s->header_chars < 3; s->header_chars++) {
78 s->header.status_code = s->header.status_code << 4 | (c -
'0');
82 if(s->header.status_code == 0x200 || s->header.status_code == 0x206) {
98 if(s->header_chars == 0) {
107 while(c !=
' ' && c !=
'\t' && c !=
':' && c !=
'\r' &&
108 s->header_chars <
sizeof(s->header_field) - 1) {
109 s->header_field[s->header_chars++] = c;
112 s->header_field[s->header_chars] =
'\0';
114 while(c ==
' ' || c ==
'\t') {
123 while(c ==
' ' || c ==
'\t') {
127 if(!strcmp(s->header_field,
"Content-Length")) {
128 s->header.content_length = 0;
129 while(isdigit((
int)c)) {
130 s->header.content_length = s->header.content_length * 10 + c -
'0';
134 }
else if(!strcmp(s->header_field,
"Content-Range")) {
136 while(c !=
' ' && c !=
'\t') {
141 while(c ==
' ' || c ==
'\t') {
145 s->header.content_range.first_byte_pos = 0;
146 while(isdigit((
int)c)) {
147 s->header.content_range.first_byte_pos =
148 s->header.content_range.first_byte_pos * 10 + c -
'0';
153 while(c ==
' ' || c ==
'\t') {
162 while(c ==
' ' || c ==
'\t') {
166 s->header.content_range.last_byte_pos = 0;
167 while(isdigit((
int)c)) {
168 s->header.content_range.last_byte_pos =
169 s->header.content_range.last_byte_pos * 10 + c -
'0';
174 while(c ==
' ' || c ==
'\t') {
183 while(c ==
' ' || c ==
'\t') {
188 s->header.content_range.instance_length = 0;
189 while(isdigit((
int)c)) {
190 s->header.content_range.instance_length =
191 s->header.content_range.instance_length * 10 + c -
'0';
203 call_callback(s, HTTP_SOCKET_HEADER, (
void *)&s->header,
sizeof(s->header));
209 if(s->header.status_code == 0x404) {
210 printf(
"File not found\n");
211 }
else if(s->header.status_code == 0x301 || s->header.status_code == 0x302) {
212 printf(
"File moved (not handled)\n");
215 call_callback(s, HTTP_SOCKET_ERR, (
void *)&s->header,
sizeof(s->header));
216 tcp_socket_close(&s->s);
226 input_pt(
struct http_socket *s,
227 const uint8_t *inputptr,
int inputdatalen)
233 s->header_received = 0;
235 for(i = 0; i < inputdatalen; i++) {
236 if(!
PT_SCHEDULE(parse_header_byte(s, inputptr[i]))) {
237 s->header_received = 1;
244 if(s->header_received == 0) {
249 }
while(s->header_received == 0);
254 call_callback(s, HTTP_SOCKET_DATA, inputptr, inputdatalen);
257 if(s->header.content_length >= 0 && s->bodylen < s->header.content_length) {
258 s->bodylen += inputdatalen;
259 if(s->bodylen >= s->header.content_length) {
260 tcp_socket_close(&s->s);
265 }
while(inputdatalen > 0);
271 start_timeout_timer(
struct http_socket *s)
274 etimer_set(&s->timeout_timer, HTTP_SOCKET_TIMEOUT);
276 s->timeout_timer_started = 1;
280 input(
struct tcp_socket *tcps,
void *ptr,
281 const uint8_t *inputptr,
int inputdatalen)
283 struct http_socket *s = ptr;
285 input_pt(s, inputptr, inputdatalen);
286 start_timeout_timer(s);
292 parse_url(
const char *url,
char *host, uint16_t *portptr,
char *path)
300 printf(
"null url\n");
305 if(strlen(url) == 0) {
306 printf(
"empty url\n");
312 if(strncmp(url,
"http://", strlen(
"http://")) == 0) {
313 urlptr = url + strlen(
"http://");
322 for(i = 0; i < MAX_HOSTLEN; ++i) {
336 for(i = 0; i < MAX_HOSTLEN; ++i) {
354 if(!memchr(host, 0, MAX_HOSTLEN)) {
364 if(*urlptr >=
'0' && *urlptr <=
'9') {
365 port = (10 * port) + (*urlptr -
'0');
367 }
while(*urlptr >=
'0' &&
370 if(portptr !=
NULL) {
374 while(*urlptr !=
'/' && *urlptr != 0) {
383 strncpy(path, file, MAX_PATHLEN);
389 removesocket(
struct http_socket *s)
392 s->timeout_timer_started = 0;
397 event(
struct tcp_socket *tcps,
void *ptr,
398 tcp_socket_event_t e)
400 struct http_socket *s = ptr;
401 char host[MAX_HOSTLEN];
402 char path[MAX_PATHLEN];
407 if(e == TCP_SOCKET_CONNECTED) {
408 printf(
"Connected\n");
409 if(parse_url(s->url, host, &port, path)) {
410 tcp_socket_send_str(tcps, s->postdata !=
NULL ?
"POST " :
"GET ");
411 if(s->proxy_port != 0) {
414 tcp_socket_send_str(tcps, s->url);
416 tcp_socket_send_str(tcps, path);
418 tcp_socket_send_str(tcps,
" HTTP/1.1\r\n");
419 tcp_socket_send_str(tcps,
"Connection: close\r\n");
420 tcp_socket_send_str(tcps,
"Host: ");
423 if(memchr(host,
':', MAX_HOSTLEN)) {
424 tcp_socket_send_str(tcps,
"[");
426 tcp_socket_send_str(tcps, host);
427 if(memchr(host,
':', MAX_HOSTLEN)) {
428 tcp_socket_send_str(tcps,
"]");
430 tcp_socket_send_str(tcps,
"\r\n");
431 if(s->postdata !=
NULL) {
432 if(s->content_type) {
433 tcp_socket_send_str(tcps,
"Content-Type: ");
434 tcp_socket_send_str(tcps, s->content_type);
435 tcp_socket_send_str(tcps,
"\r\n");
437 tcp_socket_send_str(tcps,
"Content-Length: ");
438 sprintf(str,
"%u", s->postdatalen);
439 tcp_socket_send_str(tcps, str);
440 tcp_socket_send_str(tcps,
"\r\n");
441 }
else if(s->length || s->pos > 0) {
442 tcp_socket_send_str(tcps,
"Range: bytes=");
445 sprintf(str,
"%llu-%llu", s->pos, s->pos + s->length - 1);
447 sprintf(str,
"-%llu", s->length);
450 sprintf(str,
"%llu-", s->pos);
452 tcp_socket_send_str(tcps, str);
453 tcp_socket_send_str(tcps,
"\r\n");
455 tcp_socket_send_str(tcps,
"\r\n");
456 if(s->postdata !=
NULL && s->postdatalen) {
457 len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
459 s->postdatalen -= len;
462 parse_header_init(s);
463 }
else if(e == TCP_SOCKET_CLOSED) {
464 call_callback(s, HTTP_SOCKET_CLOSED,
NULL, 0);
467 }
else if(e == TCP_SOCKET_TIMEDOUT) {
468 call_callback(s, HTTP_SOCKET_TIMEDOUT,
NULL, 0);
470 printf(
"Timedout\n");
471 }
else if(e == TCP_SOCKET_ABORTED) {
472 call_callback(s, HTTP_SOCKET_ABORTED,
NULL, 0);
475 }
else if(e == TCP_SOCKET_DATA_SENT) {
476 if(s->postdata !=
NULL && s->postdatalen) {
477 len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
479 s->postdatalen -= len;
481 start_timeout_timer(s);
487 start_request(
struct http_socket *s)
490 uip_ip6addr_t ip6addr;
492 char host[MAX_HOSTLEN];
493 char path[MAX_PATHLEN];
497 if(parse_url(s->url, host, &port, path)) {
499 printf(
"url %s host %s port %d path %s\n",
500 s->url, host, port, path);
503 if(s->proxy_port != 0) {
505 uip_ip6addr_copy(&ip6addr, &s->proxy_addr);
506 port = s->proxy_port;
507 }
else if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
509 if(uiplib_ip4addrconv(host, &ip4addr) != 0) {
510 ip64_addr_4to6(&ip4addr, &ip6addr);
518 puts(
"Resolving host...");
519 return HTTP_SOCKET_OK;
522 s->did_tcp_connect = 1;
523 tcp_socket_connect(&s->s, addr, port);
524 return HTTP_SOCKET_OK;
526 return HTTP_SOCKET_ERR;
530 tcp_socket_connect(&s->s, &ip6addr, port);
531 return HTTP_SOCKET_OK;
533 return HTTP_SOCKET_ERR;
546 struct http_socket *s;
547 const char *name = data;
555 char host[MAX_HOSTLEN];
556 if(s->did_tcp_connect) {
558 }
else if(parse_url(s->url, host,
NULL,
NULL) &&
559 strcmp(name, host) == 0) {
565 call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND,
NULL, 0);
570 }
else if(ev == PROCESS_EVENT_TIMER) {
571 struct http_socket *s;
572 struct etimer *timeout_timer = data;
581 if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) {
582 tcp_socket_close(&s->s);
595 static uint8_t inited = 0;
604 http_socket_init(
struct http_socket *s)
612 initialize_socket(
struct http_socket *s)
618 s->timeout_timer_started = 0;
620 tcp_socket_register(&s->s, s,
621 s->inputbuf,
sizeof(s->inputbuf),
622 s->outputbuf,
sizeof(s->outputbuf),
627 http_socket_get(
struct http_socket *s,
631 http_socket_callback_t callback,
634 initialize_socket(s);
635 strncpy(s->url, url,
sizeof(s->url));
638 s->callback = callback;
639 s->callbackptr = callbackptr;
641 s->did_tcp_connect = 0;
645 return start_request(s);
649 http_socket_post(
struct http_socket *s,
651 const void *postdata,
652 uint16_t postdatalen,
653 const char *content_type,
654 http_socket_callback_t callback,
657 initialize_socket(s);
658 strncpy(s->url, url,
sizeof(s->url));
659 s->postdata = postdata;
660 s->postdatalen = postdatalen;
661 s->content_type = content_type;
663 s->callback = callback;
664 s->callbackptr = callbackptr;
666 s->did_tcp_connect = 0;
670 return start_request(s);
674 http_socket_close(
struct http_socket *socket)
676 struct http_socket *s;
681 tcp_socket_close(&s->s);
690 http_socket_set_proxy(
struct http_socket *s,
691 const uip_ipaddr_t *addr, uint16_t port)
694 s->proxy_port = port;
Hostname was found, but it's status has expired.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
#define PT_SCHEDULE(f)
Schedule a protothread.
#define PT_INIT(pt)
Initialize a protothread.
#define LIST(name)
Declare a linked list.
static uip_ds6_addr_t * addr
Pointer to a router list entry.
#define PROCESS_CONTEXT_END(p)
End a context switch.
#define uip_create_unspecified(a)
set IP address a to unspecified
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
#define PROCESS_END()
Define the end of a process.
#define PROCESS(name, strname)
Declare a process.
static void input(void)
Process a received 6lowpan packet.
#define PT_YIELD(pt)
Yield from the current protothread.
void * list_item_next(void *item)
Get the next item following this item.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
process_event_t resolv_event_found
Event that is broadcasted when a DNS name has been resolved.
Hostname was not found in the cache.
void etimer_stop(struct etimer *et)
Stop a pending event timer.
Representation of an IP address.
void list_init(list_t list)
Initialize a list.
#define PT_EXIT(pt)
Exit the protothread.
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
void * list_head(list_t list)
Get a pointer to the first element of a list.
#define NULL
The null pointer.
resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t **ipaddr)
Look up a hostname in the array of known hostnames.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Hostname is fresh and usable.
void list_add(list_t list, void *item)
Add an item at the end of a list.
void process_start(struct process *p, process_data_t data)
Start a process.
void resolv_query(const char *name)
Queues a name so that a question for the name will be sent out.
#define PT_END(pt)
Declare the end of a protothread.
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
#define PROCESS_BEGIN()
Define the beginning of a process.