220 lines
No EOL
7.2 KiB
C++
220 lines
No EOL
7.2 KiB
C++
|
|
#include "HTTPService.h"
|
|
#include "Platform.h"
|
|
#include "Version.h"
|
|
|
|
#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(ConnectionInfo *pConnInfo):_pConnInfo(pConnInfo) {
|
|
_apiURL = pConnInfo->serverUrl;
|
|
_apiURL += "/api/v2/";
|
|
bool https = pConnInfo->serverUrl.startsWith("https");
|
|
if(https) {
|
|
#if defined(ESP8266)
|
|
BearSSL::WiFiClientSecure *wifiClientSec = new BearSSL::WiFiClientSecure;
|
|
if (pConnInfo->insecure) {
|
|
wifiClientSec->setInsecure();
|
|
} else if(pConnInfo->certInfo && strlen_P(pConnInfo->certInfo) > 0) {
|
|
if(strlen_P(pConnInfo->certInfo) > 60 ) { //differentiate fingerprint and cert
|
|
_cert = new BearSSL::X509List(pConnInfo->certInfo);
|
|
wifiClientSec->setTrustAnchors(_cert);
|
|
} else {
|
|
wifiClientSec->setFingerprint(pConnInfo->certInfo);
|
|
}
|
|
}
|
|
checkMFLN(wifiClientSec, pConnInfo->serverUrl);
|
|
#elif defined(ESP32)
|
|
WiFiClientSecure *wifiClientSec = new WiFiClientSecure;
|
|
if (pConnInfo->insecure) {
|
|
#ifndef ARDUINO_ESP32_RELEASE_1_0_4
|
|
// This works only in ESP32 SDK 1.0.5 and higher
|
|
wifiClientSec->setInsecure();
|
|
#endif
|
|
} else if(pConnInfo->certInfo && strlen_P(pConnInfo->certInfo) > 0) {
|
|
wifiClientSec->setCACert(pConnInfo->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
|
|
}
|
|
|
|
|
|
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)) {
|
|
_pConnInfo->lastError = F("begin failed");
|
|
return false;
|
|
}
|
|
if(_pConnInfo->authToken.length() > 0) {
|
|
_httpClient->addHeader(F("Authorization"), "Token " + _pConnInfo->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::doPOST(const char *url, Stream *stream, const char *contentType, int expectedCode, httpResponseCallback cb) {
|
|
INFLUXDB_CLIENT_DEBUG("[D] POST request - %s, data: %dbytes, type %s\n", url, stream->available(), contentType);
|
|
if(!beforeRequest(url)) {
|
|
return false;
|
|
}
|
|
if(contentType) {
|
|
_httpClient->addHeader(F("Content-Type"), FPSTR(contentType));
|
|
}
|
|
_lastStatusCode = _httpClient->sendRequest("POST", stream, stream->available());
|
|
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::doDELETE(const char *url, int expectedCode, httpResponseCallback cb) {
|
|
INFLUXDB_CLIENT_DEBUG("[D] DELETE - %s\n", url);
|
|
if(!beforeRequest(url)) {
|
|
return false;
|
|
}
|
|
_lastStatusCode = _httpClient->sendRequest("DELETE");
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
_pConnInfo->lastError = (char *)nullptr;
|
|
bool ret = _lastStatusCode == expectedStatusCode;
|
|
bool endConnection = true;
|
|
if(!ret) {
|
|
if(_lastStatusCode > 0) {
|
|
_pConnInfo->lastError = _httpClient->getString();
|
|
INFLUXDB_CLIENT_DEBUG("[D] Response:\n%s\n", _pConnInfo->lastError.c_str());
|
|
} else {
|
|
_pConnInfo->lastError = _httpClient->errorToString(_lastStatusCode);
|
|
INFLUXDB_CLIENT_DEBUG("[E] Error - %s\n", _pConnInfo->lastError.c_str());
|
|
}
|
|
} else if(cb){
|
|
endConnection = cb(_httpClient);
|
|
}
|
|
if(endConnection) {
|
|
_httpClient->end();
|
|
}
|
|
return ret;
|
|
} |