nodemcu-firmware/app/http/httpclient.c

556 lines
14 KiB
C
Raw Normal View History

/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* Martin d'Allens <martin.dallens@gmail.com> wrote this file. As long as you retain
* this notice you can do whatever you want with this stuff. If we meet some day,
* and you think this stuff is worth it, you can buy me a beer in return.
* ----------------------------------------------------------------------------
*/
/*
* FIXME: sprintf->snprintf everywhere.
* FIXME: support null characters in responses.
*/
#include "osapi.h"
#include "user_interface.h"
#include "espconn.h"
#include "mem.h"
#include "limits.h"
#include "httpclient.h"
#include "stdlib.h"
/* Internal state. */
typedef struct request_args_t {
char * hostname;
int port;
bool secure;
char * method;
char * path;
char * headers;
char * post_data;
char * buffer;
int buffer_size;
int timeout;
os_timer_t timeout_timer;
http_callback_t callback_handle;
} request_args_t;
static char * ICACHE_FLASH_ATTR esp_strdup( const char * str )
{
if ( str == NULL )
{
return(NULL);
}
char * new_str = (char *) malloc( os_strlen( str ) + 1 ); /* 1 for null character */
if ( new_str == NULL )
{
HTTPCLIENT_DEBUG( "esp_strdup: malloc error" );
return(NULL);
}
os_strcpy( new_str, str );
return(new_str);
}
static int ICACHE_FLASH_ATTR
esp_isupper( char c )
{
return(c >= 'A' && c <= 'Z');
}
static int ICACHE_FLASH_ATTR
esp_isalpha( char c )
{
return( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
}
static int ICACHE_FLASH_ATTR
esp_isspace( char c )
{
return(c == ' ' || c == '\t' || c == '\n' || c == '\12');
}
static int ICACHE_FLASH_ATTR
esp_isdigit( char c )
{
return(c >= '0' && c <= '9');
}
static int ICACHE_FLASH_ATTR http_chunked_decode( const char * chunked, char * decode )
{
int i = 0, j = 0;
int decode_size = 0;
char *str = (char *) chunked;
do
{
char * endstr;
/* [chunk-size] */
i = strtoul( str + j, NULL, 16 );
HTTPCLIENT_DEBUG( "Chunk Size:%d\r\n", i );
if ( i <= 0 )
break;
/* [chunk-size-end-ptr] */
endstr = (char *) os_strstr( str + j, "\r\n" );
/* [chunk-ext] */
j += endstr - (str + j);
/* [CRLF] */
j += 2;
/* [chunk-data] */
decode_size += i;
os_memcpy( (char *) &decode[decode_size - i], (char *) str + j, i );
j += i;
/* [CRLF] */
j += 2;
}
while ( true );
/*
*
* footer CRLF
*
*/
return(j);
}
static void ICACHE_FLASH_ATTR http_receive_callback( void * arg, char * buf, unsigned short len )
{
struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse;
if ( req->buffer == NULL )
{
return;
}
/* Let's do the equivalent of a realloc(). */
const int new_size = req->buffer_size + len;
char * new_buffer;
if ( new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *) malloc( new_size ) ) )
{
HTTPCLIENT_DEBUG( "Response too long (%d)\n", new_size );
req->buffer[0] = '\0'; /* Discard the buffer to avoid using an incomplete response. */
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#if 0
if ( req->secure )
espconn_secure_disconnect( conn );
else
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#endif
espconn_disconnect( conn );
return; /* The disconnect callback will be called. */
}
os_memcpy( new_buffer, req->buffer, req->buffer_size );
os_memcpy( new_buffer + req->buffer_size - 1 /*overwrite the null character*/, buf, len ); /* Append new data. */
new_buffer[new_size - 1] = '\0'; /* Make sure there is an end of string. */
free( req->buffer );
req->buffer = new_buffer;
req->buffer_size = new_size;
}
static void ICACHE_FLASH_ATTR http_send_callback( void * arg )
{
struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse;
if ( req->post_data == NULL )
{
HTTPCLIENT_DEBUG( "All sent\n" );
}
else
{
/* The headers were sent, now send the contents. */
HTTPCLIENT_DEBUG( "Sending request body\n" );
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#if 0
if ( req->secure )
espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
else
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#endif
espconn_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
free( req->post_data );
req->post_data = NULL;
}
}
static void ICACHE_FLASH_ATTR http_connect_callback( void * arg )
{
HTTPCLIENT_DEBUG( "Connected\n" );
struct espconn * conn = (struct espconn *) arg;
request_args_t * req = (request_args_t *) conn->reverse;
espconn_regist_recvcb( conn, http_receive_callback );
espconn_regist_sentcb( conn, http_send_callback );
char post_headers[32] = "";
if ( req->post_data != NULL ) /* If there is data then add Content-Length header. */
{
os_sprintf( post_headers, "Content-Length: %d\r\n", strlen( req->post_data ) );
}
if(req->headers == NULL) /* Avoid NULL pointer, it may cause exception */
{
req->headers = (char *)malloc(sizeof(char));
req->headers[0] = '\0';
}
char buf[69 + strlen( req->method ) + strlen( req->path ) + strlen( req->hostname ) +
strlen( req->headers ) + strlen( post_headers )];
int len = os_sprintf( buf,
"%s %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Connection: close\r\n"
"User-Agent: ESP8266\r\n"
"%s"
"%s"
"\r\n",
req->method, req->path, req->hostname, req->port, req->headers, post_headers );
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#if 0
if ( req->secure )
espconn_secure_send( conn, (uint8_t *) buf, len );
else
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#endif
espconn_send( conn, (uint8_t *) buf, len );
if(req->headers != NULL)
free( req->headers );
req->headers = NULL;
HTTPCLIENT_DEBUG( "Sending request header\n" );
}
static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
{
HTTPCLIENT_DEBUG( "Disconnected\n" );
struct espconn *conn = (struct espconn *) arg;
if ( conn == NULL )
{
return;
}
if ( conn->proto.tcp != NULL )
{
free( conn->proto.tcp );
}
if ( conn->reverse != NULL )
{
request_args_t * req = (request_args_t *) conn->reverse;
int http_status = -1;
char * body = "";
// Turn off timeout timer
os_timer_disarm( &(req->timeout_timer) );
if ( req->buffer == NULL )
{
HTTPCLIENT_DEBUG( "Buffer probably shouldn't be NULL\n" );
}
else if ( req->buffer[0] != '\0' )
{
/* FIXME: make sure this is not a partial response, using the Content-Length header. */
const char * version_1_0 = "HTTP/1.0 ";
const char * version_1_1 = "HTTP/1.1 ";
if (( os_strncmp( req->buffer, version_1_0, strlen( version_1_0 ) ) != 0 ) &&
( os_strncmp( req->buffer, version_1_1, strlen( version_1_1 ) ) != 0 ))
{
HTTPCLIENT_DEBUG( "Invalid version in %s\n", req->buffer );
}
else
{
http_status = atoi( req->buffer + strlen( version_1_0 ) );
body = (char *) os_strstr(req->buffer, "\r\n\r\n");
if (NULL == body) {
/* Find missing body */
HTTPCLIENT_DEBUG("Body shouldn't be NULL\n");
/* To avoid NULL body */
body = "";
} else {
/* Skip CR & LF */
body = body + 4;
}
if ( os_strstr( req->buffer, "Transfer-Encoding: chunked" ) )
{
int body_size = req->buffer_size - (body - req->buffer);
char chunked_decode_buffer[body_size];
os_memset( chunked_decode_buffer, 0, body_size );
/* Chuncked data */
http_chunked_decode( body, chunked_decode_buffer );
os_memcpy( body, chunked_decode_buffer, body_size );
}
}
}
if ( req->callback_handle != NULL ) /* Callback is optional. */
{
req->callback_handle( body, http_status, req->buffer );
}
if (req->buffer) {
free( req->buffer );
}
free( req->hostname );
free( req->method );
free( req->path );
free( req );
}
/* Fix memory leak. */
espconn_delete( conn );
free( conn );
}
static void ICACHE_FLASH_ATTR http_error_callback( void *arg, sint8 errType )
{
HTTPCLIENT_DEBUG( "Disconnected with error\n" );
http_disconnect_callback( arg );
}
static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg )
{
HTTPCLIENT_DEBUG( "Connection timeout\n" );
struct espconn * conn = (struct espconn *) arg;
if ( conn == NULL )
{
return;
}
if ( conn->reverse == NULL )
{
return;
}
request_args_t * req = (request_args_t *) conn->reverse;
/* Call disconnect */
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#if 0
if ( req->secure )
espconn_secure_disconnect( conn );
else
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#endif
espconn_disconnect( conn );
}
static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_t * addr, void * arg )
{
request_args_t * req = (request_args_t *) arg;
if ( addr == NULL )
{
HTTPCLIENT_DEBUG( "DNS failed for %s\n", hostname );
if ( req->callback_handle != NULL )
{
req->callback_handle( "", -1, "" );
}
free( req );
}
else
{
HTTPCLIENT_DEBUG( "DNS found %s " IPSTR "\n", hostname, IP2STR( addr ) );
struct espconn * conn = (struct espconn *) zalloc( sizeof(struct espconn) );
conn->type = ESPCONN_TCP;
conn->state = ESPCONN_NONE;
conn->proto.tcp = (esp_tcp *) zalloc( sizeof(esp_tcp) );
conn->proto.tcp->local_port = espconn_port();
conn->proto.tcp->remote_port = req->port;
conn->reverse = req;
os_memcpy( conn->proto.tcp->remote_ip, addr, 4 );
espconn_regist_connectcb( conn, http_connect_callback );
espconn_regist_disconcb( conn, http_disconnect_callback );
espconn_regist_reconcb( conn, http_error_callback );
/* Set connection timeout timer */
os_timer_disarm( &(req->timeout_timer) );
os_timer_setfn( &(req->timeout_timer), (os_timer_func_t *) http_timeout_callback, conn );
os_timer_arm( &(req->timeout_timer), req->timeout, false );
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#if 0
if ( req->secure )
{
espconn_secure_set_size( ESPCONN_CLIENT, 5120 ); /* set SSL buffer size */
espconn_secure_connect( conn );
}
else
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#endif
{
espconn_connect( conn );
}
}
}
void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool secure, const char * method, const char * path, const char * headers, const char * post_data, http_callback_t callback_handle )
{
HTTPCLIENT_DEBUG( "DNS request\n" );
request_args_t * req = (request_args_t *) zalloc( sizeof(request_args_t) );
req->hostname = esp_strdup( hostname );
req->port = port;
req->secure = secure;
req->method = esp_strdup( method );
req->path = esp_strdup( path );
req->headers = esp_strdup( headers );
req->post_data = esp_strdup( post_data );
req->buffer_size = 1;
req->buffer = (char *) malloc( 1 );
req->buffer[0] = '\0'; /* Empty string. */
req->callback_handle = callback_handle;
req->timeout = HTTP_REQUEST_TIMEOUT_MS;
ip_addr_t addr;
err_t error = espconn_gethostbyname( (struct espconn *) req, /* It seems we don't need a real espconn pointer here. */
hostname, &addr, http_dns_callback );
if ( error == ESPCONN_INPROGRESS )
{
HTTPCLIENT_DEBUG( "DNS pending\n" );
}
else if ( error == ESPCONN_OK )
{
/* Already in the local names table (or hostname was an IP address), execute the callback ourselves. */
http_dns_callback( hostname, &addr, req );
}
else
{
if ( error == ESPCONN_ARG )
{
HTTPCLIENT_DEBUG( "DNS arg error %s\n", hostname );
}else {
HTTPCLIENT_DEBUG( "DNS error code %d\n", error );
}
http_dns_callback( hostname, NULL, req ); /* Handle all DNS errors the same way. */
}
}
/*
* Parse an URL of the form http://host:port/path
* <host> can be a hostname or an IP address
* <port> is optional
*/
void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, const char * headers, const char * post_data, http_callback_t callback_handle )
{
/*
* FIXME: handle HTTP auth with http://user:pass@host/
* FIXME: get rid of the #anchor part if present.
*/
char hostname[128] = "";
int port = 80;
bool secure = false;
bool is_http = os_strncmp( url, "http://", strlen( "http://" ) ) == 0;
bool is_https = os_strncmp( url, "https://", strlen( "https://" ) ) == 0;
if ( is_http )
url += strlen( "http://" ); /* Get rid of the protocol. */
else if ( is_https )
{
port = 443;
secure = true;
url += strlen( "https://" ); /* Get rid of the protocol. */
}
else
{
HTTPCLIENT_DEBUG( "URL is not HTTP or HTTPS %s\n", url );
return;
}
char * path = os_strchr( url, '/' );
if ( path == NULL )
{
path = os_strchr( url, '\0' ); /* Pointer to end of string. */
}
char * colon = os_strchr( url, ':' );
if ( colon > path )
{
colon = NULL; /* Limit the search to characters before the path. */
}
Adds support for verifying the certificate offered by an SSL server. Squashed commit of the following: commit 4439b8c45192f6dee1222df78bbb59f74509e0ee Author: philip <philip@gladstonefamily.net> Date: Sun Mar 6 20:23:21 2016 -0500 Fix the ignore commit a07ee5acdf91286607c3e2dce128c9b8bfd7bd80 Author: philip <philip@gladstonefamily.net> Date: Sun Mar 6 20:20:41 2016 -0500 Remove uneeded stuff commit b3604ace92fc13b30161d385c354b0f1c5fe4046 Author: philip <philip@gladstonefamily.net> Date: Sun Mar 6 20:15:26 2016 -0500 Remove client cert auth commit 6e48c633569630736a986cd07a59a12de954391e Author: philip <philip@gladstonefamily.net> Date: Sun Mar 6 20:11:42 2016 -0500 More cleanup commit d40eade405ef071d0d1b60d038566b5b8f2cafa3 Author: philip <philip@gladstonefamily.net> Date: Sat Mar 5 10:56:56 2016 -0500 Move to almost working version commit 1860a2d90afa94461c53bd41251d4870d6527f9d Author: philip <philip@gladstonefamily.net> Date: Fri Mar 4 08:04:09 2016 -0500 Changed the naem to server-ca.crt commit e7a315660843273fe62943b7fe8ee6c0541dada2 Author: philip <philip@gladstonefamily.net> Date: Thu Mar 3 21:16:26 2016 -0500 Update gitignores commit 2b037d185c396209b64381399c40821c15e1840e Author: philip <philip@gladstonefamily.net> Date: Thu Mar 3 08:56:17 2016 -0500 Getting better commit 763255cffba8e279158cd7f43391a3573efdeca8 Author: philip <philip@gladstonefamily.net> Date: Wed Mar 2 22:28:21 2016 -0500 Works a bit better commit a38325d1a47dbad255cb3e681da8415e8cf699ea Author: philip <philip@gladstonefamily.net> Date: Wed Mar 2 09:11:04 2016 -0500 First building version commit 4aef13da33470ed954f2eaf5f7ac0ac3dcdf3774 Merge: 180e147 ebb0c33 Author: philip <philip@gladstonefamily.net> Date: Tue Mar 1 22:03:06 2016 -0500 Merge remote-tracking branch 'upstream/dev' into ssl-client commit 180e147c1abdcf4046ad9be9b3c1a48f4a875312 Author: philip <philip@gladstonefamily.net> Date: Sun Feb 28 21:34:21 2016 -0500 Missing files from espressif Try to imporve layout Align the file names with the contents Missing file Review comments More review coments
2016-03-07 02:25:05 +01:00
if (path - url >= sizeof(hostname)) {
HTTPCLIENT_DEBUG( "hostname is too long %s\n", url );
return;
}
if ( colon == NULL ) /* The port is not present. */
{
os_memcpy( hostname, url, path - url );
hostname[path - url] = '\0';
}
else
{
port = atoi( colon + 1 );
if ( port == 0 )
{
HTTPCLIENT_DEBUG( "Port error %s\n", url );
return;
}
os_memcpy( hostname, url, colon - url );
hostname[colon - url] = '\0';
}
if ( path[0] == '\0' ) /* Empty path is not allowed. */
{
path = "/";
}
HTTPCLIENT_DEBUG( "hostname=%s\n", hostname );
HTTPCLIENT_DEBUG( "port=%d\n", port );
HTTPCLIENT_DEBUG( "method=%s\n", method );
HTTPCLIENT_DEBUG( "path=%s\n", path );
http_raw_request( hostname, port, secure, method, path, headers, post_data, callback_handle );
}
/*
* Parse an URL of the form http://host:port/path
* <host> can be a hostname or an IP address
* <port> is optional
*/
void ICACHE_FLASH_ATTR http_post( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
{
http_request( url, "POST", headers, post_data, callback_handle );
}
void ICACHE_FLASH_ATTR http_get( const char * url, const char * headers, http_callback_t callback_handle )
{
http_request( url, "GET", headers, NULL, callback_handle );
}
void ICACHE_FLASH_ATTR http_delete( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
{
http_request( url, "DELETE", headers, post_data, callback_handle );
}
void ICACHE_FLASH_ATTR http_put( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
{
http_request( url, "PUT", headers, post_data, callback_handle );
}
void ICACHE_FLASH_ATTR http_callback_example( char * response, int http_status, char * full_response )
{
os_printf( "http_status=%d\n", http_status );
if ( http_status != HTTP_STATUS_GENERIC_ERROR )
{
os_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
os_printf( "response=%s<EOF>\n", response );
}
}