Files
ESP8266lib/net/HTTP.h
2018-09-22 15:44:26 +02:00

166 lines
3.7 KiB
C++

#ifndef HTTP_H
#define HTTP_H
#include "../Platforms.h"
#include "TCP.h"
#include "DNS.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;
DNS 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);
dns.resolveHost(this->host, _onHostResolved, (void*)this);
}
void disconnect() {
tcp.disconnect();
gotHeader = false;
numBreaks = 0;
}
void consumed(uint16_t len) {
tcp.consumed(len);
}
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:
/** send the request header */
void sendRequest() {
char buf[128];
const int len = sprintf(buf, "GET %s HTTP/1.1\r\n\r\n", this->query);
//const int len = sprintf(buf, "GET %s HTTP/1.1\r\nicy-metadata:1\r\n\r\n", this->query);
printf(buf);
//debugMod(NAME, (const char*) buf);
tcp.send((const uint8_t*)buf, len);
}
static void _onHostResolved(const char* name, const ip_addr_t* ipaddr, void* arg ) {
HTTPClient* http = (HTTPClient*) arg;
if (ipaddr) {
//debugMod1(NAME, "dns lookup returned: %s", tmp.toString());
http->tcp.connect(IP4(*ipaddr), 80);
} else {
debugMod1(NAME, "dns lookup failed: %s", name);
}
}
};
#endif // HTTP_H