|
|
@ -4,39 +4,70 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include <esp8266.h> |
|
|
|
#include <esp8266.h> |
|
|
|
#include "cgi_d2d.h" |
|
|
|
#include "cgi_d2d.h" |
|
|
|
#include "apars_logging.h" |
|
|
|
|
|
|
|
#include "version.h" |
|
|
|
#include "version.h" |
|
|
|
#include "ansi_parser_callbacks.h" |
|
|
|
#include "ansi_parser_callbacks.h" |
|
|
|
|
|
|
|
#include "api.h" |
|
|
|
#include <httpclient.h> |
|
|
|
#include <httpclient.h> |
|
|
|
#include <esp_utils.h> |
|
|
|
#include <esp_utils.h> |
|
|
|
|
|
|
|
|
|
|
|
#define D2D_TIMEOUT_MS 2000 |
|
|
|
#define D2D_TIMEOUT_MS 2000 |
|
|
|
|
|
|
|
|
|
|
|
#define D2D_HEADERS \ |
|
|
|
#define D2D_HEADERS \ |
|
|
|
"User-Agent: ESPTerm "FIRMWARE_VERSION"\r\n" \
|
|
|
|
"User-Agent: ESPTerm "FIRMWARE_VERSION" like curl wget HTTPie\r\n" \
|
|
|
|
"Content-Type: text/plain; charset=utf-8\r\n" \
|
|
|
|
"Content-Type: text/plain; charset=utf-8\r\n" \
|
|
|
|
"Cache-Control: max-age=0\r\n" |
|
|
|
"Accept-Encoding: identity\r\n" \
|
|
|
|
|
|
|
|
"Accept-Charset: utf-8\r\n" \
|
|
|
|
|
|
|
|
"Accept: text/*, application/json\r\n" \
|
|
|
|
|
|
|
|
"Cache-Control: no-cache,private,max-age=0\r\n" |
|
|
|
|
|
|
|
|
|
|
|
struct d2d_request_opts { |
|
|
|
struct d2d_request_opts { |
|
|
|
bool want_body; |
|
|
|
bool want_body; |
|
|
|
bool want_head; |
|
|
|
bool want_head; |
|
|
|
|
|
|
|
size_t max_result_len; |
|
|
|
char *nonce; |
|
|
|
char *nonce; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
volatile bool request_pending = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
requestNoopCb(int http_status, |
|
|
|
|
|
|
|
char *response_headers, |
|
|
|
|
|
|
|
char *response_body, |
|
|
|
|
|
|
|
size_t body_size, |
|
|
|
|
|
|
|
void *userArg) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
request_pending = false; |
|
|
|
|
|
|
|
if (userArg != NULL) free(userArg); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR |
|
|
|
static void ICACHE_FLASH_ATTR |
|
|
|
requestCb(int http_status, |
|
|
|
requestCb(int http_status, |
|
|
|
const char *response_headers, |
|
|
|
char *response_headers, |
|
|
|
const char *response_body, |
|
|
|
char *response_body, |
|
|
|
size_t body_size, |
|
|
|
size_t body_size, |
|
|
|
void *userArg) |
|
|
|
void *userArg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (userArg == NULL) return; |
|
|
|
if (userArg == NULL) { |
|
|
|
|
|
|
|
request_pending = false; |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct d2d_request_opts *opts = userArg; |
|
|
|
struct d2d_request_opts *opts = userArg; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d2d_dbg("Rx url response, code %d, nonce \"%s\"", http_status, opts->nonce?opts->nonce:""); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ensure positive - would be hard to parse
|
|
|
|
|
|
|
|
if (http_status < 0) http_status = -http_status; |
|
|
|
|
|
|
|
|
|
|
|
char buff100[100]; |
|
|
|
char buff100[100]; |
|
|
|
int len = 0; |
|
|
|
int len = 0; |
|
|
|
if (opts->want_head) len += strlen(response_headers); |
|
|
|
size_t headers_size = strlen(response_headers); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (opts->want_head) len += headers_size; |
|
|
|
if (opts->want_body) len += body_size + (opts->want_head*2); |
|
|
|
if (opts->want_body) len += body_size + (opts->want_head*2); |
|
|
|
|
|
|
|
if (opts->max_result_len > 0 && len > opts->max_result_len) |
|
|
|
|
|
|
|
len = (int) opts->max_result_len; |
|
|
|
|
|
|
|
|
|
|
|
char *bb = buff100; |
|
|
|
char *bb = buff100; |
|
|
|
bb += sprintf(bb, "\x1b^h;%d;", http_status); |
|
|
|
bb += sprintf(bb, "\x1b^h;%d;", http_status); |
|
|
|
const char *comma = ""; |
|
|
|
const char *comma = ""; |
|
|
@ -66,24 +97,35 @@ requestCb(int http_status, |
|
|
|
|
|
|
|
|
|
|
|
apars_respond(buff100); |
|
|
|
apars_respond(buff100); |
|
|
|
|
|
|
|
|
|
|
|
d2d_dbg("Response %d, nonce \"%s\"", http_status, opts->nonce?opts->nonce:""); |
|
|
|
//d2d_dbg("Headers (part) %100s", response_headers);
|
|
|
|
d2d_dbg("Headers %s", response_headers); |
|
|
|
//d2d_dbg("Body (part) %100s", response_body);
|
|
|
|
d2d_dbg("Body %s", response_body); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// head and payload separated by \r\n\r\n (one \r\n is at the end of head - maybe)
|
|
|
|
// head and payload separated by \r\n\r\n (one \r\n is at the end of head - maybe)
|
|
|
|
if (opts->want_head) { |
|
|
|
if (opts->want_head) { |
|
|
|
|
|
|
|
// truncate
|
|
|
|
|
|
|
|
if (headers_size > len) { |
|
|
|
|
|
|
|
response_headers[len] = 0; |
|
|
|
|
|
|
|
opts->want_body = false; // soz, it wouldn't fit
|
|
|
|
|
|
|
|
} |
|
|
|
apars_respond(response_headers); |
|
|
|
apars_respond(response_headers); |
|
|
|
if(opts->want_body) apars_respond("\r\n"); |
|
|
|
if(opts->want_body) apars_respond("\r\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(opts->want_body) { |
|
|
|
if(opts->want_body) { |
|
|
|
|
|
|
|
// truncate
|
|
|
|
|
|
|
|
if (opts->want_head*(headers_size+2)+body_size > len) { |
|
|
|
|
|
|
|
response_body[len - (opts->want_head*(headers_size+2))] = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
apars_respond(response_body); |
|
|
|
apars_respond(response_body); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
apars_respond("\a"); |
|
|
|
apars_respond("\a"); |
|
|
|
|
|
|
|
|
|
|
|
free(opts->nonce); |
|
|
|
free(opts->nonce); |
|
|
|
free(userArg); |
|
|
|
free(opts); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
request_pending = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool ICACHE_FLASH_ATTR |
|
|
|
bool ICACHE_FLASH_ATTR |
|
|
@ -101,6 +143,8 @@ d2d_parse_command(char *msg) |
|
|
|
} while(0) \
|
|
|
|
} while(0) \
|
|
|
|
|
|
|
|
|
|
|
|
if (strstarts(msg, "M;")) { |
|
|
|
if (strstarts(msg, "M;")) { |
|
|
|
|
|
|
|
if (request_pending) return false; |
|
|
|
|
|
|
|
|
|
|
|
// Send a esp-esp message
|
|
|
|
// Send a esp-esp message
|
|
|
|
msg += 2; |
|
|
|
msg += 2; |
|
|
|
const char *ip; |
|
|
|
const char *ip; |
|
|
@ -108,7 +152,7 @@ d2d_parse_command(char *msg) |
|
|
|
const char *payload = msg; |
|
|
|
const char *payload = msg; |
|
|
|
|
|
|
|
|
|
|
|
d2d_dbg("D2D Tx,dest=%s,msg=%s", ip, payload); |
|
|
|
d2d_dbg("D2D Tx,dest=%s,msg=%s", ip, payload); |
|
|
|
sprintf(buff40, "http://%s" D2D_MSG_ENDPOINT, ip); |
|
|
|
sprintf(buff40, "http://%s" API_D2D_MSG, ip); |
|
|
|
|
|
|
|
|
|
|
|
httpclient_args args; |
|
|
|
httpclient_args args; |
|
|
|
httpclient_args_init(&args); |
|
|
|
httpclient_args_init(&args); |
|
|
@ -117,10 +161,14 @@ d2d_parse_command(char *msg) |
|
|
|
args.headers = D2D_HEADERS; |
|
|
|
args.headers = D2D_HEADERS; |
|
|
|
args.timeout = D2D_TIMEOUT_MS; |
|
|
|
args.timeout = D2D_TIMEOUT_MS; |
|
|
|
args.url = buff40; // "escapes scope" warning - can ignore, strdup is used
|
|
|
|
args.url = buff40; // "escapes scope" warning - can ignore, strdup is used
|
|
|
|
http_request(&args, NULL); |
|
|
|
|
|
|
|
|
|
|
|
request_pending = true; |
|
|
|
|
|
|
|
http_request(&args, requestNoopCb); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (strstarts(msg, "H;")) { |
|
|
|
else if (strstarts(msg, "H;")) { |
|
|
|
|
|
|
|
if (request_pending) return false; |
|
|
|
|
|
|
|
|
|
|
|
// Send a esp-esp message
|
|
|
|
// Send a esp-esp message
|
|
|
|
msg += 2; |
|
|
|
msg += 2; |
|
|
|
const char *method = NULL; |
|
|
|
const char *method = NULL; |
|
|
@ -128,7 +176,7 @@ d2d_parse_command(char *msg) |
|
|
|
const char *nonce = NULL; |
|
|
|
const char *nonce = NULL; |
|
|
|
const char *url = NULL; |
|
|
|
const char *url = NULL; |
|
|
|
const char *payload = NULL; |
|
|
|
const char *payload = NULL; |
|
|
|
httpd_method methodNum = HTTPD_METHOD_GET; |
|
|
|
httpd_method methodNum; |
|
|
|
|
|
|
|
|
|
|
|
FIND_NEXT(method, ';'); |
|
|
|
FIND_NEXT(method, ';'); |
|
|
|
|
|
|
|
|
|
|
@ -140,7 +188,8 @@ d2d_parse_command(char *msg) |
|
|
|
else if (streq(method, "PATCH")) methodNum = HTTPD_METHOD_PATCH; |
|
|
|
else if (streq(method, "PATCH")) methodNum = HTTPD_METHOD_PATCH; |
|
|
|
else if (streq(method, "HEAD")) methodNum = HTTPD_METHOD_HEAD; |
|
|
|
else if (streq(method, "HEAD")) methodNum = HTTPD_METHOD_HEAD; |
|
|
|
else { |
|
|
|
else { |
|
|
|
d2d_warn("BAD METHOD: %s, using GET", method); |
|
|
|
d2d_warn("BAD METHOD: %s", method); |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FIND_NEXT(params, ';'); |
|
|
|
FIND_NEXT(params, ';'); |
|
|
@ -148,7 +197,8 @@ d2d_parse_command(char *msg) |
|
|
|
d2d_dbg("Method %s", method); |
|
|
|
d2d_dbg("Method %s", method); |
|
|
|
d2d_dbg("Params %s", params); |
|
|
|
d2d_dbg("Params %s", params); |
|
|
|
|
|
|
|
|
|
|
|
size_t max_len = HTTPCLIENT_DEF_MAX_LEN; |
|
|
|
size_t max_buf_len = HTTPCLIENT_DEF_MAX_LEN; |
|
|
|
|
|
|
|
size_t max_result_len = 0; // 0 = no truncate
|
|
|
|
uint timeout = HTTPCLIENT_DEF_TIMEOUT_MS; |
|
|
|
uint timeout = HTTPCLIENT_DEF_TIMEOUT_MS; |
|
|
|
bool want_body = 0; |
|
|
|
bool want_body = 0; |
|
|
|
bool want_head = 0; |
|
|
|
bool want_head = 0; |
|
|
@ -163,8 +213,10 @@ d2d_parse_command(char *msg) |
|
|
|
if(streq(param, "H")) want_head = 1; // Return head
|
|
|
|
if(streq(param, "H")) want_head = 1; // Return head
|
|
|
|
else if(streq(param, "B")) want_body = 1; // Return body
|
|
|
|
else if(streq(param, "B")) want_body = 1; // Return body
|
|
|
|
else if(streq(param, "X")) no_resp = 1; // X - no response, no callback
|
|
|
|
else if(streq(param, "X")) no_resp = 1; // X - no response, no callback
|
|
|
|
else if(strstarts(param, "L=")) { // max length
|
|
|
|
else if(strstarts(param, "l=")) { // max buffer length
|
|
|
|
max_len = (size_t) atoi(param + 2); |
|
|
|
max_buf_len = (size_t) atoi(param + 2); |
|
|
|
|
|
|
|
} else if(strstarts(param, "L=")) { // max length
|
|
|
|
|
|
|
|
max_result_len = (size_t) atoi(param + 2); |
|
|
|
} else if(strstarts(param, "T=")) { // timeout
|
|
|
|
} else if(strstarts(param, "T=")) { // timeout
|
|
|
|
timeout = (uint) atoi(param + 2); |
|
|
|
timeout = (uint) atoi(param + 2); |
|
|
|
} else if(strstarts(param, "N=")) { // Nonce
|
|
|
|
} else if(strstarts(param, "N=")) { // Nonce
|
|
|
@ -198,18 +250,20 @@ d2d_parse_command(char *msg) |
|
|
|
args.body = payload; |
|
|
|
args.body = payload; |
|
|
|
args.headers = D2D_HEADERS; |
|
|
|
args.headers = D2D_HEADERS; |
|
|
|
args.timeout = timeout; |
|
|
|
args.timeout = timeout; |
|
|
|
args.max_response_len = max_len; |
|
|
|
args.max_response_len = max_buf_len; |
|
|
|
args.url = url; |
|
|
|
args.url = url; |
|
|
|
|
|
|
|
|
|
|
|
if (!no_resp) { |
|
|
|
if (!no_resp) { |
|
|
|
struct d2d_request_opts *opts = malloc(sizeof(struct d2d_request_opts)); |
|
|
|
struct d2d_request_opts *opts = malloc(sizeof(struct d2d_request_opts)); |
|
|
|
opts->want_body = want_body; |
|
|
|
opts->want_body = want_body; |
|
|
|
opts->want_head = want_head; |
|
|
|
opts->want_head = want_head; |
|
|
|
|
|
|
|
opts->max_result_len = max_result_len; |
|
|
|
opts->nonce = esp_strdup(nonce); |
|
|
|
opts->nonce = esp_strdup(nonce); |
|
|
|
args.userData = opts; |
|
|
|
args.userData = opts; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
http_request(&args, no_resp ? NULL : requestCb); |
|
|
|
request_pending = true; |
|
|
|
|
|
|
|
http_request(&args, no_resp ? requestNoopCb : requestCb); |
|
|
|
|
|
|
|
|
|
|
|
d2d_dbg("Done"); |
|
|
|
d2d_dbg("Done"); |
|
|
|
return true; |
|
|
|
return true; |
|
|
@ -217,3 +271,46 @@ d2d_parse_command(char *msg) |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR cgiD2DMessage(HttpdConnData *connData) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (connData->conn==NULL) { |
|
|
|
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t len = 0; |
|
|
|
|
|
|
|
if (connData->post && connData->post->buff) |
|
|
|
|
|
|
|
len = strlen(connData->post->buff); |
|
|
|
|
|
|
|
else if (connData->getArgs) |
|
|
|
|
|
|
|
len = strlen(connData->getArgs); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
len = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u8 *ip = connData->remote_ip; |
|
|
|
|
|
|
|
char buf[20]; |
|
|
|
|
|
|
|
sprintf(buf, "\x1b^m;"IPSTR";L=%d;", ip[0], ip[1], ip[2], ip[3], (int)len); |
|
|
|
|
|
|
|
apars_respond(buf); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (connData->post && connData->post->buff) |
|
|
|
|
|
|
|
apars_respond(connData->post->buff); |
|
|
|
|
|
|
|
else if (connData->getArgs) |
|
|
|
|
|
|
|
apars_respond(connData->getArgs); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
apars_respond("\a"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d2d_dbg("D2D Rx src="IPSTR",len=%d", ip[0], ip[1], ip[2], ip[3],len); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Received a msg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
httdResponseOptions(connData, 0); |
|
|
|
|
|
|
|
httdSetTransferMode(connData, HTTPD_TRANSFER_CLOSE); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
httpdStartResponse(connData, 200); |
|
|
|
|
|
|
|
httpdHeader(connData, "Content-Type", "text/plain"); |
|
|
|
|
|
|
|
httpdEndHeaders(connData); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
httpdSend(connData, "message received\r\n", -1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|