31 #include "contiki-net.h" 32 #include "ipv6/ip64-addr.h" 34 #include "http-socket.h" 39 #define MAX_PATHLEN 80 40 #define MAX_HOSTLEN 40 41 PROCESS(http_socket_process,
"HTTP socket process");
44 static void removesocket(
struct http_socket *s);
47 call_callback(
struct http_socket *s, http_socket_event_t e,
48 const uint8_t *data, uint16_t datalen)
50 if(s->callback != NULL) {
51 s->callback(s, s->callbackptr, e,
57 parse_header_init(
struct http_socket *s)
63 parse_header_byte(
struct http_socket *s,
char c)
67 memset(&s->header, -1,
sizeof(s->header));
77 s->header.status_code = 0;
78 for(s->header_chars = 0; s->header_chars < 3; s->header_chars++) {
79 s->header.status_code = s->header.status_code << 4 | (c -
'0');
83 if(s->header.status_code == 0x200 || s->header.status_code == 0x206) {
99 if(s->header_chars == 0) {
108 while(c !=
' ' && c !=
'\t' && c !=
':' && c !=
'\r' &&
109 s->header_chars <
sizeof(s->header_field) - 1) {
110 s->header_field[s->header_chars++] = c;
113 s->header_field[s->header_chars] =
'\0';
115 while(c ==
' ' || c ==
'\t') {
124 while(c ==
' ' || c ==
'\t') {
128 if(!strcmp(s->header_field,
"Content-Length")) {
129 s->header.content_length = 0;
130 while(isdigit((
int)c)) {
131 s->header.content_length = s->header.content_length * 10 + c -
'0';
135 }
else if(!strcmp(s->header_field,
"Content-Range")) {
137 while(c !=
' ' && c !=
'\t') {
142 while(c ==
' ' || c ==
'\t') {
146 s->header.content_range.first_byte_pos = 0;
147 while(isdigit((
int)c)) {
148 s->header.content_range.first_byte_pos =
149 s->header.content_range.first_byte_pos * 10 + c -
'0';
154 while(c ==
' ' || c ==
'\t') {
163 while(c ==
' ' || c ==
'\t') {
167 s->header.content_range.last_byte_pos = 0;
168 while(isdigit((
int)c)) {
169 s->header.content_range.last_byte_pos =
170 s->header.content_range.last_byte_pos * 10 + c -
'0';
175 while(c ==
' ' || c ==
'\t') {
184 while(c ==
' ' || c ==
'\t') {
189 s->header.content_range.instance_length = 0;
190 while(isdigit((
int)c)) {
191 s->header.content_range.instance_length =
192 s->header.content_range.instance_length * 10 + c -
'0';
204 call_callback(s, HTTP_SOCKET_HEADER, (
void *)&s->header,
sizeof(s->header));
210 if(s->header.status_code == 0x404) {
211 printf(
"File not found\n");
212 }
else if(s->header.status_code == 0x301 || s->header.status_code == 0x302) {
213 printf(
"File moved (not handled)\n");
216 call_callback(s, HTTP_SOCKET_ERR, (
void *)&s->header,
sizeof(s->header));
217 tcp_socket_close(&s->s);
227 input_pt(
struct http_socket *s,
228 const uint8_t *inputptr,
int inputdatalen)
234 s->header_received = 0;
236 for(i = 0; i < inputdatalen; i++) {
237 if(!
PT_SCHEDULE(parse_header_byte(s, inputptr[i]))) {
238 s->header_received = 1;
245 if(s->header_received == 0) {
250 }
while(s->header_received == 0);
255 call_callback(s, HTTP_SOCKET_DATA, inputptr, inputdatalen);
258 if(s->header.content_length >= 0 && s->bodylen < s->header.content_length) {
259 s->bodylen += inputdatalen;
260 if(s->bodylen >= s->header.content_length) {
261 tcp_socket_close(&s->s);
266 }
while(inputdatalen > 0);
272 start_timeout_timer(
struct http_socket *s)
275 etimer_set(&s->timeout_timer, HTTP_SOCKET_TIMEOUT);
277 s->timeout_timer_started = 1;
281 input(
struct tcp_socket *tcps,
void *ptr,
282 const uint8_t *inputptr,
int inputdatalen)
284 struct http_socket *s = ptr;
286 input_pt(s, inputptr, inputdatalen);
287 start_timeout_timer(s);
293 parse_url(
const char *url,
char *host, uint16_t *portptr,
char *path)
301 printf(
"null url\n");
306 if(strlen(url) == 0) {
307 printf(
"empty url\n");
313 if(strncmp(url,
"http://", strlen(
"http://")) == 0) {
314 urlptr = url + strlen(
"http://");
323 for(i = 0; i < MAX_HOSTLEN; ++i) {
337 for(i = 0; i < MAX_HOSTLEN; ++i) {
355 if(!memchr(host, 0, MAX_HOSTLEN)) {
365 if(*urlptr >=
'0' && *urlptr <=
'9') {
366 port = (10 * port) + (*urlptr -
'0');
368 }
while(*urlptr >=
'0' &&
371 if(portptr != NULL) {
375 while(*urlptr !=
'/' && *urlptr != 0) {
384 strncpy(path, file, MAX_PATHLEN);
390 removesocket(
struct http_socket *s)
393 s->timeout_timer_started = 0;
398 event(
struct tcp_socket *tcps,
void *ptr,
399 tcp_socket_event_t e)
401 struct http_socket *s = ptr;
402 char host[MAX_HOSTLEN];
403 char path[MAX_PATHLEN];
408 if(e == TCP_SOCKET_CONNECTED) {
409 printf(
"Connected\n");
410 if(parse_url(s->url, host, &port, path)) {
411 tcp_socket_send_str(tcps, s->postdata != NULL ?
"POST " :
"GET ");
412 if(s->proxy_port != 0) {
415 tcp_socket_send_str(tcps, s->url);
417 tcp_socket_send_str(tcps, path);
419 tcp_socket_send_str(tcps,
" HTTP/1.1\r\n");
420 tcp_socket_send_str(tcps,
"Connection: close\r\n");
421 tcp_socket_send_str(tcps,
"Host: ");
424 if(memchr(host,
':', MAX_HOSTLEN)) {
425 tcp_socket_send_str(tcps,
"[");
427 tcp_socket_send_str(tcps, host);
428 if(memchr(host,
':', MAX_HOSTLEN)) {
429 tcp_socket_send_str(tcps,
"]");
431 tcp_socket_send_str(tcps,
"\r\n");
432 if(s->postdata != NULL) {
433 if(s->content_type) {
434 tcp_socket_send_str(tcps,
"Content-Type: ");
435 tcp_socket_send_str(tcps, s->content_type);
436 tcp_socket_send_str(tcps,
"\r\n");
438 tcp_socket_send_str(tcps,
"Content-Length: ");
439 sprintf(str,
"%u", s->postdatalen);
440 tcp_socket_send_str(tcps, str);
441 tcp_socket_send_str(tcps,
"\r\n");
442 }
else if(s->length || s->pos > 0) {
443 tcp_socket_send_str(tcps,
"Range: bytes=");
446 sprintf(str,
"%llu-%llu",
447 (
long long unsigned int)s->pos, (
long long unsigned int)s->pos + s->length - 1);
449 sprintf(str,
"-%llu", (
long long unsigned int)s->length);
452 sprintf(str,
"%llu-", (
long long unsigned int)s->pos);
454 tcp_socket_send_str(tcps, str);
455 tcp_socket_send_str(tcps,
"\r\n");
457 tcp_socket_send_str(tcps,
"\r\n");
458 if(s->postdata != NULL && s->postdatalen) {
459 len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
461 s->postdatalen -= len;
464 parse_header_init(s);
465 }
else if(e == TCP_SOCKET_CLOSED) {
466 call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0);
469 }
else if(e == TCP_SOCKET_TIMEDOUT) {
470 call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0);
472 printf(
"Timedout\n");
473 }
else if(e == TCP_SOCKET_ABORTED) {
474 call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0);
477 }
else if(e == TCP_SOCKET_DATA_SENT) {
478 if(s->postdata != NULL && s->postdatalen) {
479 len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
481 s->postdatalen -= len;
483 start_timeout_timer(s);
489 start_request(
struct http_socket *s)
492 uip_ip6addr_t ip6addr;
494 char host[MAX_HOSTLEN];
495 char path[MAX_PATHLEN];
499 if(parse_url(s->url, host, &port, path)) {
501 printf(
"url %s host %s port %d path %s\n",
502 s->url, host, port, path);
505 if(s->proxy_port != 0) {
507 uip_ip6addr_copy(&ip6addr, &s->proxy_addr);
508 port = s->proxy_port;
509 }
else if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
511 if(uiplib_ip4addrconv(host, &ip4addr) != 0) {
512 ip64_addr_4to6(&ip4addr, &ip6addr);
520 puts(
"Resolving host...");
521 return HTTP_SOCKET_OK;
524 s->did_tcp_connect = 1;
525 tcp_socket_connect(&s->s, addr, port);
526 return HTTP_SOCKET_OK;
528 return HTTP_SOCKET_ERR;
532 tcp_socket_connect(&s->s, &ip6addr, port);
533 return HTTP_SOCKET_OK;
535 return HTTP_SOCKET_ERR;
548 struct http_socket *s;
549 const char *name = data;
557 char host[MAX_HOSTLEN];
558 if(s->did_tcp_connect) {
560 }
else if(parse_url(s->url, host, NULL, NULL) &&
561 strcmp(name, host) == 0) {
567 call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
572 }
else if(ev == PROCESS_EVENT_TIMER) {
573 struct http_socket *s;
574 struct etimer *timeout_timer = data;
583 if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) {
584 tcp_socket_close(&s->s);
597 static uint8_t inited = 0;
606 http_socket_init(
struct http_socket *s)
614 initialize_socket(
struct http_socket *s)
620 s->timeout_timer_started = 0;
622 tcp_socket_register(&s->s, s,
623 s->inputbuf,
sizeof(s->inputbuf),
624 s->outputbuf,
sizeof(s->outputbuf),
629 http_socket_get(
struct http_socket *s,
633 http_socket_callback_t callback,
636 initialize_socket(s);
637 strncpy(s->url, url,
sizeof(s->url));
640 s->callback = callback;
641 s->callbackptr = callbackptr;
643 s->did_tcp_connect = 0;
647 return start_request(s);
651 http_socket_post(
struct http_socket *s,
653 const void *postdata,
654 uint16_t postdatalen,
655 const char *content_type,
656 http_socket_callback_t callback,
659 initialize_socket(s);
660 strncpy(s->url, url,
sizeof(s->url));
661 s->postdata = postdata;
662 s->postdatalen = postdatalen;
663 s->content_type = content_type;
665 s->callback = callback;
666 s->callbackptr = callbackptr;
668 s->did_tcp_connect = 0;
672 return start_request(s);
676 http_socket_close(
struct http_socket *socket)
678 struct http_socket *s;
683 tcp_socket_close(&s->s);
692 http_socket_set_proxy(
struct http_socket *s,
693 const uip_ipaddr_t *addr, uint16_t port)
696 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.
#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.
uIP DNS resolver code header file.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define PROCESS_END()
Define the end of a process.
Hostname was not found in the cache.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
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.
Hostname is fresh and usable.
#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 found, but it's status has expired.
#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.