Merge pull request #887 from vowstar/dev-all-in-one
Add HTTP client module and documents.
This commit is contained in:
commit
52e121f469
42
README.md
42
README.md
|
@ -289,6 +289,7 @@ Comment-out the #define statement for unused modules. Example:
|
||||||
// #define LUA_USE_MODULES_BMP085
|
// #define LUA_USE_MODULES_BMP085
|
||||||
#define LUA_USE_MODULES_TSL2561
|
#define LUA_USE_MODULES_TSL2561
|
||||||
// #define LUA_USE_MODULES_HX711
|
// #define LUA_USE_MODULES_HX711
|
||||||
|
#define LUA_USE_MODULES_HTTP
|
||||||
|
|
||||||
#endif /* LUA_USE_MODULES */
|
#endif /* LUA_USE_MODULES */
|
||||||
```
|
```
|
||||||
|
@ -628,6 +629,47 @@ json_text = cjson.encode(value)
|
||||||
-- Returns: '[true,{"foo":"bar"}]'
|
-- Returns: '[true,{"foo":"bar"}]'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
####HTTP client
|
||||||
|
```lua
|
||||||
|
-- Support HTTP and HTTPS, For example
|
||||||
|
-- HTTP POST Example with JSON header and body
|
||||||
|
http.post("http://somewhere.acceptjson.com/",
|
||||||
|
"Content-Type: application/json\r\n",
|
||||||
|
"{\"hello\":\"world\"}",
|
||||||
|
function(code, data)
|
||||||
|
print(code)
|
||||||
|
print(data)
|
||||||
|
end)
|
||||||
|
-- HTTPS GET Example with NULL header
|
||||||
|
http.get("https://www.vowstar.com/nodemcu/","",
|
||||||
|
function(code, data)
|
||||||
|
print(code)
|
||||||
|
print(data)
|
||||||
|
end)
|
||||||
|
-- You will get
|
||||||
|
-- > 200
|
||||||
|
-- hello nodemcu
|
||||||
|
-- HTTPS DELETE Example with NULL header and body
|
||||||
|
http.delete("https://10.0.0.2:443","","",
|
||||||
|
function(code, data)
|
||||||
|
print(code)
|
||||||
|
print(data)
|
||||||
|
end)
|
||||||
|
-- HTTPS PUT Example with NULL header and body
|
||||||
|
http.put("https://testput.somewhere/somewhereyouput.php","","",
|
||||||
|
function(code, data)
|
||||||
|
print(code)
|
||||||
|
print(data)
|
||||||
|
end)
|
||||||
|
-- HTTP RAW Request Example, use more HTTP/HTTPS request method
|
||||||
|
http.request("http://www.apple.com:80/library/test/success.html","GET","","",
|
||||||
|
function(code, data)
|
||||||
|
print(code)
|
||||||
|
print(data)
|
||||||
|
end)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
####Read an HX711 load cell ADC.
|
####Read an HX711 load cell ADC.
|
||||||
Note: currently only chanel A with gain 128 is supported.
|
Note: currently only chanel A with gain 128 is supported.
|
||||||
The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain.
|
The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain.
|
||||||
|
|
|
@ -41,7 +41,8 @@ SUBDIRS= \
|
||||||
cjson \
|
cjson \
|
||||||
crypto \
|
crypto \
|
||||||
dhtlib \
|
dhtlib \
|
||||||
tsl2561
|
tsl2561 \
|
||||||
|
http
|
||||||
|
|
||||||
endif # } PDIR
|
endif # } PDIR
|
||||||
|
|
||||||
|
@ -86,6 +87,7 @@ COMPONENTS_eagle.app.v6 = \
|
||||||
crypto/libcrypto.a \
|
crypto/libcrypto.a \
|
||||||
dhtlib/libdhtlib.a \
|
dhtlib/libdhtlib.a \
|
||||||
tsl2561/tsl2561lib.a \
|
tsl2561/tsl2561lib.a \
|
||||||
|
http/libhttp.a \
|
||||||
modules/libmodules.a \
|
modules/libmodules.a \
|
||||||
|
|
||||||
# Inspect the modules library and work out which modules need to be linked.
|
# Inspect the modules library and work out which modules need to be linked.
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
#############################################################
|
||||||
|
# Required variables for each makefile
|
||||||
|
# Discard this section from all parent makefiles
|
||||||
|
# Expected variables (with automatic defaults):
|
||||||
|
# CSRCS (all "C" files in the dir)
|
||||||
|
# SUBDIRS (all subdirs with a Makefile)
|
||||||
|
# GEN_LIBS - list of libs to be generated ()
|
||||||
|
# GEN_IMAGES - list of images to be generated ()
|
||||||
|
# COMPONENTS_xxx - a list of libs/objs in the form
|
||||||
|
# subdir/lib to be extracted and rolled up into
|
||||||
|
# a generated lib/image xxx.a ()
|
||||||
|
#
|
||||||
|
ifndef PDIR
|
||||||
|
GEN_LIBS = libhttp.a
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################
|
||||||
|
# Configuration i.e. compile options etc.
|
||||||
|
# Target specific stuff (defines etc.) goes in here!
|
||||||
|
# Generally values applying to a tree are captured in the
|
||||||
|
# makefile at its root level - these are then overridden
|
||||||
|
# for a subtree within the makefile rooted therein
|
||||||
|
#
|
||||||
|
#DEFINES +=
|
||||||
|
|
||||||
|
#############################################################
|
||||||
|
# Recursion Magic - Don't touch this!!
|
||||||
|
#
|
||||||
|
# Each subtree potentially has an include directory
|
||||||
|
# corresponding to the common APIs applicable to modules
|
||||||
|
# rooted at that subtree. Accordingly, the INCLUDE PATH
|
||||||
|
# of a module can only contain the include directories up
|
||||||
|
# its parent path, and not its siblings
|
||||||
|
#
|
||||||
|
# Required for each makefile to inherit from the parent
|
||||||
|
#
|
||||||
|
|
||||||
|
INCLUDES := $(INCLUDES) -I $(PDIR)include
|
||||||
|
INCLUDES += -I ./
|
||||||
|
INCLUDES += -I ./include
|
||||||
|
INCLUDES += -I ../include
|
||||||
|
INCLUDES += -I ../../include
|
||||||
|
PDIR := ../$(PDIR)
|
||||||
|
sinclude $(PDIR)Makefile
|
||||||
|
|
|
@ -0,0 +1,628 @@
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "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"
|
||||||
|
|
||||||
|
/* 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 *) os_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');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a string to a long integer.
|
||||||
|
*
|
||||||
|
* Ignores `locale' stuff. Assumes that the upper and lower case
|
||||||
|
* alphabets and digits are each contiguous.
|
||||||
|
*/
|
||||||
|
long ICACHE_FLASH_ATTR
|
||||||
|
esp_strtol( nptr, endptr, base )
|
||||||
|
const char *nptr;
|
||||||
|
|
||||||
|
|
||||||
|
char **endptr;
|
||||||
|
int base;
|
||||||
|
{
|
||||||
|
const char *s = nptr;
|
||||||
|
unsigned long acc;
|
||||||
|
int c;
|
||||||
|
unsigned long cutoff;
|
||||||
|
int neg = 0, any, cutlim;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip white space and pick up leading +/- sign if any.
|
||||||
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||||
|
* assume decimal; if base is already 16, allow 0x.
|
||||||
|
*/
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c = *s++;
|
||||||
|
}
|
||||||
|
while ( esp_isspace( c ) );
|
||||||
|
if ( c == '-' )
|
||||||
|
{
|
||||||
|
neg = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else if ( c == '+' )
|
||||||
|
c = *s++;
|
||||||
|
if ( (base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X') )
|
||||||
|
{
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
} else if ( (base == 0 || base == 2) &&
|
||||||
|
c == '0' && (*s == 'b' || *s == 'B') )
|
||||||
|
{
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 2;
|
||||||
|
}
|
||||||
|
if ( base == 0 )
|
||||||
|
base = c == '0' ? 8 : 10;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the cutoff value between legal numbers and illegal
|
||||||
|
* numbers. That is the largest legal value, divided by the
|
||||||
|
* base. An input number that is greater than this value, if
|
||||||
|
* followed by a legal input character, is too big. One that
|
||||||
|
* is equal to this value may be valid or not; the limit
|
||||||
|
* between valid and invalid numbers is then based on the last
|
||||||
|
* digit. For instance, if the range for longs is
|
||||||
|
* [-2147483648..2147483647] and the input base is 10,
|
||||||
|
* cutoff will be set to 214748364 and cutlim to either
|
||||||
|
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
|
||||||
|
* a value > 214748364, or equal but the next digit is > 7 (or 8),
|
||||||
|
* the number is too big, and we will return a range error.
|
||||||
|
*
|
||||||
|
* Set any if any `digits' consumed; make it negative to indicate
|
||||||
|
* overflow.
|
||||||
|
*/
|
||||||
|
cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
|
||||||
|
cutlim = cutoff % (unsigned long) base;
|
||||||
|
cutoff /= (unsigned long) base;
|
||||||
|
for ( acc = 0, any = 0;; c = *s++ )
|
||||||
|
{
|
||||||
|
if ( esp_isdigit( c ) )
|
||||||
|
c -= '0';
|
||||||
|
else if ( esp_isalpha( c ) )
|
||||||
|
c -= esp_isupper( c ) ? 'A' - 10 : 'a' - 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if ( c >= base )
|
||||||
|
break;
|
||||||
|
if ( any < 0 || acc > cutoff || acc == cutoff && c > cutlim )
|
||||||
|
any = -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( any < 0 )
|
||||||
|
{
|
||||||
|
acc = neg ? LONG_MIN : LONG_MAX;
|
||||||
|
/* errno = ERANGE; */
|
||||||
|
} else if ( neg )
|
||||||
|
acc = -acc;
|
||||||
|
if ( endptr != 0 )
|
||||||
|
*endptr = (char *) (any ? s - 1 : nptr);
|
||||||
|
return(acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = NULL;
|
||||||
|
/* [chunk-size] */
|
||||||
|
i = esp_strtol( str + j, endstr, 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 *) os_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. */
|
||||||
|
if ( req->secure )
|
||||||
|
espconn_secure_disconnect( conn );
|
||||||
|
else
|
||||||
|
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. */
|
||||||
|
|
||||||
|
os_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" );
|
||||||
|
if ( req->secure )
|
||||||
|
espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
|
||||||
|
else
|
||||||
|
espconn_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
|
||||||
|
os_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 *)os_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 );
|
||||||
|
|
||||||
|
if ( req->secure )
|
||||||
|
espconn_secure_send( conn, (uint8_t *) buf, len );
|
||||||
|
else
|
||||||
|
espconn_send( conn, (uint8_t *) buf, len );
|
||||||
|
if(req->headers != NULL)
|
||||||
|
os_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 )
|
||||||
|
{
|
||||||
|
os_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 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 = "HTTP/1.1 ";
|
||||||
|
if ( os_strncmp( req->buffer, version, strlen( version ) ) != 0 )
|
||||||
|
{
|
||||||
|
HTTPCLIENT_DEBUG( "Invalid version in %s\n", req->buffer );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
http_status = atoi( req->buffer + strlen( version ) );
|
||||||
|
body = (char *) os_strstr( req->buffer, "\r\n\r\n" ) + 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 );
|
||||||
|
}
|
||||||
|
os_free( req->buffer );
|
||||||
|
os_free( req->hostname );
|
||||||
|
os_free( req->method );
|
||||||
|
os_free( req->path );
|
||||||
|
os_free( req );
|
||||||
|
}
|
||||||
|
/* Fix memory leak. */
|
||||||
|
espconn_delete( conn );
|
||||||
|
os_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 */
|
||||||
|
if ( req->secure )
|
||||||
|
espconn_secure_disconnect( conn );
|
||||||
|
else
|
||||||
|
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, "" );
|
||||||
|
}
|
||||||
|
os_free( req );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HTTPCLIENT_DEBUG( "DNS found %s " IPSTR "\n", hostname, IP2STR( addr ) );
|
||||||
|
|
||||||
|
struct espconn * conn = (struct espconn *) os_malloc( sizeof(struct espconn) );
|
||||||
|
conn->type = ESPCONN_TCP;
|
||||||
|
conn->state = ESPCONN_NONE;
|
||||||
|
conn->proto.tcp = (esp_tcp *) os_malloc( 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 );
|
||||||
|
|
||||||
|
if ( req->secure )
|
||||||
|
{
|
||||||
|
espconn_secure_set_size( ESPCONN_CLIENT, 5120 ); /* set SSL buffer size */
|
||||||
|
espconn_secure_connect( conn );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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 *) os_malloc( 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 *) os_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. */
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "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.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HTTPCLIENT_H__
|
||||||
|
#define __HTTPCLIENT_H__
|
||||||
|
|
||||||
|
#if defined(GLOBAL_DEBUG_ON)
|
||||||
|
#define HTTPCLIENT_DEBUG_ON
|
||||||
|
#endif
|
||||||
|
#if defined(HTTPCLIENT_DEBUG_ON)
|
||||||
|
#define HTTPCLIENT_DEBUG(format, ...) os_printf(format, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define HTTPCLIENT_DEBUG(format, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USES_SDK_BEFORE_V140)
|
||||||
|
#define espconn_send espconn_sent
|
||||||
|
#define espconn_secure_send espconn_secure_sent
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case of TCP or DNS error the callback is called with this status.
|
||||||
|
*/
|
||||||
|
#define HTTP_STATUS_GENERIC_ERROR (-1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of http responses that will cause an error.
|
||||||
|
*/
|
||||||
|
#define BUFFER_SIZE_MAX (1024)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timeout of http request.
|
||||||
|
*/
|
||||||
|
#define HTTP_REQUEST_TIMEOUT_MS (10000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "full_response" is a string containing all response headers and the response body.
|
||||||
|
* "response_body and "http_status" are extracted from "full_response" for convenience.
|
||||||
|
*
|
||||||
|
* A successful request corresponds to an HTTP status code of 200 (OK).
|
||||||
|
* More info at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
|
||||||
|
*/
|
||||||
|
typedef void (* http_callback_t)(char * response_body, int http_status, char * full_response);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call this function to skip URL parsing if the arguments are already in separate variables.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request data from URL use custom method.
|
||||||
|
* The data should be encoded as any format.
|
||||||
|
* Try:
|
||||||
|
* http_request("http://httpbin.org/post", "OPTIONS", "Content-type: text/plain", "Hello world", http_callback_example);
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR http_request(const char * url, const char * method, const char * headers, const char * post_data, http_callback_t callback_handle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Post data to a web form.
|
||||||
|
* The data should be encoded as any format.
|
||||||
|
* Try:
|
||||||
|
* http_post("http://httpbin.org/post", "Content-type: application/json", "{\"hello\": \"world\"}", http_callback_example);
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR http_post(const char * url, const char * headers, const char * post_data, http_callback_t callback_handle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Download a web page from its URL.
|
||||||
|
* Try:
|
||||||
|
* http_get("http://wtfismyip.com/text", NULL, http_callback_example);
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR http_get(const char * url, const char * headers, http_callback_t callback_handle);
|
||||||
|
/*
|
||||||
|
* Delete a web page from its URL.
|
||||||
|
* Try:
|
||||||
|
* http_delete("http://wtfismyip.com/text", NULL, http_callback_example);
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR http_delete(const char * url, const char * headers, const char * post_data, http_callback_t callback_handle);
|
||||||
|
/*
|
||||||
|
* Update data to a web form.
|
||||||
|
* The data should be encoded as any format.
|
||||||
|
* Try:
|
||||||
|
* http_put("http://httpbin.org/post", "Content-type: application/json", "{\"hello\": \"world\"}", http_callback_example);
|
||||||
|
*/
|
||||||
|
void ICACHE_FLASH_ATTR http_put(const char * url, const char * headers, const char * post_data, http_callback_t callback_handle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output on the UART.
|
||||||
|
*/
|
||||||
|
void http_callback_example(char * response, int http_status, char * full_response);
|
||||||
|
|
||||||
|
#endif // __HTTPCLIENT_H__
|
|
@ -23,6 +23,7 @@
|
||||||
//#define LUA_USE_MODULES_ENDUSER_SETUP // USE_DNS in dhcpserver.h needs to be enabled for this module to work.
|
//#define LUA_USE_MODULES_ENDUSER_SETUP // USE_DNS in dhcpserver.h needs to be enabled for this module to work.
|
||||||
#define LUA_USE_MODULES_FILE
|
#define LUA_USE_MODULES_FILE
|
||||||
#define LUA_USE_MODULES_GPIO
|
#define LUA_USE_MODULES_GPIO
|
||||||
|
#define LUA_USE_MODULES_HTTP
|
||||||
//#define LUA_USE_MODULES_HX711
|
//#define LUA_USE_MODULES_HX711
|
||||||
#define LUA_USE_MODULES_I2C
|
#define LUA_USE_MODULES_I2C
|
||||||
#define LUA_USE_MODULES_MQTT
|
#define LUA_USE_MODULES_MQTT
|
||||||
|
|
|
@ -50,6 +50,7 @@ INCLUDES += -I ../spiffs
|
||||||
INCLUDES += -I ../smart
|
INCLUDES += -I ../smart
|
||||||
INCLUDES += -I ../cjson
|
INCLUDES += -I ../cjson
|
||||||
INCLUDES += -I ../dhtlib
|
INCLUDES += -I ../dhtlib
|
||||||
|
INCLUDES += -I ../http
|
||||||
PDIR := ../$(PDIR)
|
PDIR := ../$(PDIR)
|
||||||
sinclude $(PDIR)Makefile
|
sinclude $(PDIR)Makefile
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* HTTP module for NodeMCU
|
||||||
|
* vowstar@gmail.com
|
||||||
|
* 2015-12-29
|
||||||
|
*******************************************************************************/
|
||||||
|
#include "module.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "cpu_esp8266.h"
|
||||||
|
#include "httpclient.h"
|
||||||
|
|
||||||
|
static int http_callback_registry = LUA_NOREF;
|
||||||
|
static lua_State * http_client_L = NULL;
|
||||||
|
|
||||||
|
static void http_callback( char * response, int http_status, char * full_response )
|
||||||
|
{
|
||||||
|
#if defined(HTTPCLIENT_DEBUG_ON)
|
||||||
|
c_printf( "http_status=%d\n", http_status );
|
||||||
|
if ( http_status != HTTP_STATUS_GENERIC_ERROR )
|
||||||
|
{
|
||||||
|
c_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
|
||||||
|
c_printf( "response=%s<EOF>\n", response );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (http_callback_registry != LUA_NOREF)
|
||||||
|
{
|
||||||
|
lua_rawgeti(http_client_L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
|
||||||
|
lua_pushnumber(http_client_L, http_status);
|
||||||
|
if ( http_status != HTTP_STATUS_GENERIC_ERROR )
|
||||||
|
{
|
||||||
|
lua_pushstring(http_client_L, response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_pushnil(http_client_L);
|
||||||
|
}
|
||||||
|
lua_call(http_client_L, 2, 0); // With 2 arguments and 0 result
|
||||||
|
|
||||||
|
luaL_unref(http_client_L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
http_callback_registry = LUA_NOREF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lua: http.request( url, method, header, body, function(status, reponse) end )
|
||||||
|
static int http_lapi_request( lua_State *L )
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
http_client_L = L;
|
||||||
|
const char * url = luaL_checklstring(L, 1, &length);
|
||||||
|
const char * method = luaL_checklstring(L, 2, &length);
|
||||||
|
const char * headers = NULL;
|
||||||
|
const char * body = NULL;
|
||||||
|
|
||||||
|
// Check parameter
|
||||||
|
if ((url == NULL) || (method == NULL))
|
||||||
|
{
|
||||||
|
return luaL_error( L, "wrong arg type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isstring(L, 3))
|
||||||
|
{
|
||||||
|
headers = luaL_checklstring(L, 3, &length);
|
||||||
|
}
|
||||||
|
if (lua_isstring(L, 4))
|
||||||
|
{
|
||||||
|
body = luaL_checklstring(L, 4, &length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, 5) == LUA_TFUNCTION || lua_type(L, 5) == LUA_TLIGHTFUNCTION) {
|
||||||
|
lua_pushvalue(L, 5); // copy argument (func) to the top of stack
|
||||||
|
if (http_callback_registry != LUA_NOREF)
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
http_callback_registry = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
http_request(url, method, headers, body, http_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lua: http.post( url, header, body, function(status, reponse) end )
|
||||||
|
static int http_lapi_post( lua_State *L )
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
http_client_L = L;
|
||||||
|
const char * url = luaL_checklstring(L, 1, &length);
|
||||||
|
const char * headers = NULL;
|
||||||
|
const char * body = NULL;
|
||||||
|
|
||||||
|
// Check parameter
|
||||||
|
if ((url == NULL))
|
||||||
|
{
|
||||||
|
return luaL_error( L, "wrong arg type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isstring(L, 2))
|
||||||
|
{
|
||||||
|
headers = luaL_checklstring(L, 2, &length);
|
||||||
|
}
|
||||||
|
if (lua_isstring(L, 3))
|
||||||
|
{
|
||||||
|
body = luaL_checklstring(L, 3, &length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION) {
|
||||||
|
lua_pushvalue(L, 4); // copy argument (func) to the top of stack
|
||||||
|
if (http_callback_registry != LUA_NOREF)
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
http_callback_registry = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
http_post(url, headers, body, http_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lua: http.put( url, header, body, function(status, reponse) end )
|
||||||
|
static int http_lapi_put( lua_State *L )
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
http_client_L = L;
|
||||||
|
const char * url = luaL_checklstring(L, 1, &length);
|
||||||
|
const char * headers = NULL;
|
||||||
|
const char * body = NULL;
|
||||||
|
|
||||||
|
// Check parameter
|
||||||
|
if ((url == NULL))
|
||||||
|
{
|
||||||
|
return luaL_error( L, "wrong arg type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isstring(L, 2))
|
||||||
|
{
|
||||||
|
headers = luaL_checklstring(L, 2, &length);
|
||||||
|
}
|
||||||
|
if (lua_isstring(L, 3))
|
||||||
|
{
|
||||||
|
body = luaL_checklstring(L, 3, &length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION) {
|
||||||
|
lua_pushvalue(L, 4); // copy argument (func) to the top of stack
|
||||||
|
if (http_callback_registry != LUA_NOREF)
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
http_callback_registry = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
http_put(url, headers, body, http_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lua: http.delete( url, header, body, function(status, reponse) end )
|
||||||
|
static int http_lapi_delete( lua_State *L )
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
http_client_L = L;
|
||||||
|
const char * url = luaL_checklstring(L, 1, &length);
|
||||||
|
const char * headers = NULL;
|
||||||
|
const char * body = NULL;
|
||||||
|
|
||||||
|
// Check parameter
|
||||||
|
if ((url == NULL))
|
||||||
|
{
|
||||||
|
return luaL_error( L, "wrong arg type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isstring(L, 2))
|
||||||
|
{
|
||||||
|
headers = luaL_checklstring(L, 2, &length);
|
||||||
|
}
|
||||||
|
if (lua_isstring(L, 3))
|
||||||
|
{
|
||||||
|
body = luaL_checklstring(L, 3, &length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, 4) == LUA_TFUNCTION || lua_type(L, 4) == LUA_TLIGHTFUNCTION) {
|
||||||
|
lua_pushvalue(L, 4); // copy argument (func) to the top of stack
|
||||||
|
if (http_callback_registry != LUA_NOREF)
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
http_callback_registry = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
http_delete(url, headers, body, http_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lua: http.get( url, header, function(status, reponse) end )
|
||||||
|
static int http_lapi_get( lua_State *L )
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
http_client_L = L;
|
||||||
|
const char * url = luaL_checklstring(L, 1, &length);
|
||||||
|
const char * headers = NULL;
|
||||||
|
|
||||||
|
// Check parameter
|
||||||
|
if ((url == NULL))
|
||||||
|
{
|
||||||
|
return luaL_error( L, "wrong arg type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isstring(L, 2))
|
||||||
|
{
|
||||||
|
headers = luaL_checklstring(L, 2, &length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) {
|
||||||
|
lua_pushvalue(L, 3); // copy argument (func) to the top of stack
|
||||||
|
if (http_callback_registry != LUA_NOREF)
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, http_callback_registry);
|
||||||
|
http_callback_registry = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
http_get(url, headers, http_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module function map
|
||||||
|
static const LUA_REG_TYPE http_map[] = {
|
||||||
|
{ LSTRKEY( "request" ), LFUNCVAL( http_lapi_request ) },
|
||||||
|
{ LSTRKEY( "post" ), LFUNCVAL( http_lapi_post ) },
|
||||||
|
{ LSTRKEY( "put" ), LFUNCVAL( http_lapi_put ) },
|
||||||
|
{ LSTRKEY( "delete" ), LFUNCVAL( http_lapi_delete ) },
|
||||||
|
{ LSTRKEY( "get" ), LFUNCVAL( http_lapi_get ) },
|
||||||
|
|
||||||
|
{ LSTRKEY( "OK" ), LNUMVAL( 0 ) },
|
||||||
|
{ LSTRKEY( "ERROR" ), LNUMVAL( HTTP_STATUS_GENERIC_ERROR ) },
|
||||||
|
|
||||||
|
{ LNILKEY, LNILVAL }
|
||||||
|
};
|
||||||
|
|
||||||
|
NODEMCU_MODULE(HTTP, "http", http_map, NULL);
|
Loading…
Reference in New Issue