31 #include "contiki-net.h" 32 #include "ipv6/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",
446 (
long long unsigned int)s->pos, (
long long unsigned int)s->pos + s->length - 1);
448 sprintf(str,
"-%llu", (
long long unsigned int)s->length);
451 sprintf(str,
"%llu-", (
long long unsigned int)s->pos);
453 tcp_socket_send_str(tcps, str);
454 tcp_socket_send_str(tcps,
"\r\n");
456 tcp_socket_send_str(tcps,
"\r\n");
457 if(s->postdata != NULL && s->postdatalen) {
458 len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
460 s->postdatalen -= len;
463 parse_header_init(s);
464 }
else if(e == TCP_SOCKET_CLOSED) {
465 call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0);
468 }
else if(e == TCP_SOCKET_TIMEDOUT) {
469 call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0);
471 printf(
"Timedout\n");
472 }
else if(e == TCP_SOCKET_ABORTED) {
473 call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0);
476 }
else if(e == TCP_SOCKET_DATA_SENT) {
477 if(s->postdata != NULL && s->postdatalen) {
478 len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
480 s->postdatalen -= len;
482 start_timeout_timer(s);
488 start_request(
struct http_socket *s)
491 uip_ip6addr_t ip6addr;
493 char host[MAX_HOSTLEN];
494 char path[MAX_PATHLEN];
498 if(parse_url(s->url, host, &port, path)) {
500 printf(
"url %s host %s port %d path %s\n",
501 s->url, host, port, path);
504 if(s->proxy_port != 0) {
506 uip_ip6addr_copy(&ip6addr, &s->proxy_addr);
507 port = s->proxy_port;
508 }
else if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
510 if(uiplib_ip4addrconv(host, &ip4addr) != 0) {
511 ip64_addr_4to6(&ip4addr, &ip6addr);
519 puts(
"Resolving host...");
520 return HTTP_SOCKET_OK;
523 s->did_tcp_connect = 1;
524 tcp_socket_connect(&s->s, addr, port);
525 return HTTP_SOCKET_OK;
527 return HTTP_SOCKET_ERR;
531 tcp_socket_connect(&s->s, &ip6addr, port);
532 return HTTP_SOCKET_OK;
534 return HTTP_SOCKET_ERR;
547 struct http_socket *s;
548 const char *name = data;
556 char host[MAX_HOSTLEN];
557 if(s->did_tcp_connect) {
559 }
else if(parse_url(s->url, host, NULL, NULL) &&
560 strcmp(name, host) == 0) {
566 call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
571 }
else if(ev == PROCESS_EVENT_TIMER) {
572 struct http_socket *s;
573 struct etimer *timeout_timer = data;
582 if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) {
583 tcp_socket_close(&s->s);
596 static uint8_t inited = 0;
605 http_socket_init(
struct http_socket *s)
613 initialize_socket(
struct http_socket *s)
619 s->timeout_timer_started = 0;
621 tcp_socket_register(&s->s, s,
622 s->inputbuf,
sizeof(s->inputbuf),
623 s->outputbuf,
sizeof(s->outputbuf),
628 http_socket_get(
struct http_socket *s,
632 http_socket_callback_t callback,
635 initialize_socket(s);
636 strncpy(s->url, url,
sizeof(s->url));
639 s->callback = callback;
640 s->callbackptr = callbackptr;
642 s->did_tcp_connect = 0;
646 return start_request(s);
650 http_socket_post(
struct http_socket *s,
652 const void *postdata,
653 uint16_t postdatalen,
654 const char *content_type,
655 http_socket_callback_t callback,
658 initialize_socket(s);
659 strncpy(s->url, url,
sizeof(s->url));
660 s->postdata = postdata;
661 s->postdatalen = postdatalen;
662 s->content_type = content_type;
664 s->callback = callback;
665 s->callbackptr = callbackptr;
667 s->did_tcp_connect = 0;
671 return start_request(s);
675 http_socket_close(
struct http_socket *socket)
677 struct http_socket *s;
682 tcp_socket_close(&s->s);
691 http_socket_set_proxy(
struct http_socket *s,
692 const uip_ipaddr_t *addr, uint16_t port)
695 s->proxy_port = port;
process_event_t resolv_event_found
Event that is broadcasted when a DNS name has been resolved.
#define PROCESS(name, strname)
Declare a process.
void etimer_stop(struct etimer *et)
Stop a pending event timer.
#define PROCESS_CONTEXT_END(p)
End a context switch.
Hostname is fresh and usable.
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define PROCESS_END()
Define the end of a process.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Hostname was found, but it's status has expired.
Representation of an IP address.
#define PT_INIT(pt)
Initialize a protothread.
#define PT_END(pt)
Declare the end of a protothread.
resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t **ipaddr)
Look up a hostname in the array of known hostnames.
#define PT_SCHEDULE(f)
Schedule a protothread.
void * list_head(list_t list)
Get a pointer to the first element of a list.
#define PT_YIELD(pt)
Yield from the current protothread.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
#define PT_EXIT(pt)
Exit the protothread.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Hostname was not found in the cache.
#define uip_create_unspecified(a)
set IP address a to unspecified
void list_init(list_t list)
Initialize a list.
#define LIST(name)
Declare a linked list.
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
static void input(void)
Process a received 6lowpan packet.
void resolv_query(const char *name)
Queues a name so that a question for the name will be sent out.
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
void * list_item_next(void *item)
Get the next item following this item.
void process_start(struct process *p, process_data_t data)
Start a process.