forked from tobiasschuerg/InfluxDB-Client-for-Arduino
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bcf7b07
commit 9f7f857
Showing
10 changed files
with
480 additions
and
330 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
|
||
#include "HTTPService.h" | ||
#include "Platform.h" | ||
#include "Version.h" | ||
|
||
// Uncomment bellow in case of a problem and rebuild sketch | ||
//#define INFLUXDB_CLIENT_DEBUG_ENABLE | ||
#include "util/debug.h" | ||
|
||
static const char UserAgent[] PROGMEM = "influxdb-client-arduino/" INFLUXDB_CLIENT_VERSION " (" INFLUXDB_CLIENT_PLATFORM " " INFLUXDB_CLIENT_PLATFORM_VERSION ")"; | ||
|
||
#if defined(ESP8266) | ||
bool checkMFLN(BearSSL::WiFiClientSecure *client, String url); | ||
#endif | ||
|
||
// This cannot be put to PROGMEM due to the way how it is used | ||
static const char *RetryAfter = "Retry-After"; | ||
const char *TransferEncoding = "Transfer-Encoding"; | ||
|
||
HTTPService::HTTPService(const String &serverUrl, const String &authToken, const char *certInfo, bool insecure) { | ||
_authToken = authToken; | ||
_apiURL = serverUrl; | ||
_apiURL += "/api/v2/"; | ||
bool https = serverUrl.startsWith("https"); | ||
if(https) { | ||
#if defined(ESP8266) | ||
BearSSL::WiFiClientSecure *wifiClientSec = new BearSSL::WiFiClientSecure; | ||
if (insecure) { | ||
wifiClientSec->setInsecure(); | ||
} else if(certInfo && strlen_P(certInfo) > 0) { | ||
if(strlen_P(certInfo) > 60 ) { //differentiate fingerprint and cert | ||
_cert = new BearSSL::X509List(certInfo); | ||
wifiClientSec->setTrustAnchors(_cert); | ||
} else { | ||
wifiClientSec->setFingerprint(certInfo); | ||
} | ||
} | ||
checkMFLN(wifiClientSec, serverUrl); | ||
#elif defined(ESP32) | ||
WiFiClientSecure *wifiClientSec = new WiFiClientSecure; | ||
if (insecure) { | ||
#ifndef ARDUINO_ESP32_RELEASE_1_0_4 | ||
// This works only in ESP32 SDK 1.0.5 and higher | ||
wifiClientSec->setInsecure(); | ||
#endif | ||
} else if(_certInfo && strlen_P(certInfo) > 0) { | ||
wifiClientSec->setCACert(certInfo); | ||
} | ||
#endif | ||
_wifiClient = wifiClientSec; | ||
} else { | ||
_wifiClient = new WiFiClient; | ||
} | ||
if(!_httpClient) { | ||
_httpClient = new HTTPClient; | ||
} | ||
_httpClient->setReuse(_httpOptions._connectionReuse); | ||
|
||
_httpClient->setUserAgent(FPSTR(UserAgent)); | ||
}; | ||
|
||
HTTPService::~HTTPService() { | ||
if(_httpClient) { | ||
delete _httpClient; | ||
_httpClient = nullptr; | ||
} | ||
if(_wifiClient) { | ||
delete _wifiClient; | ||
_wifiClient = nullptr; | ||
} | ||
#if defined(ESP8266) | ||
if(_cert) { | ||
delete _cert; | ||
_cert = nullptr; | ||
} | ||
#endif | ||
_lastStatusCode = 0; | ||
_lastErrorResponse = ""; | ||
} | ||
|
||
|
||
void HTTPService::setHTTPOptions(const HTTPOptions & httpOptions) { | ||
_httpOptions = httpOptions; | ||
if(!_httpClient) { | ||
_httpClient = new HTTPClient; | ||
} | ||
_httpClient->setReuse(_httpOptions._connectionReuse); | ||
_httpClient->setTimeout(_httpOptions._httpReadTimeout); | ||
#if defined(ESP32) | ||
_httpClient->setConnectTimeout(_httpOptions._httpReadTimeout); | ||
#endif | ||
} | ||
|
||
// parse URL for host and port and call probeMaxFragmentLength | ||
#if defined(ESP8266) | ||
bool checkMFLN(BearSSL::WiFiClientSecure *client, String url) { | ||
int index = url.indexOf(':'); | ||
if(index < 0) { | ||
return false; | ||
} | ||
String protocol = url.substring(0, index); | ||
int port = -1; | ||
url.remove(0, (index + 3)); // remove http:// or https:// | ||
|
||
if (protocol == "http") { | ||
// set default port for 'http' | ||
port = 80; | ||
} else if (protocol == "https") { | ||
// set default port for 'https' | ||
port = 443; | ||
} else { | ||
return false; | ||
} | ||
index = url.indexOf('/'); | ||
String host = url.substring(0, index); | ||
url.remove(0, index); // remove host | ||
// check Authorization | ||
index = host.indexOf('@'); | ||
if(index >= 0) { | ||
host.remove(0, index + 1); // remove auth part including @ | ||
} | ||
// get port | ||
index = host.indexOf(':'); | ||
if(index >= 0) { | ||
String portS = host; | ||
host = host.substring(0, index); // hostname | ||
portS.remove(0, (index + 1)); // remove hostname + : | ||
port = portS.toInt(); // get port | ||
} | ||
INFLUXDB_CLIENT_DEBUG("[D] probeMaxFragmentLength to %s:%d\n", host.c_str(), port); | ||
bool mfln = client->probeMaxFragmentLength(host, port, 1024); | ||
INFLUXDB_CLIENT_DEBUG("[D] MFLN:%s\n", mfln ? "yes" : "no"); | ||
if (mfln) { | ||
client->setBufferSizes(1024, 1024); | ||
} | ||
return mfln; | ||
} | ||
#endif //ESP8266 | ||
|
||
bool HTTPService::beforeRequest(const char *url) { | ||
if(!_httpClient->begin(*_wifiClient, url)) { | ||
_lastErrorResponse = F("begin failed"); | ||
return false; | ||
} | ||
if(_authToken.length() > 0) { | ||
_httpClient->addHeader(F("Authorization"), "Token " + _authToken); | ||
} | ||
const char * headerKeys[] = {RetryAfter, TransferEncoding} ; | ||
_httpClient->collectHeaders(headerKeys, 2); | ||
return true; | ||
} | ||
|
||
bool HTTPService::doPOST(const char *url, const char *data, const char *contentType, int expectedCode, httpResponseCallback cb) { | ||
INFLUXDB_CLIENT_DEBUG("[D] POST request - %s, data: %dbytes, type %s\n", url, strlen(data), contentType); | ||
if(!beforeRequest(url)) { | ||
return false; | ||
} | ||
if(contentType) { | ||
_httpClient->addHeader(F("Content-Type"), FPSTR(contentType)); | ||
} | ||
_lastStatusCode = _httpClient->POST((uint8_t *) data, strlen(data)); | ||
return afterRequest(expectedCode, cb); | ||
} | ||
|
||
bool HTTPService::doGET(const char *url, int expectedCode, httpResponseCallback cb) { | ||
INFLUXDB_CLIENT_DEBUG("[D] GET request - %s\n", url); | ||
if(!beforeRequest(url)) { | ||
return false; | ||
} | ||
_lastStatusCode = _httpClient->GET(); | ||
return afterRequest(expectedCode, cb, false); | ||
} | ||
|
||
bool HTTPService::afterRequest(int expectedStatusCode, httpResponseCallback cb, bool modifyLastConnStatus) { | ||
if(modifyLastConnStatus) { | ||
_lastRequestTime = millis(); | ||
INFLUXDB_CLIENT_DEBUG("[D] HTTP status code - %d\n", _lastStatusCode); | ||
_lastRetryAfter = 0; | ||
if(_lastStatusCode >= 429) { //retryable server errors | ||
if(_httpClient->hasHeader(RetryAfter)) { | ||
_lastRetryAfter = _httpClient->header(RetryAfter).toInt(); | ||
INFLUXDB_CLIENT_DEBUG("[D] Reply after - %d\n", _lastRetryAfter); | ||
} | ||
} | ||
} | ||
_lastErrorResponse = ""; | ||
bool ret = _lastStatusCode == expectedStatusCode; | ||
bool endConnection = true; | ||
if(!ret) { | ||
if(_lastStatusCode > 0) { | ||
_lastErrorResponse = _httpClient->getString(); | ||
INFLUXDB_CLIENT_DEBUG("[D] Response:\n%s\n", _lastErrorResponse.c_str()); | ||
} else { | ||
_lastErrorResponse = _httpClient->errorToString(_lastStatusCode); | ||
INFLUXDB_CLIENT_DEBUG("[E] Error - %s\n", _lastErrorResponse.c_str()); | ||
} | ||
} else if(cb){ | ||
endConnection = cb(_httpClient); | ||
} | ||
if(endConnection) { | ||
_httpClient->end(); | ||
} | ||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#ifndef _HTTP_SERVICE_H_ | ||
#define _HTTP_SERVICE_H_ | ||
|
||
#include <Arduino.h> | ||
#if defined(ESP8266) | ||
# include <WiFiClientSecureBearSSL.h> | ||
# include <ESP8266HTTPClient.h> | ||
#elif defined(ESP32) | ||
# include <HTTPClient.h> | ||
#else | ||
# error "This library currently supports only ESP8266 and ESP32." | ||
#endif | ||
#include "Options.h" | ||
|
||
class Test; | ||
|
||
typedef std::function<bool(HTTPClient *client)> httpResponseCallback; | ||
extern const char *TransferEncoding; | ||
|
||
class HTTPService { | ||
friend class Test; | ||
private: | ||
// Server API URL | ||
String _apiURL; | ||
// authetication token | ||
String _authToken; | ||
// Last time in ms we made are a request to server | ||
uint32_t _lastRequestTime = 0; | ||
// HTTP status code of last request to server | ||
int _lastStatusCode = 0; | ||
// Server reponse or library error message for last failed request | ||
String _lastErrorResponse; | ||
// Underlying HTTPClient instance | ||
HTTPClient *_httpClient = nullptr; | ||
// Underlying connection object | ||
WiFiClient *_wifiClient = nullptr; | ||
// Certificate info | ||
const char *_certInfo = nullptr; | ||
#ifdef ESP8266 | ||
BearSSL::X509List *_cert = nullptr; | ||
#endif | ||
// Store retry timeout suggested by server after last request | ||
int _lastRetryAfter = 0; | ||
// HTTP options | ||
HTTPOptions _httpOptions; | ||
protected: | ||
// Sets request params | ||
bool beforeRequest(const char *url); | ||
// Handles response | ||
bool afterRequest(int expectedStatusCode, httpResponseCallback cb, bool modifyLastConnStatus = true); | ||
public: | ||
HTTPService(const String &serverUrl, const String &authToken, const char *certInfo, bool insecure); | ||
~HTTPService(); | ||
// Sets custom HTTP options. See HTTPOptions doc for more info. | ||
// Must be called before calling any method initiating a connection to server. | ||
// Example: | ||
// service.setHTTPOptions(HTTPOptions().httpReadTimeout(20000)). | ||
void setHTTPOptions(const HTTPOptions &httpOptions); | ||
HTTPOptions &getHTTPOptions() { return _httpOptions; } | ||
// Performs HTTP POST by sending data. On success calls response call back | ||
bool doPOST(const char *url, const char *data, const char *contentType, int expectedCode, httpResponseCallback cb); | ||
// Performs HTTP GET. On success calls response call back | ||
bool doGET(const char *url, int expectedCode, httpResponseCallback cb); | ||
|
||
String getServerAPIURL() const { return _apiURL; } | ||
int getLastRetryAfter() const { return _lastRetryAfter; } | ||
int getLastStatusCode() const { return _lastStatusCode; } | ||
uint32_t getLastRequestTime() const { return _lastRequestTime; } | ||
// Returns last response when operation failed | ||
String getLastErrorMessage() const { return _lastErrorResponse; } | ||
}; | ||
|
||
#endif //_HTTP_SERVICE_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.