/*---------------------------------------------------------------------------*/ PROCESS_THREAD(http_socket_process, ev, data) { PROCESS_BEGIN(); while(1) { PROCESS_WAIT_EVENT(); if(ev == resolv_event_found && data != NULL) { struct http_socket *s; const char *name = data; /* Either found a hostname, or not. We need to go through the list of http sockets and figure out to which connection this reply corresponds, then either restart the HTTP get, or kill it (if no hostname was found). */ for(s = list_head(socketlist); s != NULL; s = list_item_next(s)) { char host[MAX_HOSTLEN]; if(s->did_tcp_connect) { /* We already connected, ignored */ } else if(parse_url(s->url, host, NULL, NULL) && strcmp(name, host) == 0) { if(resolv_lookup(name, NULL) == RESOLV_STATUS_CACHED) { /* Hostname found, restart get. */ start_request(s); } else { /* Hostname not found, kill connection. */ call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0); removesocket(s); } } } } else if(ev == PROCESS_EVENT_TIMER) { struct http_socket *s; struct etimer *timeout_timer = data; /* * A socket time-out has occurred. We need to go through the list of HTTP * sockets and figure out to which socket this timer event corresponds, * then close this socket. */ for(s = list_head(socketlist); s != NULL; s = list_item_next(s)) { if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) { tcp_socket_close(&s->s); break; } } } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ int http_socket_close(struct http_socket *socket) { struct http_socket *s; for(s = list_head(socketlist); s != NULL; s = list_item_next(s)) { if(s == socket) { tcp_socket_close(&s->s); removesocket(s); return 1; } } return 0; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(http_socket_process, ev, data) { PROCESS_BEGIN(); while(1) { PROCESS_WAIT_EVENT(); if(ev == resolv_event_found && data != NULL) { struct http_socket *s; const char *name = data; /* Either found a hostname, or not. We need to go through the list of http sockets and figure out to which connection this reply corresponds, then either restart the HTTP get, or kill it (if no hostname was found). */ for(s = list_head(socketlist); s != NULL; s = list_item_next(s)) { char host[MAX_HOSTLEN]; if(parse_url(s->url, host, NULL, NULL) && strcmp(name, host) == 0) { if(resolv_lookup(name, 0) == RESOLV_STATUS_CACHED) { /* Hostname found, restart request. */ start_request(s); } else { /* Hostname not found, kill connection. */ call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0); removesocket(s); } } } } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ static void event(struct tcp_socket *tcps, void *ptr, tcp_socket_event_t e) { struct http_socket *s = ptr; char host[MAX_HOSTLEN]; char path[MAX_PATHLEN]; char content_lenstr[8]; uint16_t port; if(e == TCP_SOCKET_CONNECTED) { PRINTF("Connected\n"); if(parse_url(s->url, host, &port, path)) { tcp_socket_send_str(tcps, HTTP_METHOD_STR(s->method)); tcp_socket_send_str(tcps, " "); tcp_socket_send_str(tcps, path); tcp_socket_send_str(tcps, " HTTP/1.0\r\n"); tcp_socket_send_str(tcps, "Host: "); tcp_socket_send_str(tcps, host); tcp_socket_send_str(tcps, "\r\n"); if (s->method == HTTP_GET || s->method == HTTP_HEAD || s->method == HTTP_DELETE) { tcp_socket_send_str(tcps, "\r\n"); } } parse_header_init(s); } else if(e == TCP_SOCKET_DATA_SENT) { if (s->method == HTTP_POST) { if (s->post_headers_sent == 0) { if (s->connection_policy == HTTP_CONNECTION_KEEPALIVE) { tcp_socket_send_str(tcps, "Connection: Keep-Alive\r\n"); } tcp_socket_send_str(tcps, "Content-type: "); tcp_socket_send_str(tcps, s->content_type); tcp_socket_send_str(tcps, "\r\n"); snprintf(content_lenstr, sizeof(content_lenstr), "%d", s->request_datalen); tcp_socket_send_str(tcps, "Content-length: "); tcp_socket_send_str(tcps, content_lenstr); tcp_socket_send_str(tcps, "\r\n"); tcp_socket_send_str(tcps, "\r\n"); s->post_headers_sent = 1; } if (s->request_dataptr < s->request_datalen) { s->request_dataptr += tcp_socket_send(tcps, &s->request_data[s->request_dataptr], s->request_datalen - s->request_dataptr); } } } else if(e == TCP_SOCKET_CLOSED) { call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0); removesocket(s); PRINTF("Closed\n"); } else if(e == TCP_SOCKET_TIMEDOUT) { call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0); removesocket(s); PRINTF("Timedout\n"); } else if(e == TCP_SOCKET_ABORTED) { call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0); removesocket(s); PRINTF("Aborted\n"); } }
/*---------------------------------------------------------------------------*/ static int parse_header_byte(struct http_socket *s, char c) { PT_BEGIN(&s->headerpt); memset(&s->header, -1, sizeof(s->header)); /* Skip the HTTP response */ while(c != ' ') { PT_YIELD(&s->headerpt); } /* Skip the space */ PT_YIELD(&s->headerpt); /* Read three characters of HTTP status and convert to BCD */ s->header.status_code = 0; for(s->header_chars = 0; s->header_chars < 3; s->header_chars++) { s->header.status_code = s->header.status_code << 4 | (c - '0'); PT_YIELD(&s->headerpt); } if(s->header.status_code == 0x200 || s->header.status_code == 0x206) { /* Read headers until data */ while(1) { /* Skip characters until end of line */ do { while(c != '\r') { s->header_chars++; PT_YIELD(&s->headerpt); } s->header_chars++; PT_YIELD(&s->headerpt); } while(c != '\n'); s->header_chars--; PT_YIELD(&s->headerpt); if(s->header_chars == 0) { /* This was an empty line, i.e. the end of headers */ break; } /* Start of line */ s->header_chars = 0; /* Read header field */ while(c != ' ' && c != '\t' && c != ':' && c != '\r' && s->header_chars < sizeof(s->header_field) - 1) { s->header_field[s->header_chars++] = c; PT_YIELD(&s->headerpt); } s->header_field[s->header_chars] = '\0'; /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } if(c == ':') { /* Skip the colon */ s->header_chars++; PT_YIELD(&s->headerpt); /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } if(!strcmp(s->header_field, "Content-Length")) { s->header.content_length = 0; while(isdigit((int)c)) { s->header.content_length = s->header.content_length * 10 + c - '0'; s->header_chars++; PT_YIELD(&s->headerpt); } } else if(!strcmp(s->header_field, "Content-Range")) { /* Skip the bytes-unit token */ while(c != ' ' && c != '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } s->header.content_range.first_byte_pos = 0; while(isdigit((int)c)) { s->header.content_range.first_byte_pos = s->header.content_range.first_byte_pos * 10 + c - '0'; s->header_chars++; PT_YIELD(&s->headerpt); } /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } if(c == '-') { /* Skip the dash */ s->header_chars++; PT_YIELD(&s->headerpt); /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } s->header.content_range.last_byte_pos = 0; while(isdigit((int)c)) { s->header.content_range.last_byte_pos = s->header.content_range.last_byte_pos * 10 + c - '0'; s->header_chars++; PT_YIELD(&s->headerpt); } /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } if(c == '/') { /* Skip the slash */ s->header_chars++; PT_YIELD(&s->headerpt); /* Skip linear white spaces */ while(c == ' ' || c == '\t') { s->header_chars++; PT_YIELD(&s->headerpt); } if(c != '*') { s->header.content_range.instance_length = 0; while(isdigit((int)c)) { s->header.content_range.instance_length = s->header.content_range.instance_length * 10 + c - '0'; s->header_chars++; PT_YIELD(&s->headerpt); } } } } } } } /* All headers read, now read data */ call_callback(s, HTTP_SOCKET_HEADER, (void *)&s->header, sizeof(s->header)); /* Should exit the pt here to indicate that all headers have been read */ PT_EXIT(&s->headerpt); } else { if(s->header.status_code == 0x404) { puts("File not found"); } else if(s->header.status_code == 0x301 || s->header.status_code == 0x302) { puts("File moved (not handled)"); } call_callback(s, HTTP_SOCKET_ERR, (void *)&s->header, sizeof(s->header)); tcp_socket_close(&s->s); removesocket(s); PT_EXIT(&s->headerpt); } PT_END(&s->headerpt); }
/*---------------------------------------------------------------------------*/ static void event(struct tcp_socket *tcps, void *ptr, tcp_socket_event_t e) { struct http_socket *s = ptr; char host[MAX_HOSTLEN]; char path[MAX_PATHLEN]; uint16_t port; char str[42]; int len; if(e == TCP_SOCKET_CONNECTED) { puts("Connected"); if(parse_url(s->url, host, &port, path)) { tcp_socket_send_str(tcps, s->postdata != NULL ? "POST " : "GET "); tcp_socket_send_str(tcps, path); tcp_socket_send_str(tcps, " HTTP/1.1\r\n\r"); tcp_socket_send_str(tcps, "Connection: close\r\n\r"); tcp_socket_send_str(tcps, "Host: "); tcp_socket_send_str(tcps, host); tcp_socket_send_str(tcps, "\r\n\r"); if(s->postdata != NULL) { if(s->content_type) { tcp_socket_send_str(tcps, "Content-Type: "); tcp_socket_send_str(tcps, s->content_type); tcp_socket_send_str(tcps, "\r\n\r"); } tcp_socket_send_str(tcps, "Content-Length: "); sprintf(str, "%u", s->postdatalen); tcp_socket_send_str(tcps, str); tcp_socket_send_str(tcps, "\r\n\r"); } else if(s->length || s->pos > 0) { tcp_socket_send_str(tcps, "Range: bytes="); if(s->length) { if(s->pos >= 0) { sprintf(str, "%llu-%llu", s->pos, s->pos + s->length - 1); } else { sprintf(str, "-%llu", s->length); } } else { sprintf(str, "%llu-", s->pos); } tcp_socket_send_str(tcps, str); tcp_socket_send_str(tcps, "\r\n\r"); } tcp_socket_send_str(tcps, "\r\n\r"); if(s->postdata != NULL && s->postdatalen) { len = tcp_socket_send(tcps, s->postdata, s->postdatalen); s->postdata += len; s->postdatalen -= len; } } parse_header_init(s); } else if(e == TCP_SOCKET_CLOSED) { call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0); removesocket(s); puts("Closed"); } else if(e == TCP_SOCKET_TIMEDOUT) { call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0); removesocket(s); puts("Timedout"); } else if(e == TCP_SOCKET_ABORTED) { call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0); removesocket(s); puts("Aborted"); } else if(e == TCP_SOCKET_DATA_SENT) { if(s->postdata != NULL && s->postdatalen) { len = tcp_socket_send(tcps, s->postdata, s->postdatalen); s->postdata += len; s->postdatalen -= len; } else { start_timeout_timer(s); } } }
/*---------------------------------------------------------------------------*/ static void event(struct tcp_socket *tcps, void *ptr, tcp_socket_event_t e) { struct http_socket *s = ptr; char host[MAX_HOSTLEN]; char path[MAX_PATHLEN]; uint16_t port; char str[42]; int len; if(e == TCP_SOCKET_CONNECTED) { printf("Connected\n"); if(parse_url(s->url, host, &port, path)) { tcp_socket_send_str(tcps, s->postdata != NULL ? "POST " : "GET "); if(s->proxy_port != 0) { /* If we are configured to route through a proxy, we should provide the full URL as the path. */ tcp_socket_send_str(tcps, s->url); } else { tcp_socket_send_str(tcps, path); } tcp_socket_send_str(tcps, " HTTP/1.1\r\n"); tcp_socket_send_str(tcps, "Connection: close\r\n"); tcp_socket_send_str(tcps, "Host: "); /* If we have IPv6 host, add the '[' and the ']' characters to the host. As in rfc2732. */ if(memchr(host, ':', MAX_HOSTLEN)) { tcp_socket_send_str(tcps, "["); } tcp_socket_send_str(tcps, host); if(memchr(host, ':', MAX_HOSTLEN)) { tcp_socket_send_str(tcps, "]"); } tcp_socket_send_str(tcps, "\r\n"); if(s->postdata != NULL) { if(s->content_type) { tcp_socket_send_str(tcps, "Content-Type: "); tcp_socket_send_str(tcps, s->content_type); tcp_socket_send_str(tcps, "\r\n"); } tcp_socket_send_str(tcps, "Content-Length: "); sprintf(str, "%u", s->postdatalen); tcp_socket_send_str(tcps, str); tcp_socket_send_str(tcps, "\r\n"); } else if(s->length || s->pos > 0) { tcp_socket_send_str(tcps, "Range: bytes="); if(s->length) { if(s->pos >= 0) { sprintf(str, "%llu-%llu", s->pos, s->pos + s->length - 1); } else { sprintf(str, "-%llu", s->length); } } else { sprintf(str, "%llu-", s->pos); } tcp_socket_send_str(tcps, str); tcp_socket_send_str(tcps, "\r\n"); } tcp_socket_send_str(tcps, "\r\n"); if(s->postdata != NULL && s->postdatalen) { len = tcp_socket_send(tcps, s->postdata, s->postdatalen); s->postdata += len; s->postdatalen -= len; } } parse_header_init(s); } else if(e == TCP_SOCKET_CLOSED) { call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0); removesocket(s); printf("Closed\n"); } else if(e == TCP_SOCKET_TIMEDOUT) { call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0); removesocket(s); printf("Timedout\n"); } else if(e == TCP_SOCKET_ABORTED) { call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0); removesocket(s); printf("Aborted\n"); } else if(e == TCP_SOCKET_DATA_SENT) { if(s->postdata != NULL && s->postdatalen) { len = tcp_socket_send(tcps, s->postdata, s->postdatalen); s->postdata += len; s->postdatalen -= len; } else { start_timeout_timer(s); } } }