diff --git a/cores/esp8266/StreamString.cpp b/cores/esp8266/StreamString.cpp new file mode 100644 index 000000000..9aace2b47 --- /dev/null +++ b/cores/esp8266/StreamString.cpp @@ -0,0 +1,68 @@ +/** + StreamString.cpp + + Copyright (c) 2015 Markus Sattler. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + */ + +#include +#include "StreamString.h" + +size_t StreamString::write(const uint8_t *buffer, size_t size) { + if(reserve(length() + size + 1)) { + for(size_t i = 0; i < size; i++) { + if(write(*buffer)) { + buffer++; + } else { + return i; + } + } + + } + return 0; +} + +size_t StreamString::write(uint8_t data) { + return concat((char) data); +} + +int StreamString::available() { + return length(); +} + +int StreamString::read() { + if(length()) { + char c = charAt(0); + remove(0, 1); + return c; + + } + return -1; +} + +int StreamString::peek() { + if(length()) { + char c = charAt(0); + return c; + } + return -1; +} + +void StreamString::flush() { +} + diff --git a/cores/esp8266/StreamString.h b/cores/esp8266/StreamString.h new file mode 100644 index 000000000..4f9f458ae --- /dev/null +++ b/cores/esp8266/StreamString.h @@ -0,0 +1,40 @@ +/** + StreamString.h + + Copyright (c) 2015 Markus Sattler. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef STREAMSTRING_H_ +#define STREAMSTRING_H_ + + +class StreamString: public Stream, public String { + + size_t write(const uint8_t *buffer, size_t size); + size_t write(uint8_t data); + + int available(); + int read(); + int peek(); + void flush(); + +}; + + +#endif /* STREAMSTRING_H_ */ diff --git a/cores/esp8266/debug.h b/cores/esp8266/debug.h index 9cf5980ef..98bdaf03c 100644 --- a/cores/esp8266/debug.h +++ b/cores/esp8266/debug.h @@ -4,7 +4,7 @@ #include #include -#define DEBUGV(...) ets_printf(__VA_ARGS__) +//#define DEBUGV(...) ets_printf(__VA_ARGS__) #ifndef DEBUGV #define DEBUGV(...) diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index f4dfae09d..283fa1057 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -97,6 +97,7 @@ class ClientContext { close(); if(_discard_cb) _discard_cb(_discard_cb_arg, this); + DEBUGV(":del\r\n"); delete this; } } diff --git a/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino new file mode 100644 index 000000000..15526e096 --- /dev/null +++ b/libraries/ESP8266httpClient/examples/BasicHttpClient/BasicHttpClient.ino @@ -0,0 +1,68 @@ +/** + * BasicHttpClient.ino + * + * Created on: 24.05.2015 + * + */ + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +ESP8266WiFiMulti WiFiMulti; + +void setup() { + + USE_SERIAL.begin(115200); + // USE_SERIAL.setDebugOutput(true); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if((WiFiMulti.run() == WL_CONNECTED)) { + + httpClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url + //http.begin("192.168.1.12", 443, "/test.html", true, "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS + http.begin("192.168.1.12", 80, "/test.html"); //HTTP + + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + if(httpCode) { + // HTTP header has been send and Server response header has been handled + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == 200) { + String payload = http.getString(); + USE_SERIAL.println(payload); + } + } else { + USE_SERIAL.print("[HTTP] GET... failed, no connection or no HTTP server\n"); + } + } + + delay(10000); +} + diff --git a/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino new file mode 100644 index 000000000..43b6d4d8b --- /dev/null +++ b/libraries/ESP8266httpClient/examples/StreamHttpClient/StreamHttpClient.ino @@ -0,0 +1,98 @@ +/** + * StreamHttpClient.ino + * + * Created on: 24.05.2015 + * + */ + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +ESP8266WiFiMulti WiFiMulti; + +void setup() { + + USE_SERIAL.begin(115200); + // USE_SERIAL.setDebugOutput(true); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if((WiFiMulti.run() == WL_CONNECTED)) { + + httpClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url + http.begin("192.168.1.12", 80, "/test.html"); + + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + if(httpCode) { + // HTTP header has been send and Server response header has been handled + + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == 200) { + + // get lenght of document (is -1 when Server sends no Content-Length header) + int len = http.getSize(); + + // create buffer for read + uint8_t buff[128] = { 0 }; + + // get tcp stream + WiFiClient * stream = http.getStreamPtr(); + + // read all data from server + while(http.connected() && (len > 0 || len == -1)) { + // get available data size + size_t size = stream->available(); + + if(size) { + // read up to 128 byte + int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write it to Serial + USE_SERIAL.write(buff, c); + + if(len > 0) { + len -= c; + } + } + delay(1); + } + + USE_SERIAL.println(); + USE_SERIAL.print("[HTTP] connection closed or file end.\n"); + + } + } else { + USE_SERIAL.print("[HTTP] GET... failed, no connection or no HTTP server\n"); + } + } + + delay(10000); +} + diff --git a/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino b/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino new file mode 100644 index 000000000..4610cb972 --- /dev/null +++ b/libraries/ESP8266httpClient/examples/reuseConnection/reuseConnection.ino @@ -0,0 +1,65 @@ +/** + * reuseConnection.ino + * + * Created on: 22.11.2015 + * + */ + + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +ESP8266WiFiMulti WiFiMulti; + +httpClient http; + +void setup() { + + USE_SERIAL.begin(115200); + // USE_SERIAL.setDebugOutput(true); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + WiFiMulti.addAP("SSID", "PASSWORD"); + + +} + +void loop() { + // wait for WiFi connection + if((WiFiMulti.run() == WL_CONNECTED)) { + + http.begin("192.168.1.12", 80, "/test.html"); + + int httpCode = http.GET(); + if(httpCode) { + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == 200) { + http.writeToStream(&USE_SERIAL); + } + } else { + USE_SERIAL.print("[HTTP] GET... failed, no connection or no HTTP server\n"); + } + } + + delay(1000); +} + + + diff --git a/libraries/ESP8266httpClient/library.properties b/libraries/ESP8266httpClient/library.properties new file mode 100644 index 000000000..55110c143 --- /dev/null +++ b/libraries/ESP8266httpClient/library.properties @@ -0,0 +1,9 @@ +name=ESP8266httpClient +version=1.0 +author=Markus Sattler +maintainer=Markus Sattler +sentence=http Client for ESP8266 +paragraph= +category=Communication +url=https://github.com/Links2004/Arduino/tree/libraries/ESP8266httpClient +architectures=esp8266 diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp new file mode 100644 index 000000000..69becd195 --- /dev/null +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.cpp @@ -0,0 +1,508 @@ +/** + * ESP8266httpClient.cpp + * + * Created on: 02.11.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP8266httpClient for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include "ESP8266httpClient.h" + +/** + * constractor + */ +httpClient::httpClient() { + _tcp = NULL; + _tcps = NULL; + + _reuse = false; + + _headerKeysCount = 0; + _currentHeaders = NULL; + + _returnCode = 0; + _size = -1; + _canReuse = false; + +} + +/** + * deconstractor + */ +httpClient::~httpClient() { + + if(_tcps) { + _tcps->stop(); + _tcps->~WiFiClientSecure(); + _tcps = NULL; + _tcp = NULL; + } else if(_tcp) { + _tcp->stop(); + _tcp->~WiFiClient(); + _tcp = NULL; + } + + if(_currentHeaders) { + delete[] _currentHeaders; + } +} + +/** + * begin + * @param host const char * + * @param port uint16_t + * @param url const char * + * @param https bool + * @param httpsFingerprint const char * + */ +void httpClient::begin(const char *host, uint16_t port, const char * url, bool https, const char * httpsFingerprint) { + + DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port:%d url: %s https: %d httpsFingerprint: %s\n", host, port, url, https, httpsFingerprint); + + _host = host; + _port = port; + _url = url; + _https = https; + _httpsFingerprint = httpsFingerprint; + + _returnCode = 0; + _size = -1; + + _Headers = ""; + +} + +void httpClient::begin(String host, uint16_t port, String url, bool https, String httpsFingerprint) { + begin(host.c_str(), port, url.c_str(), https, httpsFingerprint.c_str()); +} + +/** + * end + * called after the payload is handled + */ +void httpClient::end(void) { + if(connected()) { + if(_reuse && _canReuse) { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n"); + } else { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop\n"); + _tcp->stop(); + } + } else { + DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp is closed\n"); + } +} + +/** + * connected + * @return connected status + */ +bool httpClient::connected() { + if(_tcp) { + return (_tcp->connected() || (_tcp->available() > 0)); + } + return false; +} + + +/** + * try to reuse the connection to the server + * keep-alive + * @param reuse bool + */ +void httpClient::setReuse(bool reuse) { + _reuse = reuse; +} + +/** + * send a GET request + * @return http code + */ +int httpClient::GET() { + return sendRequest("GET"); +} + +/** + * sends a post request to the server + * @param payload uint8_t * + * @param size size_t + * @return http code + */ +int httpClient::POST(uint8_t * payload, size_t size) { + return sendRequest("POST", payload, size); +} + +int httpClient::POST(String payload) { + return POST((uint8_t *) payload.c_str(), payload.length()); +} + +/** + * sendRequest + * @param type const char * "GET", "POST", .... + * @param payload uint8_t * data for the message body if null not send + * @param size size_t size for the message body if 0 not send + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int httpClient::sendRequest(const char * type, uint8_t * payload, size_t size) { + // connect ro server + if(!connect()) { + return HTTPC_ERROR_CONNECTION_REFUSED; + } + + if(payload && size > 0) { + addHeader("Content-Length", String(size)); + } + + // send Header + if(!sendHeader(type)) { + return HTTPC_ERROR_SEND_HEADER_FAILED; + } + + // send Payload if needed + if(payload && size > 0) { + if(_tcp->write(&payload[0], size) != size) { + return HTTPC_ERROR_SEND_PAYLOAD_FAILED; + } + } + + // handle Server Response (Header) + return handleHeaderResponse(); +} + +/** + * size of message body / payload + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int httpClient::getSize(void) { + return _size; +} + +/** + * deprecated Note: this is not working with https! + * returns the stream of the tcp connection + * @return WiFiClient + */ +WiFiClient & httpClient::getStream(void) { + if(connected()) { + return *_tcp; + } + + DEBUG_HTTPCLIENT("[HTTP-Client] no stream to return!?\n"); + + // todo return error? +} + +/** + * returns the stream of the tcp connection + * @return WiFiClient * + */ +WiFiClient * httpClient::getStreamPtr(void) { + if(connected()) { + return _tcp; + } + + DEBUG_HTTPCLIENT("[HTTP-Client] no stream to return!?\n"); + return NULL; +} + +WiFiClient * getStreamPtr(void); +/** + * write all message body / payload to Stream + * @param stream Stream * + * @return bytes written ( negative values are error codes ) + */ +int httpClient::writeToStream(Stream * stream) { + + if(!stream) { + return HTTPC_ERROR_NO_STREAM; + } + + if(!connected()) { + return HTTPC_ERROR_NOT_CONNECTED; + } + + // get length of document (is -1 when Server sends no Content-Length header) + int len = _size; + int bytesWritten = 0; + + // create buffer for read + uint8_t buff[1460] = { 0 }; + + // read all data from server + while(connected() && (len > 0 || len == -1)) { + + // get available data size + size_t size = _tcp->available(); + + if(size) { + int c = _tcp->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write it to Stream + bytesWritten += stream->write(buff, c); + + if(len > 0) { + len -= c; + } + + delay(0); + } else { + delay(1); + } + } + + DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] connection closed or file end (written: %d).\n", bytesWritten); + + if(_size && _size != bytesWritten) { + DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] bytesWritten %d and size %d missmatch!.\n", bytesWritten, _size); + } + + end(); + return bytesWritten; +} + +/** + * return all payload as String (may need lot of ram or trigger out of memory!) + * @return String + */ +String httpClient::getString(void) { + StreamString sstring; + + if(_size) { + // try to reserve needed memmory + if(!sstring.reserve((_size + 1))) { + DEBUG_HTTPCLIENT("[HTTP-Client][getString] too less memory to resive as string! need: %d\n", (_size + 1)); + return String("--too less memory--"); + } + } + + writeToStream(&sstring); + return sstring; +} + + +/** + * adds Header to the request + * @param name + * @param value + * @param first + */ +void httpClient::addHeader(const String& name, const String& value, bool first) { + + String headerLine = name; + headerLine += ": "; + headerLine += value; + headerLine += "\r\n"; + + if(first) { + _Headers = headerLine + _Headers; + } else { + _Headers += headerLine; + } +} + +void httpClient::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { + _headerKeysCount = headerKeysCount; + if(_currentHeaders) + delete[] _currentHeaders; + _currentHeaders = new RequestArgument[_headerKeysCount]; + for(size_t i = 0; i < _headerKeysCount; i++) { + _currentHeaders[i].key = headerKeys[i]; + } +} + +String httpClient::header(const char* name) { + for(size_t i = 0; i < _headerKeysCount; ++i) { + if(_currentHeaders[i].key == name) + return _currentHeaders[i].value; + } + return String(); +} + +String httpClient::header(size_t i) { + if(i < _headerKeysCount) + return _currentHeaders[i].value; + return String(); +} + +String httpClient::headerName(size_t i) { + if(i < _headerKeysCount) + return _currentHeaders[i].key; + return String(); +} + +int httpClient::headers() { + return _headerKeysCount; +} + +bool httpClient::hasHeader(const char* name) { + for(size_t i = 0; i < _headerKeysCount; ++i) { + if((_currentHeaders[i].key == name) && (_currentHeaders[i].value.length() > 0)) + return true; + } + return false; +} + +/** + * init TCP connection and handle ssl verify if needed + * @return true if connection is ok + */ +bool httpClient::connect(void) { + + if(connected()) { + DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, try reuse!\n"); + return true; + } + + + if(_https) { + DEBUG_HTTPCLIENT("[HTTP-Client] connect https...\n"); + if(_tcps) { + _tcps->~WiFiClient(); + _tcps = NULL; + _tcp = NULL; + } + _tcps = new WiFiClientSecure(); + _tcp = _tcps; + } else { + DEBUG_HTTPCLIENT("[HTTP-Client] connect http...\n"); + if(_tcp) { + _tcp->~WiFiClient(); + _tcp = NULL; + } + _tcp = new WiFiClient(); + } + + if(!_tcp->connect(_host.c_str(), _port)) { + DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u.\n", _host.c_str(), _port); + return false; + } + + DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u.\n", _host.c_str(), _port); + + if(_https && _httpsFingerprint.length() > 0) { + if(_tcps->verify(_httpsFingerprint.c_str(), _host.c_str())) { + DEBUG_HTTPCLIENT("[HTTP-Client] https certificate matches\n"); + } else { + DEBUG_HTTPCLIENT("[HTTP-Client] https certificate doesn't match!\n"); + _tcp->stop(); + return false; + } + } + + // set Timeout for readBytesUntil and readStringUntil + _tcp->setTimeout(HTTPCLIENT_TCP_TIMEOUT); + +#ifdef ESP8266 + _tcp->setNoDelay(true); +#endif + return connected(); +} + +/** + * sends HTTP request header + * @param type (GET, POST, ...) + * @return status + */ +bool httpClient::sendHeader(const char * type) { + if(!connected()) { + return false; + } + String header = String(type) + " " + _url + " HTTP/1.1\r\n" + "Host: " + _host + "\r\n" + "User-Agent: ESP8266httpClient\r\n" + "Connection: "; + + if(_reuse) { + header += "keep-alive"; + } else { + header += "close"; + } + header += "\r\n" + _Headers + "\r\n"; + + return _tcp->write(header.c_str(), header.length()); +} + +/** + * reads the response from the server + * @return int http code + */ +int httpClient::handleHeaderResponse() { + + if(!connected()) { + return HTTPC_ERROR_NOT_CONNECTED; + } + + _returnCode = -1; + _size = -1; + + while(connected()) { + size_t len = _tcp->available(); + if(len > 0) { + String headerLine = _tcp->readStringUntil('\n'); + headerLine.trim(); // remove \r + + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] RX: '%s'\n", headerLine.c_str()); + + if(headerLine.startsWith("HTTP/1.")) { + _returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt(); + } else if(headerLine.indexOf(':')) { + String headerName = headerLine.substring(0, headerLine.indexOf(':')); + String headerValue = headerLine.substring(headerLine.indexOf(':') + 2); + + if(headerName.equalsIgnoreCase("Content-Length")) { + _size = headerValue.toInt(); + } + + if(headerName.equalsIgnoreCase("Connection")) { + _canReuse = headerValue.equalsIgnoreCase("keep-alive"); + } + + for(size_t i = 0; i < _headerKeysCount; i++) { + if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) { + _currentHeaders[i].value = headerValue; + break; + } + } + } + + if(headerLine == "") { + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode); + if(_size) { + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size); + } + if(_returnCode) { + return _returnCode; + } else { + DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Remote host is not an HTTP Server!"); + return HTTPC_ERROR_NO_HTTP_SERVER; + } + } + + } else { + delay(0); + } + } + + return HTTPC_ERROR_CONNECTION_LOST; +} diff --git a/libraries/ESP8266httpClient/src/ESP8266httpClient.h b/libraries/ESP8266httpClient/src/ESP8266httpClient.h new file mode 100644 index 000000000..1f3d33bd5 --- /dev/null +++ b/libraries/ESP8266httpClient/src/ESP8266httpClient.h @@ -0,0 +1,122 @@ +/** + * ESP8266httpClient.h + * + * Created on: 02.11.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP8266httpClient for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef ESP8266HTTPCLIENT_H_ +#define ESP8266HTTPCLIENT_H_ + +//#define DEBUG_HTTPCLIENT(...) Serial1.printf( __VA_ARGS__ ) + +#ifndef DEBUG_HTTPCLIENT +#define DEBUG_HTTPCLIENT(...) +#endif + +#define HTTPCLIENT_TCP_TIMEOUT (1000) + +/// HTTP client errors +#define HTTPC_ERROR_CONNECTION_REFUSED (-1) +#define HTTPC_ERROR_SEND_HEADER_FAILED (-2) +#define HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) +#define HTTPC_ERROR_NOT_CONNECTED (-4) +#define HTTPC_ERROR_CONNECTION_LOST (-5) +#define HTTPC_ERROR_NO_STREAM (-6) +#define HTTPC_ERROR_NO_HTTP_SERVER (-7) + + +class httpClient { + public: + httpClient(); + ~httpClient(); + + void begin(const char *host, uint16_t port, const char * url = "/", bool https = false, const char * httpsFingerprint = ""); + void begin(String host, uint16_t port, String url = "/", bool https = false, String httpsFingerprint = ""); + void end(void); + + bool connected(void); + + void setReuse(bool reuse); /// keep-alive + + /// request handling + int GET(); + int POST(uint8_t * payload, size_t size); + int POST(String payload); + int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0); + + void addHeader(const String& name, const String& value, bool first = false); + + /// Response handling + void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); + String header(const char* name); // get request header value by name + String header(size_t i); // get request header value by number + String headerName(size_t i); // get request header name by number + int headers(); // get header count + bool hasHeader(const char* name); // check if header exists + + + int getSize(void); + + WiFiClient & getStream(void) __attribute__ ((deprecated)) ; + WiFiClient * getStreamPtr(void); + int writeToStream(Stream * stream); + String getString(void); + + protected: + + struct RequestArgument { + String key; + String value; + }; + + + WiFiClient * _tcp; + WiFiClientSecure * _tcps; + + /// request handling + String _host; + uint16_t _port; + bool _reuse; + + + String _url; + bool _https; + String _httpsFingerprint; + + String _Headers; + + /// Response handling + RequestArgument* _currentHeaders; + size_t _headerKeysCount; + + int _returnCode; + int _size; + bool _canReuse; + + bool connect(void); + bool sendHeader(const char * type); + int handleHeaderResponse(); + +}; + + + +#endif /* ESP8266HTTPCLIENT_H_ */