many changes :Py
This commit is contained in:
160
net/HTTP.h
Normal file
160
net/HTTP.h
Normal file
@@ -0,0 +1,160 @@
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H
|
||||
|
||||
#include "TCP.h"
|
||||
#include "../Debug.h"
|
||||
|
||||
class HTTPClient;
|
||||
|
||||
typedef void (*HTTPCBodyDataCallback)(HTTPClient* httpc, const uint8_t* data, uint16_t len);
|
||||
typedef void (*HTTPCConnectCallback)(HTTPClient* httpc);
|
||||
typedef void (*HTTPCDisconnectCallback)(HTTPClient* httpc);
|
||||
|
||||
|
||||
class HTTPClient {
|
||||
|
||||
static constexpr const char* NAME = "HTTPC";
|
||||
TCP tcp;
|
||||
|
||||
espconn dns;
|
||||
ip_addr_t ip;
|
||||
char host[64];
|
||||
char query[128];
|
||||
bool gotHeader = false;
|
||||
int numBreaks = 0;
|
||||
|
||||
HTTPCConnectCallback onConnect = nullptr;
|
||||
HTTPCDisconnectCallback onDisconnect = nullptr;
|
||||
HTTPCBodyDataCallback onBodyData = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
HTTPClient() {
|
||||
debugMod(NAME, "init()");
|
||||
tcp.setUserData(this);
|
||||
tcp.setDataCallback(_onData);
|
||||
tcp.setConnectCallback(_onConnect);
|
||||
tcp.setDisconnectCallback(_onDisconnect);
|
||||
}
|
||||
|
||||
void hold() {
|
||||
tcp.hold();
|
||||
}
|
||||
|
||||
void unhold() {
|
||||
tcp.unhold();
|
||||
}
|
||||
|
||||
void setBodyDataCallback(HTTPCBodyDataCallback c) {
|
||||
this->onBodyData = c;
|
||||
}
|
||||
|
||||
void setConnectCallback(HTTPCConnectCallback c) {
|
||||
this->onConnect = c;
|
||||
}
|
||||
|
||||
void setDisconnectCallback(HTTPCDisconnectCallback c) {
|
||||
this->onDisconnect = c;
|
||||
}
|
||||
|
||||
/** connect to the given IP/Port */
|
||||
void connect(const char* url) {
|
||||
//strcpy(this->url, url);
|
||||
|
||||
const char* hostStart = &url[7]; // skip the "http://"
|
||||
const char* hostEnd = strchr(hostStart, '/'); // find the terminating /
|
||||
strncpy(this->host, hostStart, hostEnd-hostStart); // hostname only
|
||||
this->host[hostEnd-hostStart] = 0; // 0 terminator!!
|
||||
strcpy(this->query, hostEnd); // query only
|
||||
|
||||
debugMod3(NAME, "connect(%s) -> host: '%s' query: '%s'", url, this->host, this->query);
|
||||
|
||||
resolveHost(this->host);
|
||||
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
tcp.disconnect();
|
||||
gotHeader = false;
|
||||
numBreaks = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** from TCP: connected */
|
||||
static void _onConnect(TCP* tcp) {
|
||||
debugMod(NAME, "connected");
|
||||
HTTPClient* httpc = (HTTPClient*) tcp->getUserData();
|
||||
if (httpc->onConnect) {httpc->onConnect(httpc);}
|
||||
httpc->sendRequest();
|
||||
}
|
||||
|
||||
/** from TCP: disconnected */
|
||||
static void _onDisconnect(TCP* tcp) {
|
||||
debugMod(NAME, "disconnected");
|
||||
HTTPClient* httpc = (HTTPClient*) tcp->getUserData();
|
||||
if (httpc->onDisconnect) {httpc->onDisconnect(httpc);}
|
||||
}
|
||||
|
||||
/** from TCP: got data */
|
||||
static void _onData(TCP* tcp, const uint8_t* data, const uint16_t dataLen) {
|
||||
HTTPClient* httpc = (HTTPClient*) tcp->getUserData();
|
||||
httpc->onData(data, dataLen);
|
||||
}
|
||||
|
||||
/** analyze incoming data */
|
||||
void onData(const uint8_t* data, uint16_t dataLen) {
|
||||
|
||||
// header not yet received. scan incoming data. count number of consecutive linebreaks
|
||||
if (!gotHeader) {
|
||||
while(dataLen && !gotHeader) {
|
||||
const char c = *data;
|
||||
if (c == '\r' || c == '\n') {++numBreaks;} else {numBreaks = 0;}
|
||||
if (numBreaks == 4) {
|
||||
debugMod(NAME, "got header");
|
||||
gotHeader = true;
|
||||
}
|
||||
++data; --dataLen;
|
||||
}
|
||||
}
|
||||
|
||||
// maybe we got the header now
|
||||
if (gotHeader && dataLen) {
|
||||
if (onBodyData) {
|
||||
onBodyData(this, data, dataLen);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** resolve hostname. creates callback */
|
||||
void resolveHost(const char* c) {
|
||||
debugMod1(NAME, "dns lookup: %s", c);
|
||||
dns.reverse = (void*) this;
|
||||
espconn_gethostbyname(&dns, c, &ip, _onHostResolved);
|
||||
}
|
||||
|
||||
/** send the request header */
|
||||
void sendRequest() {
|
||||
char buf[128];
|
||||
const int len = os_sprintf(buf, "GET %s HTTP/1.1\r\nicy-metadata:1\r\n\r\n", this->query);
|
||||
debugMod(NAME, buf);
|
||||
tcp.send((const uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
static void _onHostResolved(const char* name, ip_addr_t* ipaddr, void* arg ) {
|
||||
HTTPClient* http = (HTTPClient*) ((espconn*)arg)->reverse;
|
||||
if (ipaddr) {
|
||||
//debugMod1(NAME, "dns lookup returned: %s", tmp.toString());
|
||||
http->tcp.connect(IP(*ipaddr), 80);
|
||||
} else {
|
||||
debugMod1(NAME, "dns lookup failed: %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTP_H
|
||||
Reference in New Issue
Block a user