61#if LWIP_TCP && LWIP_CALLBACK_API
67#define HTTPC_DEBUG LWIP_DBG_OFF
71#ifndef HTTPC_DEBUG_REQUEST
72#define HTTPC_DEBUG_REQUEST 0
76#ifndef HTTPC_CLIENT_AGENT
77#define HTTPC_CLIENT_AGENT "lwIP/" LWIP_VERSION_STRING " (http://savannah.nongnu.org/projects/lwip)"
81#define HTTPC_DEBUG_TRACE (HTTPC_DEBUG | LWIP_DBG_TRACE)
82#define HTTPC_DEBUG_STATE (HTTPC_DEBUG | LWIP_DBG_STATE)
83#define HTTPC_DEBUG_WARN (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING)
84#define HTTPC_DEBUG_WARN_STATE (HTTPC_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
85#define HTTPC_DEBUG_SERIOUS (HTTPC_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
87#define HTTPC_POLL_INTERVAL 1
88#define HTTPC_POLL_TIMEOUT 30
90#define HTTPC_CONTENT_LEN_INVALID 0xFFFFFFFF
93#define HTTPC_REQ_11 "GET %s HTTP/1.1\r\n" \
94 "User-Agent: %s\r\n" \
96 "Connection: Close\r\n"
\
98#define HTTPC_REQ_11_FORMAT(uri) HTTPC_REQ_11, uri, HTTPC_CLIENT_AGENT
101#define HTTPC_REQ_11_HOST "GET %s HTTP/1.1\r\n" \
102 "User-Agent: %s\r\n" \
105 "Connection: Close\r\n" \
107#define HTTPC_REQ_11_HOST_FORMAT(uri, srv_name) HTTPC_REQ_11_HOST, uri, HTTPC_CLIENT_AGENT, srv_name
110#define HTTPC_REQ_11_PROXY "GET http://%s%s HTTP/1.1\r\n" \
111 "User-Agent: %s\r\n" \
114 "Connection: Close\r\n" \
116#define HTTPC_REQ_11_PROXY_FORMAT(host, uri, srv_name) HTTPC_REQ_11_PROXY, host, uri, HTTPC_CLIENT_AGENT, srv_name
119#define HTTPC_REQ_11_PROXY_PORT "GET http://%s:%d%s HTTP/1.1\r\n" \
120 "User-Agent: %s\r\n" \
123 "Connection: Close\r\n" \
125#define HTTPC_REQ_11_PROXY_PORT_FORMAT(host, host_port, uri, srv_name) HTTPC_REQ_11_PROXY_PORT, host, host_port, uri, HTTPC_CLIENT_AGENT, srv_name
127typedef enum ehttpc_parse_state {
128 HTTPC_PARSE_WAIT_FIRST_LINE = 0,
129 HTTPC_PARSE_WAIT_HEADERS,
131} httpc_parse_state_t;
133typedef struct _httpc_state
140 struct pbuf *rx_hdrs;
141 u16_t rx_http_version;
144 const httpc_connection_t *conn_settings;
146 u32_t rx_content_len;
147 u32_t hdr_content_len;
149#if HTTPC_DEBUG_REQUEST
157httpc_free_state(httpc_state_t* req)
161 if (req->request !=
NULL) {
165 if (req->rx_hdrs !=
NULL) {
195 if (req->conn_settings !=
NULL) {
196 if (req->conn_settings->result_fn !=
NULL) {
197 req->conn_settings->result_fn(req->callback_arg,
result, req->rx_content_len, server_response,
err);
200 return httpc_free_state(req);
207http_parse_response_status(
struct pbuf *
p,
u16_t *http_version,
u16_t *http_status,
u16_t *http_status_str_offset)
210 if (end1 != 0xFFFF) {
212 u16_t space1, space2;
214 if (space1 != 0xFFFF) {
217 size_t status_num_len;
226 if (space2 != 0xFFFF) {
227 *http_status_str_offset = space2 + 1;
228 status_num_len = space2 - space1 - 1;
230 status_num_len = end1 - space1 - 1;
232 memset(status_num, 0,
sizeof(status_num));
251 if (end1 < (0xFFFF - 2)) {
254 u16_t content_len_hdr;
256 *total_header_len = end1 + 4;
258 content_len_hdr =
pbuf_memfind(
p,
"Content-Length: ", 16, 0);
259 if (content_len_hdr != 0xFFFF) {
261 if (content_len_line_end != 0xFFFF) {
262 char content_len_num[16];
263 u16_t content_len_num_len = (
u16_t)(content_len_line_end - content_len_hdr - 16);
264 memset(content_len_num, 0,
sizeof(content_len_num));
265 if (
pbuf_copy_partial(
p, content_len_num, content_len_num_len, content_len_hdr + 16) == content_len_num_len) {
266 int len =
atoi(content_len_num);
267 if ((
len >= 0) && ((
u32_t)
len < HTTPC_CONTENT_LEN_INVALID)) {
282 httpc_state_t* req = (httpc_state_t*)
arg;
287 if (req->parse_state != HTTPC_PARSE_RX_DATA) {
289 result = HTTPC_RESULT_ERR_CLOSED;
290 }
else if ((req->hdr_content_len != HTTPC_CONTENT_LEN_INVALID) &&
291 (req->hdr_content_len != req->rx_content_len)) {
293 result = HTTPC_RESULT_ERR_CONTENT_LEN;
298 return httpc_close(req,
result, req->rx_status,
ERR_OK);
300 if (req->parse_state != HTTPC_PARSE_RX_DATA) {
301 if (req->rx_hdrs ==
NULL) {
306 if (req->parse_state == HTTPC_PARSE_WAIT_FIRST_LINE) {
307 u16_t status_str_off;
308 err_t err = http_parse_response_status(req->rx_hdrs, &req->rx_http_version, &req->rx_status, &status_str_off);
311 req->parse_state = HTTPC_PARSE_WAIT_HEADERS;
314 if (req->parse_state == HTTPC_PARSE_WAIT_HEADERS) {
315 u16_t total_header_len;
316 err_t err = http_wait_headers(req->rx_hdrs, &req->hdr_content_len, &total_header_len);
321 if (req->conn_settings) {
322 if (req->conn_settings->headers_done_fn) {
323 err = req->conn_settings->headers_done_fn(req, req->callback_arg, req->rx_hdrs, total_header_len, req->hdr_content_len);
325 return httpc_close(req, HTTPC_RESULT_LOCAL_ABORT, req->rx_status,
err);
334 req->parse_state = HTTPC_PARSE_RX_DATA;
338 if ((
p !=
NULL) && (req->parse_state == HTTPC_PARSE_RX_DATA)) {
339 req->rx_content_len +=
p->tot_len;
341 req->timeout_ticks = HTTPC_POLL_TIMEOUT;
342 if (req->recv_fn !=
NULL) {
344 return req->recv_fn(req->callback_arg, pcb,
p,
r);
357 httpc_state_t* req = (httpc_state_t*)
arg;
361 httpc_close(req, HTTPC_RESULT_ERR_CLOSED, 0,
err);
370 httpc_state_t* req = (httpc_state_t*)
arg;
373 if (req->timeout_ticks) {
374 req->timeout_ticks--;
376 if (!req->timeout_ticks) {
377 return httpc_close(req, HTTPC_RESULT_ERR_TIMEOUT, 0,
ERR_OK);
399 httpc_state_t* req = (httpc_state_t*)
arg;
404 r =
altcp_write(req->pcb, req->request->payload, req->request->len - 1, TCP_WRITE_FLAG_COPY);
407 return httpc_close(req, HTTPC_RESULT_ERR_MEM, 0,
r);
419httpc_get_internal_addr(httpc_state_t* req,
const ip_addr_t *ipaddr)
424 if (&req->remote_addr != ipaddr) {
426 req->remote_addr = *ipaddr;
429 err =
altcp_connect(req->pcb, &req->remote_addr, req->remote_port, httpc_tcp_connected);
433 LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, (
"tcp_connect failed: %d\n", (
int)
err));
444 httpc_state_t* req = (httpc_state_t*)
arg;
450 if (ipaddr !=
NULL) {
451 err = httpc_get_internal_addr(req, ipaddr);
455 result = HTTPC_RESULT_ERR_CONNECT;
457 LWIP_DEBUGF(HTTPC_DEBUG_WARN_STATE, (
"httpc_dns_found: failed to resolve hostname: %s\n",
459 result = HTTPC_RESULT_ERR_HOSTNAME;
468httpc_get_internal_dns(httpc_state_t* req,
const char*
server_name)
474 err = dns_gethostbyname(
server_name, &req->remote_addr, httpc_dns_found, req);
481 err = httpc_get_internal_addr(req, &req->remote_addr);
489httpc_create_request_string(
const httpc_connection_t *
settings,
const char*
server_name,
int server_port,
const char*
uri,
494 if (server_port != HTTP_DEFAULT_PORT) {
499 }
else if (use_host) {
509httpc_init_connection_common(httpc_state_t **connection,
const httpc_connection_t *
settings,
const char*
server_name,
514 int req_len, req_len2;
516#if HTTPC_DEBUG_REQUEST
517 size_t server_name_len, uri_len;
524 if ((req_len < 0) || (req_len > 0xFFFF)) {
528 alloc_len =
sizeof(httpc_state_t);
529#if HTTPC_DEBUG_REQUEST
532 alloc_len += server_name_len + 1 + uri_len + 1;
535 if ((mem_alloc_len < alloc_len) || (req_len + 1 > 0xFFFF)) {
543 memset(req, 0,
sizeof(httpc_state_t));
544 req->timeout_ticks = HTTPC_POLL_TIMEOUT;
546 if (req->request ==
NULL) {
547 httpc_free_state(req);
550 if (req->request->next !=
NULL) {
552 httpc_free_state(req);
555 req->hdr_content_len = HTTPC_CONTENT_LEN_INVALID;
556#if HTTPC_DEBUG_REQUEST
557 req->server_name = (
char*)(req + 1);
561 req->uri = req->server_name + server_name_len + 1;
565 if(req->pcb ==
NULL) {
566 httpc_free_state(req);
569 req->remote_port =
settings->use_proxy ?
settings->proxy_port : server_port;
573 altcp_poll(req->pcb, httpc_tcp_poll, HTTPC_POLL_INTERVAL);
578 (
char *)req->request->payload, req_len + 1);
579 if (req_len2 != req_len) {
580 httpc_free_state(req);
584 req->recv_fn = recv_fn;
586 req->callback_arg = callback_arg;
596httpc_init_connection(httpc_state_t **connection,
const httpc_connection_t *
settings,
const char*
server_name,
599 return httpc_init_connection_common(connection,
settings,
server_name, server_port,
uri, recv_fn, callback_arg, 1);
607httpc_init_connection_addr(httpc_state_t **connection,
const httpc_connection_t *
settings,
612 if (server_addr_str ==
NULL) {
615 return httpc_init_connection_common(connection,
settings, server_addr_str, server_port,
uri,
616 recv_fn, callback_arg, 1);
635 altcp_recv_fn recv_fn,
void* callback_arg, httpc_state_t **connection)
643 uri, recv_fn, callback_arg);
649 err = httpc_get_internal_addr(req, &
settings->proxy_addr);
651 err = httpc_get_internal_addr(req, server_addr);
654 httpc_free_state(req);
658 if (connection !=
NULL) {
680 altcp_recv_fn recv_fn,
void* callback_arg, httpc_state_t **connection)
693 err = httpc_get_internal_addr(req, &
settings->proxy_addr);
698 httpc_free_state(req);
702 if (connection !=
NULL) {
708#if LWIP_HTTPC_HAVE_FILE_IO
711typedef struct _httpc_filestate
713 const char* local_file_name;
716 const httpc_connection_t *client_settings;
720static void httpc_fs_result(
void *
arg, httpc_result_t httpc_result,
u32_t rx_content_len,
725httpc_fs_init(httpc_filestate_t **filestate_out,
const char* local_file_name,
726 const httpc_connection_t *
settings,
void* callback_arg)
728 httpc_filestate_t *filestate;
729 size_t file_len, alloc_len;
732 file_len =
strlen(local_file_name);
733 alloc_len =
sizeof(httpc_filestate_t) + file_len + 1;
736 if (filestate ==
NULL) {
739 memset(filestate, 0,
sizeof(httpc_filestate_t));
740 filestate->local_file_name = (
const char *)(filestate + 1);
741 memcpy((
char *)(filestate + 1), local_file_name, file_len + 1);
742 filestate->file =
NULL;
743 filestate->client_settings =
settings;
744 filestate->callback_arg = callback_arg;
746 memcpy(&filestate->settings,
settings,
sizeof(httpc_connection_t));
747 filestate->settings.result_fn = httpc_fs_result;
749 f =
fopen(local_file_name,
"wb");
756 *filestate_out = filestate;
762httpc_fs_free(httpc_filestate_t *filestate)
764 if (filestate !=
NULL) {
765 if (filestate->file !=
NULL) {
767 filestate->file =
NULL;
775httpc_fs_result(
void *
arg, httpc_result_t httpc_result,
u32_t rx_content_len,
778 httpc_filestate_t *filestate = (httpc_filestate_t *)
arg;
779 if (filestate !=
NULL) {
780 if (filestate->client_settings->result_fn !=
NULL) {
781 filestate->client_settings->result_fn(filestate->callback_arg, httpc_result, rx_content_len,
784 httpc_fs_free(filestate);
792 httpc_filestate_t *filestate = (httpc_filestate_t*)
arg;
799 fwrite(
q->payload, 1,
q->len, filestate->file);
821 void* callback_arg,
const char* local_file_name, httpc_state_t **connection)
825 httpc_filestate_t *filestate;
829 err = httpc_fs_init(&filestate, local_file_name,
settings, callback_arg);
834 err = httpc_init_connection_addr(&req, &filestate->settings, server_addr,
port,
835 uri, httpc_fs_tcp_recv, filestate);
837 httpc_fs_free(filestate);
842 err = httpc_get_internal_addr(req, &
settings->proxy_addr);
844 err = httpc_get_internal_addr(req, server_addr);
847 httpc_fs_free(filestate);
848 httpc_free_state(req);
852 if (connection !=
NULL) {
873 void* callback_arg,
const char* local_file_name, httpc_state_t **connection)
877 httpc_filestate_t *filestate;
881 err = httpc_fs_init(&filestate, local_file_name,
settings, callback_arg);
887 uri, httpc_fs_tcp_recv, filestate);
889 httpc_fs_free(filestate);
894 err = httpc_get_internal_addr(req, &
settings->proxy_addr);
899 httpc_fs_free(filestate);
900 httpc_free_state(req);
904 if (connection !=
NULL) {
struct mke2fs_defaults settings[]
ACPI_SIZE strlen(const char *String)
#define altcp_new(allocator)
#define mem_free(ptr, bsize)
static const WCHAR version[]
void * mem_malloc(mem_size_t size_in)
#define LWIP_DEBUGF(debug, message)
#define LWIP_ERROR(message, expression, handler)
#define LWIP_ASSERT(message, assertion)
GLdouble GLdouble GLdouble r
GLdouble GLdouble GLdouble GLdouble q
#define LWIP_UNUSED_ARG(x)
u16_t pbuf_memfind(const struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset)
u16_t pbuf_memcmp(const struct pbuf *p, u16_t offset, const void *s2, u16_t n)
u8_t pbuf_get_at(const struct pbuf *p, u16_t offset)
void pbuf_cat(struct pbuf *h, struct pbuf *t)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
u8_t pbuf_free(struct pbuf *p)
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_opt_ _CRTIMP size_t __cdecl fwrite(_In_reads_bytes_(_Size *_Count) const void *_Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE *_File)
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define ipaddr_aton(cp, addr)
#define ipaddr_ntoa(ipaddr)
#define memcpy(s1, s2, n)
static DWORD64 content_length
struct pbuf * pbuf_free_header(struct pbuf *q, u16_t size)
wchar_t const *const size_t const buffer_size