From 1f4e85a09e7afa628e43df27f35279a13ee4227d Mon Sep 17 00:00:00 2001 From: iranl Date: Thu, 8 Aug 2024 12:29:48 +0200 Subject: [PATCH] Remove Solo1 support + validate HTTPS certs on HTTPS requests (#443) * Use esp_crt_bundle for HTTPS requests * Remove Solo1 support --- .github/workflows/beta.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/release.yml | 2 +- README.md | 4 +- .../BasicHttpsClient/BasicHttpsClient.ino | 57 +- lib/HTTPClient/library.properties | 2 +- lib/HTTPClient/src/HTTPClient.cpp | 2393 ++++++++--------- lib/HTTPClient/src/HTTPClient.h | 399 +-- .../WiFiClientSecure/WiFiClientSecure.ino | 52 +- lib/NetworkClientSecure/library.properties | 2 +- .../src/NetworkClientSecure.cpp | 17 +- .../src/NetworkClientSecure.h | 3 +- .../src/WiFiClientSecure.h | 2 +- lib/NetworkClientSecure/src/ssl_client.cpp | 2 +- pio_package.py | 5 - platformio.ini | 43 +- resources/how-to-flash.txt | 13 - src/Config.h | 10 - src/NukiNetwork.cpp | 50 +- src/NukiNetwork.h | 2 - src/NukiNetworkLock.cpp | 4 - src/WebCfgServer.cpp | 97 +- src/main.cpp | 18 - src/networkDevices/EthLan8720Device.cpp | 8 +- src/networkDevices/EthLan8720Device.h | 27 +- src/networkDevices/WifiDevice.h | 4 - updater/pio_package.py | 2 - updater/pio_package_pre_solo1.py | 42 - updater/platformio.ini | 21 +- 30 files changed, 1532 insertions(+), 1755 deletions(-) delete mode 100644 updater/pio_package_pre_solo1.py diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 871a703..487c952 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - board: [esp32dev, esp32-s3, esp32-c3, esp32-c6, esp32solo1] + board: [esp32dev, esp32-s3, esp32-c3, esp32-c6] build: [release] env: BOARD: ${{ matrix.board }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2df905e..01b69ac 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - board: [esp32dev, esp32-s3, esp32-c3, esp32-c6, esp32solo1] + board: [esp32dev, esp32-s3, esp32-c3, esp32-c6] build: [release, debug] env: BOARD: ${{ matrix.board }} diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f3d7f90..cb99157 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - board: [esp32dev, esp32-s3, esp32-c3, esp32-c6, esp32solo1] + board: [esp32dev, esp32-s3, esp32-c3, esp32-c6] build: [release] env: BOARD: ${{ matrix.board }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c2c01c..dd4edf4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - board: [esp32dev, esp32-s3, esp32-c3, esp32-c6, esp32solo1] + board: [esp32dev, esp32-s3, esp32-c3, esp32-c6] build: [release, debug] env: BOARD: ${{ matrix.board }} diff --git a/README.md b/README.md index d475e9b..c8636b3 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,12 @@ Feel free to join us on Discord: https://discord.gg/9nPq85bP4p ## Supported devices Supported ESP32 devices: -- Nuki Hub is compiled against all ESP32 models with Wi-Fi and Bluetooh Low Energy (BLE) which are supported by ESP-IDF 5.1.4 and Arduino Core 3.0.1. +- Nuki Hub is compiled against all ESP32 models with Wi-Fi and Bluetooh Low Energy (BLE) which are supported by ESP-IDF 5.1.4 and Arduino Core 3.0.2. - Tested stable builds are provided for the ESP32, ESP32-S3 and ESP32-C3. - Support for the ESP32-C6 is experimental. There could be more frequent crashes than on other ESP32 devices and connections with the Nuki device could be slower than on other ESP32 devices. -- The ESP32-Solo1 is not supported by ESP-IDF 5.1 and as such can't be build using Arduino Core 3 and ESP-IDF 5.1. Untested builds against Arduino Core 2.0.14 and ESP-IDF 4.4 are provided. Not supported ESP32 devices: +- The ESP32-Solo1 is not supported by ESP-IDF 5.1 and as such can't be build using Arduino Core 3 and ESP-IDF 5.1. Release 9.0 was the last (untested) release for the Solo1 which for the Solo1 is built against Arduino Core 2.0.14 and ESP-IDF 4.4. - The ESP32-S2 has no BLE and as such can't run Nuki Hub. - The ESP32-H2 has no Wi-FI and Nuki Hub is not compiled against this target because of this (at this time). diff --git a/lib/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino b/lib/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino index 138e68d..eb6caef 100644 --- a/lib/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino +++ b/lib/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino @@ -14,42 +14,29 @@ #include -// This is GandiStandardSSLCA2.pem, the root Certificate Authority that signed -// the server certificate for the demo server https://jigsaw.w3.org in this -// example. This certificate is valid until Sep 11 23:59:59 2024 GMT +// This is a Baltimore CyberTrust cert, the root Certificate Authority that +// signed the server certificate for the demo server https://jigsaw.w3.org in this +// example. This certificate is valid until Mon, 12 May 2025 23:59:00 GMT const char *rootCACertificate = "-----BEGIN CERTIFICATE-----\n" - "MIIF6TCCA9GgAwIBAgIQBeTcO5Q4qzuFl8umoZhQ4zANBgkqhkiG9w0BAQwFADCB\n" - "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" - "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" - "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQw\n" - "OTEyMDAwMDAwWhcNMjQwOTExMjM1OTU5WjBfMQswCQYDVQQGEwJGUjEOMAwGA1UE\n" - "CBMFUGFyaXMxDjAMBgNVBAcTBVBhcmlzMQ4wDAYDVQQKEwVHYW5kaTEgMB4GA1UE\n" - "AxMXR2FuZGkgU3RhbmRhcmQgU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" - "DwAwggEKAoIBAQCUBC2meZV0/9UAPPWu2JSxKXzAjwsLibmCg5duNyj1ohrP0pIL\n" - "m6jTh5RzhBCf3DXLwi2SrCG5yzv8QMHBgyHwv/j2nPqcghDA0I5O5Q1MsJFckLSk\n" - "QFEW2uSEEi0FXKEfFxkkUap66uEHG4aNAXLy59SDIzme4OFMH2sio7QQZrDtgpbX\n" - "bmq08j+1QvzdirWrui0dOnWbMdw+naxb00ENbLAb9Tr1eeohovj0M1JLJC0epJmx\n" - "bUi8uBL+cnB89/sCdfSN3tbawKAyGlLfOGsuRTg/PwSWAP2h9KK71RfWJ3wbWFmV\n" - "XooS/ZyrgT5SKEhRhWvzkbKGPym1bgNi7tYFAgMBAAGjggF1MIIBcTAfBgNVHSME\n" - "GDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUs5Cn2MmvTs1hPJ98\n" - "rV1/Qf1pMOowDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD\n" - "VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGy\n" - "MQECAhowCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl\n" - "cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy\n" - "bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy\n" - "dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ\n" - "aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAWGf9\n" - "crJq13xhlhl+2UNG0SZ9yFP6ZrBrLafTqlb3OojQO3LJUP33WbKqaPWMcwO7lWUX\n" - "zi8c3ZgTopHJ7qFAbjyY1lzzsiI8Le4bpOHeICQW8owRc5E69vrOJAKHypPstLbI\n" - "FhfFcvwnQPYT/pOmnVHvPCvYd1ebjGU6NSU2t7WKY28HJ5OxYI2A25bUeo8tqxyI\n" - "yW5+1mUfr13KFj8oRtygNeX56eXVlogMT8a3d2dIhCe2H7Bo26y/d7CQuKLJHDJd\n" - "ArolQ4FCR7vY4Y8MDEZf7kYzawMUgtN+zY+vkNaOJH1AQrRqahfGlZfh8jjNp+20\n" - "J0CT33KpuMZmYzc4ZCIwojvxuch7yPspOqsactIGEk72gtQjbz7Dk+XYtsDe3CMW\n" - "1hMwt6CaDixVBgBwAc/qOR2A24j3pSC4W/0xJmmPLQphgzpHphNULB7j7UTKvGof\n" - "KA5R2d4On3XNDgOVyvnFqSot/kGkoUeuDcL5OWYzSlvhhChZbH2UF3bkRYKtcCD9\n" - "0m9jqNf6oDP6N8v3smWe2lBvP+Sn845dWDKXcCMu5/3EFZucJ48y7RetWIExKREa\n" - "m9T8bJUox04FB6b9HbwZ4ui3uRGKLXASUoWNjDNKD/yZkuBjcNqllEdjB+dYxzFf\n" - "BT02Vf6Dsuimrdfp5gJ0iHRc2jTbkNJtUQoj1iM=\n" + "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n" + "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n" + "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n" + "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n" + "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n" + "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n" + "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n" + "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n" + "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n" + "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n" + "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n" + "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n" + "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n" + "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n" + "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" + "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n" + "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n" + "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n" + "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" "-----END CERTIFICATE-----\n"; // Not sure if NetworkClientSecure checks the validity date of the certificate. diff --git a/lib/HTTPClient/library.properties b/lib/HTTPClient/library.properties index 56af94c..eca8d22 100644 --- a/lib/HTTPClient/library.properties +++ b/lib/HTTPClient/library.properties @@ -1,5 +1,5 @@ name=HTTPClient -version=2.0.0 +version=3.0.3 author=Markus Sattler maintainer=Markus Sattler sentence=HTTP Client for ESP32 diff --git a/lib/HTTPClient/src/HTTPClient.cpp b/lib/HTTPClient/src/HTTPClient.cpp index 9a14c82..7881a87 100644 --- a/lib/HTTPClient/src/HTTPClient.cpp +++ b/lib/HTTPClient/src/HTTPClient.cpp @@ -28,118 +28,85 @@ #include #include - -#ifdef HTTPCLIENT_1_1_COMPATIBLE -#include -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) -#include -#else -#include -#endif -#endif - #include #include - #include "HTTPClient.h" /// Cookie jar support #include #ifdef HTTPCLIENT_1_1_COMPATIBLE -class TransportTraits -{ +class TransportTraits { public: - virtual ~TransportTraits() - { - } + virtual ~TransportTraits() {} - virtual std::unique_ptr create() - { - return std::unique_ptr(new WiFiClient()); - } + virtual std::unique_ptr create() { + return std::unique_ptr(new NetworkClient()); + } - virtual bool verify(WiFiClient& client, const char* host) - { - return true; - } + virtual bool verify(NetworkClient &client, const char *host) { + return true; + } }; -class TLSTraits : public TransportTraits -{ +#ifndef HTTPCLIENT_NOSECURE +class TLSTraits : public TransportTraits { public: - TLSTraits(const char* CAcert, const char* clicert = nullptr, const char* clikey = nullptr) : - _cacert(CAcert), _clicert(clicert), _clikey(clikey) - { - } + TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {} - std::unique_ptr create() override - { - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - return std::unique_ptr(new WiFiClientSecure()); - #else - return std::unique_ptr(new NetworkClientSecure()); - #endif - } + std::unique_ptr create() override { + return std::unique_ptr(new NetworkClientSecure()); + } - bool verify(WiFiClient& client, const char* host) override - { - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - WiFiClientSecure& wcs = static_cast(client); - #else - NetworkClientSecure& wcs = static_cast(client); - #endif - if (_cacert == nullptr) { - wcs.setInsecure(); - } else { - wcs.setCACert(_cacert); - wcs.setCertificate(_clicert); - wcs.setPrivateKey(_clikey); - } - return true; + bool verify(NetworkClient &client, const char *host) override { + NetworkClientSecure &wcs = static_cast(client); + if (_cacert == nullptr) { + wcs.setInsecure(); + } else { + wcs.setCACert(_cacert); + wcs.setCertificate(_clicert); + wcs.setPrivateKey(_clikey); } + return true; + } protected: - const char* _cacert; - const char* _clicert; - const char* _clikey; + const char *_cacert; + const char *_clicert; + const char *_clikey; }; -#endif // HTTPCLIENT_1_1_COMPATIBLE +#endif // HTTPCLIENT_NOSECURE +#endif // HTTPCLIENT_1_1_COMPATIBLE /** * constructor */ -HTTPClient::HTTPClient() -{ -} +HTTPClient::HTTPClient() {} /** * destructor */ -HTTPClient::~HTTPClient() -{ - if(_client) { - _client->stop(); - } - if(_currentHeaders) { - delete[] _currentHeaders; - } - if(_tcpDeprecated) { - _tcpDeprecated.reset(nullptr); - } - if(_transportTraits) { - _transportTraits.reset(nullptr); - } +HTTPClient::~HTTPClient() { + if (_client) { + _client->stop(); + } + if (_currentHeaders) { + delete[] _currentHeaders; + } + if (_tcpDeprecated) { + _tcpDeprecated.reset(nullptr); + } + if (_transportTraits) { + _transportTraits.reset(nullptr); + } } -void HTTPClient::clear() -{ - _returnCode = 0; - _size = -1; - _headers = ""; +void HTTPClient::clear() { + _returnCode = 0; + _size = -1; + _headers = ""; } - /** * parsing the url for all needed parameters * @param client Client& @@ -147,36 +114,41 @@ void HTTPClient::clear() * @param https bool * @return success bool */ -bool HTTPClient::begin(WiFiClient &client, String url) { +bool HTTPClient::begin(NetworkClient &client, String url) { #ifdef HTTPCLIENT_1_1_COMPATIBLE - if(_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } + if (_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } #endif - _client = &client; + _client = &client; - // check for : (http: or https:) - int index = url.indexOf(':'); - if(index < 0) { - log_d("failed to parse protocol"); - return false; - } + // check for : (http: or https:) + int index = url.indexOf(':'); + if (index < 0) { + log_d("failed to parse protocol"); + return false; + } - String protocol = url.substring(0, index); - if(protocol != "http" && protocol != "https") { - log_d("unknown protocol '%s'", protocol.c_str()); - return false; - } + String protocol = url.substring(0, index); + if (protocol != "http" && protocol != "https") { + log_d("unknown protocol '%s'", protocol.c_str()); + return false; + } - _port = (protocol == "https" ? 443 : 80); - _secure = (protocol == "https"); - return beginInternal(url, protocol.c_str()); + _port = (protocol == "https" ? 443 : 80); + _secure = (protocol == "https"); + +#ifdef HTTPCLIENT_NOSECURE + if (_secure) { + return false; + } +#endif // HTTPCLIENT_NOSECURE + return beginInternal(url, protocol.c_str()); } - /** * directly supply all needed parameters * @param client Client& @@ -186,252 +158,251 @@ bool HTTPClient::begin(WiFiClient &client, String url) { * @param https bool * @return success bool */ -bool HTTPClient::begin(WiFiClient &client, String host, uint16_t port, String uri, bool https) -{ +bool HTTPClient::begin(NetworkClient &client, String host, uint16_t port, String uri, bool https) { #ifdef HTTPCLIENT_1_1_COMPATIBLE - if(_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } + if (_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } #endif - _client = &client; + _client = &client; - clear(); - _host = host; - _port = port; - _uri = uri; - _protocol = (https ? "https" : "http"); - _secure = https; - return true; + clear(); + _host = host; + _port = port; + _uri = uri; + _protocol = (https ? "https" : "http"); + _secure = https; + +#ifdef HTTPCLIENT_NOSECURE + return _secure ? false : true; +#else + return true; +#endif // HTTPCLIENT_NOSECURE } - #ifdef HTTPCLIENT_1_1_COMPATIBLE -bool HTTPClient::begin(String url, const char* CAcert) -{ - if(_client && !_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } +#ifndef HTTPCLIENT_NOSECURE +bool HTTPClient::begin(String url, const char *CAcert) { + if (_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } - clear(); - _port = 443; - if (!beginInternal(url, "https")) { - return false; - } - _secure = true; - _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); - if(!_transportTraits) { - log_e("could not create transport traits"); - return false; - } + clear(); + _port = 443; + if (!beginInternal(url, "https")) { + return false; + } + _secure = true; + _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); + if (!_transportTraits) { + log_e("could not create transport traits"); + return false; + } - return true; + return true; } +#endif // HTTPCLIENT_NOSECURE /** * parsing the url for all needed parameters * @param url String */ -bool HTTPClient::begin(String url) -{ - if(_client && !_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } +bool HTTPClient::begin(String url) { + if (_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } - clear(); - _port = 80; - if (!beginInternal(url, "http")) { - return begin(url, (const char*)NULL); - } - _transportTraits = TransportTraitsPtr(new TransportTraits()); - if(!_transportTraits) { - log_e("could not create transport traits"); - return false; - } + clear(); + _port = 80; + if (!beginInternal(url, "http")) { +#ifdef HTTPCLIENT_NOSECURE + return false; +#else + return begin(url, (const char *)NULL); +#endif // HTTPCLIENT_NOSECURE + } + _transportTraits = TransportTraitsPtr(new TransportTraits()); + if (!_transportTraits) { + log_e("could not create transport traits"); + return false; + } - return true; + return true; } -#endif // HTTPCLIENT_1_1_COMPATIBLE +#endif // HTTPCLIENT_1_1_COMPATIBLE -bool HTTPClient::beginInternal(String url, const char* expectedProtocol) -{ - log_v("url: %s", url.c_str()); +bool HTTPClient::beginInternal(String url, const char *expectedProtocol) { + log_v("url: %s", url.c_str()); - // check for : (http: or https: - int index = url.indexOf(':'); - if(index < 0) { - log_e("failed to parse protocol"); - return false; - } + // check for : (http: or https: + int index = url.indexOf(':'); + if (index < 0) { + log_e("failed to parse protocol"); + return false; + } - _protocol = url.substring(0, index); - if (_protocol != expectedProtocol) { - log_d("unexpected protocol: %s, expected %s", _protocol.c_str(), expectedProtocol); - return false; - } + _protocol = url.substring(0, index); + if (_protocol != expectedProtocol) { + log_d("unexpected protocol: %s, expected %s", _protocol.c_str(), expectedProtocol); + return false; + } - url.remove(0, (index + 3)); // remove http:// or https:// + url.remove(0, (index + 3)); // remove http:// or https:// - index = url.indexOf('/'); - if (index == -1) { - index = url.length(); - url += '/'; - } - String host = url.substring(0, index); - url.remove(0, index); // remove host part + index = url.indexOf('/'); + if (index == -1) { + index = url.length(); + url += '/'; + } + String host = url.substring(0, index); + url.remove(0, index); // remove host part - // get Authorization - index = host.indexOf('@'); - if(index >= 0) { - // auth info - String auth = host.substring(0, index); - host.remove(0, index + 1); // remove auth part including @ - _base64Authorization = base64::encode(auth); - } + // get Authorization + index = host.indexOf('@'); + if (index >= 0) { + // auth info + String auth = host.substring(0, index); + host.remove(0, index + 1); // remove auth part including @ + _base64Authorization = base64::encode(auth); + } - // get port - index = host.indexOf(':'); - String the_host; - if(index >= 0) { - the_host = host.substring(0, index); // hostname - host.remove(0, (index + 1)); // remove hostname + : - _port = host.toInt(); // get port - } else { - the_host = host; - } - if(_host != the_host && connected()){ - log_d("switching host from '%s' to '%s'. disconnecting first", _host.c_str(), the_host.c_str()); - _canReuse = false; - disconnect(true); - } - _host = the_host; - _uri = url; - log_d("protocol: %s, host: %s port: %d url: %s", _protocol.c_str(), _host.c_str(), _port, _uri.c_str()); - return true; + // get port + index = host.indexOf(':'); + String the_host; + if (index >= 0) { + the_host = host.substring(0, index); // hostname + host.remove(0, (index + 1)); // remove hostname + : + _port = host.toInt(); // get port + } else { + the_host = host; + } + if (_host != the_host && connected()) { + log_d("switching host from '%s' to '%s'. disconnecting first", _host.c_str(), the_host.c_str()); + _canReuse = false; + disconnect(true); + } + _host = the_host; + _uri = url; + log_d("protocol: %s, host: %s port: %d url: %s", _protocol.c_str(), _host.c_str(), _port, _uri.c_str()); + return true; } #ifdef HTTPCLIENT_1_1_COMPATIBLE -bool HTTPClient::begin(String host, uint16_t port, String uri) -{ - if(_client && !_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } +bool HTTPClient::begin(String host, uint16_t port, String uri) { + if (_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } - clear(); - _host = host; - _port = port; - _uri = uri; - _transportTraits = TransportTraitsPtr(new TransportTraits()); - log_d("host: %s port: %d uri: %s", host.c_str(), port, uri.c_str()); - return true; + clear(); + _host = host; + _port = port; + _uri = uri; + _transportTraits = TransportTraitsPtr(new TransportTraits()); + log_d("host: %s port: %d uri: %s", host.c_str(), port, uri.c_str()); + return true; } -bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcert) -{ - if(_client && !_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } +#ifndef HTTPCLIENT_NOSECURE +bool HTTPClient::begin(String host, uint16_t port, String uri, const char *CAcert) { + if (_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } - clear(); - _host = host; - _port = port; - _uri = uri; + clear(); + _host = host; + _port = port; + _uri = uri; - if (strlen(CAcert) == 0) { - return false; - } - _secure = true; - _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); - return true; + if (strlen(CAcert) == 0) { + return false; + } + _secure = true; + _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); + return true; } -bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key) -{ - if(_client && !_tcpDeprecated) { - log_d("mix up of new and deprecated api"); - _canReuse = false; - end(); - } +bool HTTPClient::begin(String host, uint16_t port, String uri, const char *CAcert, const char *cli_cert, const char *cli_key) { + if (_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } - clear(); - _host = host; - _port = port; - _uri = uri; + clear(); + _host = host; + _port = port; + _uri = uri; - if (strlen(CAcert) == 0) { - return false; - } - _secure = true; - _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert, cli_cert, cli_key)); - return true; + if (strlen(CAcert) == 0) { + return false; + } + _secure = true; + _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert, cli_cert, cli_key)); + return true; } -#endif // HTTPCLIENT_1_1_COMPATIBLE +#endif // HTTPCLIENT_NOSECURE +#endif // HTTPCLIENT_1_1_COMPATIBLE /** * end * called after the payload is handled */ -void HTTPClient::end(void) -{ - disconnect(false); - clear(); +void HTTPClient::end(void) { + disconnect(false); + clear(); } - - /** * disconnect * close the TCP socket */ -void HTTPClient::disconnect(bool preserveClient) -{ - if(connected()) { - if(_client->available() > 0) { - log_d("still data in buffer (%d), clean up.\n", _client->available()); - _client->flush(); - } - - if(_reuse && _canReuse) { - log_d("tcp keep open for reuse"); - } else { - log_d("tcp stop"); - _client->stop(); - if(!preserveClient) { - _client = nullptr; -#ifdef HTTPCLIENT_1_1_COMPATIBLE - if(_tcpDeprecated) { - _transportTraits.reset(nullptr); - _tcpDeprecated.reset(nullptr); - } -#endif - } - } - } else { - log_d("tcp is closed\n"); +void HTTPClient::disconnect(bool preserveClient) { + if (connected()) { + if (_client->available() > 0) { + log_d("still data in buffer (%d), clean up.\n", _client->available()); + _client->flush(); } -} + if (_reuse && _canReuse) { + log_d("tcp keep open for reuse"); + } else { + log_d("tcp stop"); + _client->stop(); + if (!preserveClient) { + _client = nullptr; +#ifdef HTTPCLIENT_1_1_COMPATIBLE + if (_tcpDeprecated) { + _transportTraits.reset(nullptr); + _tcpDeprecated.reset(nullptr); + } +#endif + } + } + } else { + log_d("tcp is closed\n"); + } +} /** * connected * @return connected status */ -bool HTTPClient::connected() -{ - if(_client) { - return ((_client->available() > 0) || _client->connected()); - } - return false; +bool HTTPClient::connected() { + if (_client) { + return ((_client->available() > 0) || _client->connected()); + } + return false; } /** @@ -439,18 +410,24 @@ bool HTTPClient::connected() * keep-alive * @param reuse bool */ -void HTTPClient::setReuse(bool reuse) -{ - _reuse = reuse; +void HTTPClient::setReuse(bool reuse) { + _reuse = reuse; } /** * set User Agent * @param userAgent const char * */ -void HTTPClient::setUserAgent(const String& userAgent) -{ - _userAgent = userAgent; +void HTTPClient::setUserAgent(const String &userAgent) { + _userAgent = userAgent; +} + +/** + * set Accept Encoding Header + * @param acceptEncoding const char * + */ +void HTTPClient::setAcceptEncoding(const String &acceptEncoding) { + _acceptEncoding = acceptEncoding; } /** @@ -458,76 +435,69 @@ void HTTPClient::setUserAgent(const String& userAgent) * @param user const char * * @param password const char * */ -void HTTPClient::setAuthorization(const char * user, const char * password) -{ - if(user && password) { - String auth = user; - auth += ":"; - auth += password; - _base64Authorization = base64::encode(auth); - } +void HTTPClient::setAuthorization(const char *user, const char *password) { + if (user && password) { + String auth = user; + auth += ":"; + auth += password; + _base64Authorization = base64::encode(auth); + } } /** * set the Authorizatio for the http request * @param auth const char * base64 */ -void HTTPClient::setAuthorization(const char * auth) -{ - if(auth) { - _base64Authorization = auth; - } +void HTTPClient::setAuthorization(const char *auth) { + if (auth) { + _base64Authorization = auth; + } } /** * set the Authorization type for the http request * @param authType const char * */ -void HTTPClient::setAuthorizationType(const char * authType) -{ - if(authType) { - _authorizationType = authType; - } +void HTTPClient::setAuthorizationType(const char *authType) { + if (authType) { + _authorizationType = authType; + } } /** * set the timeout (ms) for establishing a connection to the server * @param connectTimeout int32_t */ -void HTTPClient::setConnectTimeout(int32_t connectTimeout) -{ - _connectTimeout = connectTimeout; +void HTTPClient::setConnectTimeout(int32_t connectTimeout) { + _connectTimeout = connectTimeout; } /** * set the timeout for the TCP connection * @param timeout unsigned int */ -void HTTPClient::setTimeout(uint16_t timeout) -{ - _tcpTimeout = timeout; - if(connected()) { - _client->setTimeout((timeout + 500) / 1000); - } +void HTTPClient::setTimeout(uint16_t timeout) { + _tcpTimeout = timeout; + if (connected()) { + _client->setTimeout(timeout); + } } /** * use HTTP1.0 * @param use */ -void HTTPClient::useHTTP10(bool useHTTP10) -{ - _useHTTP10 = useHTTP10; - _reuse = !useHTTP10; +void HTTPClient::useHTTP10(bool useHTTP10) { + _useHTTP10 = useHTTP10; + _reuse = !useHTTP10; } /** * send a GET request * @return http code */ -int HTTPClient::GET() -{ - return sendRequest("GET"); +int HTTPClient::GET() { + return sendRequest("GET"); } /** @@ -536,14 +506,12 @@ int HTTPClient::GET() * @param size size_t * @return http code */ -int HTTPClient::POST(uint8_t * payload, size_t size) -{ - return sendRequest("POST", payload, size); +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()); +int HTTPClient::POST(String payload) { + return POST((uint8_t *)payload.c_str(), payload.length()); } /** @@ -552,14 +520,12 @@ int HTTPClient::POST(String payload) * @param size size_t * @return http code */ -int HTTPClient::PATCH(uint8_t * payload, size_t size) -{ - return sendRequest("PATCH", payload, size); +int HTTPClient::PATCH(uint8_t *payload, size_t size) { + return sendRequest("PATCH", payload, size); } -int HTTPClient::PATCH(String payload) -{ - return PATCH((uint8_t *) payload.c_str(), payload.length()); +int HTTPClient::PATCH(String payload) { + return PATCH((uint8_t *)payload.c_str(), payload.length()); } /** @@ -568,12 +534,12 @@ int HTTPClient::PATCH(String payload) * @param size size_t * @return http code */ -int HTTPClient::PUT(uint8_t * payload, size_t size) { - return sendRequest("PUT", payload, size); +int HTTPClient::PUT(uint8_t *payload, size_t size) { + return sendRequest("PUT", payload, size); } int HTTPClient::PUT(String payload) { - return PUT((uint8_t *) payload.c_str(), payload.length()); + return PUT((uint8_t *)payload.c_str(), payload.length()); } /** @@ -582,9 +548,8 @@ int HTTPClient::PUT(String payload) { * @param payload String data for the message body * @return */ -int HTTPClient::sendRequest(const char * type, String payload) -{ - return sendRequest(type, (uint8_t *) payload.c_str(), payload.length()); +int HTTPClient::sendRequest(const char *type, String payload) { + return sendRequest(type, (uint8_t *)payload.c_str(), payload.length()); } /** @@ -594,128 +559,122 @@ int HTTPClient::sendRequest(const char * type, String payload) * @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) -{ - int code; - bool redirect = false; - uint16_t redirectCount = 0; - do { - // wipe out any existing headers from previous request - for(size_t i = 0; i < _headerKeysCount; i++) { - if (_currentHeaders[i].value.length() > 0) { - _currentHeaders[i].value.clear(); +int HTTPClient::sendRequest(const char *type, uint8_t *payload, size_t size) { + int code; + bool redirect = false; + uint16_t redirectCount = 0; + do { + // wipe out any existing headers from previous request + for (size_t i = 0; i < _headerKeysCount; i++) { + if (_currentHeaders[i].value.length() > 0) { + _currentHeaders[i].value.clear(); + } + } + + log_d("request type: '%s' redirCount: %d\n", type, redirectCount); + + // connect to server + if (!connect()) { + return returnError(HTTPC_ERROR_CONNECTION_REFUSED); + } + + if (payload && size > 0) { + addHeader(F("Content-Length"), String(size)); + } + + // add cookies to header, if present + String cookie_string; + if (generateCookieString(&cookie_string)) { + addHeader("Cookie", cookie_string); + } + + // send Header + if (!sendHeader(type)) { + return returnError(HTTPC_ERROR_SEND_HEADER_FAILED); + } + + // send Payload if needed + if (payload && size > 0) { + size_t sent_bytes = 0; + while (sent_bytes < size) { + size_t sent = _client->write(&payload[sent_bytes], size - sent_bytes); + if (sent == 0) { + log_w("Failed to send chunk! Lets wait a bit"); + delay(100); + sent = _client->write(&payload[sent_bytes], size - sent_bytes); + if (sent == 0) { + log_e("Failed to send chunk!"); + break; + } + } + sent_bytes += sent; + } + if (sent_bytes != size) { + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } + } + + code = handleHeaderResponse(); + log_d("sendRequest code=%d\n", code); + + // Handle redirections as stated in RFC document: + // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + // + // Implementing HTTP_CODE_FOUND as redirection with GET method, + // to follow most of existing user agent implementations. + // + redirect = false; + if (_followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS && redirectCount < _redirectLimit && _location.length() > 0) { + switch (code) { + // redirecting using the same method + case HTTP_CODE_MOVED_PERMANENTLY: + case HTTP_CODE_TEMPORARY_REDIRECT: + { + if ( + // allow to force redirections on other methods + // (the RFC require user to accept the redirection) + _followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS || + // allow GET and HEAD methods without force + !strcmp(type, "GET") || !strcmp(type, "HEAD")) { + redirectCount += 1; + log_d("following redirect (the same method): '%s' redirCount: %d\n", _location.c_str(), redirectCount); + if (!setURL(_location)) { + log_d("failed setting URL for redirection\n"); + // no redirection + break; } + // redirect using the same request method and payload, different URL + redirect = true; + } + break; + } + // redirecting with method dropped to GET or HEAD + // note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method + case HTTP_CODE_FOUND: + case HTTP_CODE_SEE_OTHER: + { + redirectCount += 1; + log_d("following redirect (dropped to GET/HEAD): '%s' redirCount: %d\n", _location.c_str(), redirectCount); + if (!setURL(_location)) { + log_d("failed setting URL for redirection\n"); + // no redirection + break; + } + // redirect after changing method to GET/HEAD and dropping payload + type = "GET"; + payload = nullptr; + size = 0; + redirect = true; + break; } - log_d("request type: '%s' redirCount: %d\n", type, redirectCount); + default: break; + } + } - // connect to server - if(!connect()) { - return returnError(HTTPC_ERROR_CONNECTION_REFUSED); - } - - if(payload && size > 0) { - addHeader(F("Content-Length"), String(size)); - } - - // add cookies to header, if present - String cookie_string; - if(generateCookieString(&cookie_string)) { - addHeader("Cookie", cookie_string); - } - - // send Header - if(!sendHeader(type)) { - return returnError(HTTPC_ERROR_SEND_HEADER_FAILED); - } - - // send Payload if needed - if(payload && size > 0) { - size_t sent_bytes = 0; - while(sent_bytes < size){ - size_t sent = _client->write(&payload[sent_bytes], size - sent_bytes); - if (sent == 0){ - log_w("Failed to send chunk! Lets wait a bit"); - delay(100); - sent = _client->write(&payload[sent_bytes], size - sent_bytes); - if (sent == 0){ - log_e("Failed to send chunk!"); - break; - } - } - sent_bytes += sent; - } - if(sent_bytes != size){ - return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); - } - } - - code = handleHeaderResponse(); - log_d("sendRequest code=%d\n", code); - - // Handle redirections as stated in RFC document: - // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html - // - // Implementing HTTP_CODE_FOUND as redirection with GET method, - // to follow most of existing user agent implementations. - // - redirect = false; - if ( - _followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS && - redirectCount < _redirectLimit && - _location.length() > 0 - ) { - switch (code) { - // redirecting using the same method - case HTTP_CODE_MOVED_PERMANENTLY: - case HTTP_CODE_TEMPORARY_REDIRECT: { - if ( - // allow to force redirections on other methods - // (the RFC require user to accept the redirection) - _followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS || - // allow GET and HEAD methods without force - !strcmp(type, "GET") || - !strcmp(type, "HEAD") - ) { - redirectCount += 1; - log_d("following redirect (the same method): '%s' redirCount: %d\n", _location.c_str(), redirectCount); - if (!setURL(_location)) { - log_d("failed setting URL for redirection\n"); - // no redirection - break; - } - // redirect using the same request method and payload, diffrent URL - redirect = true; - } - break; - } - // redirecting with method dropped to GET or HEAD - // note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method - case HTTP_CODE_FOUND: - case HTTP_CODE_SEE_OTHER: { - redirectCount += 1; - log_d("following redirect (dropped to GET/HEAD): '%s' redirCount: %d\n", _location.c_str(), redirectCount); - if (!setURL(_location)) { - log_d("failed setting URL for redirection\n"); - // no redirection - break; - } - // redirect after changing method to GET/HEAD and dropping payload - type = "GET"; - payload = nullptr; - size = 0; - redirect = true; - break; - } - - default: - break; - } - } - - } while (redirect); - // handle Server Response (Header) - return returnError(code); + } while (redirect); + // handle Server Response (Header) + return returnError(code); } /** @@ -725,180 +684,176 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) * @param size size_t size for the message body if 0 not Content-Length is send * @return -1 if no info or > 0 when Content-Length is set by server */ -int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) -{ +int HTTPClient::sendRequest(const char *type, Stream *stream, size_t size) { - if(!stream) { - return returnError(HTTPC_ERROR_NO_STREAM); - } + if (!stream) { + return returnError(HTTPC_ERROR_NO_STREAM); + } - // connect to server - if(!connect()) { - return returnError(HTTPC_ERROR_CONNECTION_REFUSED); - } + // connect to server + if (!connect()) { + return returnError(HTTPC_ERROR_CONNECTION_REFUSED); + } - if(size > 0) { - addHeader("Content-Length", String(size)); - } + if (size > 0) { + addHeader("Content-Length", String(size)); + } - // add cookies to header, if present - String cookie_string; - if(generateCookieString(&cookie_string)) { - addHeader("Cookie", cookie_string); - } + // add cookies to header, if present + String cookie_string; + if (generateCookieString(&cookie_string)) { + addHeader("Cookie", cookie_string); + } - // send Header - if(!sendHeader(type)) { - return returnError(HTTPC_ERROR_SEND_HEADER_FAILED); - } + // send Header + if (!sendHeader(type)) { + return returnError(HTTPC_ERROR_SEND_HEADER_FAILED); + } - int buff_size = HTTP_TCP_BUFFER_SIZE; + int buff_size = HTTP_TCP_TX_BUFFER_SIZE; - int len = size; - int bytesWritten = 0; + int len = size; + int bytesWritten = 0; - if(len == 0) { - len = -1; - } + if (len == 0) { + len = -1; + } - // if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE - if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) { - buff_size = len; - } + // if possible create smaller buffer then HTTP_TCP_TX_BUFFER_SIZE + if ((len > 0) && (len < buff_size)) { + buff_size = len; + } - // create buffer for read - uint8_t * buff = (uint8_t *) malloc(buff_size); + // create buffer for read + uint8_t *buff = (uint8_t *)malloc(buff_size); - if(buff) { - // read all data from stream and send it to server - while(connected() && (stream->available() > -1) && (len > 0 || len == -1)) { + if (buff) { + // read all data from stream and send it to server + while (connected() && (stream->available() > -1) && (len > 0 || len == -1)) { - // get available data size - int sizeAvailable = stream->available(); + // get available data size + int sizeAvailable = stream->available(); - if(sizeAvailable) { + if (sizeAvailable) { - int readBytes = sizeAvailable; + int readBytes = sizeAvailable; - // read only the asked bytes - if(len > 0 && readBytes > len) { - readBytes = len; - } - - // not read more the buffer can handle - if(readBytes > buff_size) { - readBytes = buff_size; - } - - // read data - int bytesRead = stream->readBytes(buff, readBytes); - - // write it to Stream - int bytesWrite = _client->write((const uint8_t *) buff, bytesRead); - bytesWritten += bytesWrite; - - // are all Bytes a writen to stream ? - if(bytesWrite != bytesRead) { - log_d("short write, asked for %d but got %d retry...", bytesRead, bytesWrite); - - // check for write error - if(_client->getWriteError()) { - log_d("stream write error %d", _client->getWriteError()); - - //reset write error for retry - _client->clearWriteError(); - } - - // some time for the stream - delay(1); - - int leftBytes = (readBytes - bytesWrite); - - // retry to send the missed bytes - bytesWrite = _client->write((const uint8_t *) (buff + bytesWrite), leftBytes); - bytesWritten += bytesWrite; - - if(bytesWrite != leftBytes) { - // failed again - log_d("short write, asked for %d but got %d failed.", leftBytes, bytesWrite); - free(buff); - return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); - } - } - - // check for write error - if(_client->getWriteError()) { - log_d("stream write error %d", _client->getWriteError()); - free(buff); - return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); - } - - // count bytes to read left - if(len > 0) { - len -= readBytes; - } - - delay(0); - } else { - delay(1); - } + // read only the asked bytes + if (len > 0 && readBytes > len) { + readBytes = len; } - free(buff); + // not read more the buffer can handle + if (readBytes > buff_size) { + readBytes = buff_size; + } - if(size && (int) size != bytesWritten) { - log_d("Stream payload bytesWritten %d and size %d mismatch!.", bytesWritten, size); - log_d("ERROR SEND PAYLOAD FAILED!"); + // read data + int bytesRead = stream->readBytes(buff, readBytes); + + // write it to Stream + int bytesWrite = _client->write((const uint8_t *)buff, bytesRead); + bytesWritten += bytesWrite; + + // are all Bytes a written to stream ? + if (bytesWrite != bytesRead) { + log_d("short write, asked for %d but got %d retry...", bytesRead, bytesWrite); + + // check for write error + if (_client->getWriteError()) { + log_d("stream write error %d", _client->getWriteError()); + + //reset write error for retry + _client->clearWriteError(); + } + + // some time for the stream + delay(1); + + int leftBytes = (readBytes - bytesWrite); + + // retry to send the missed bytes + bytesWrite = _client->write((const uint8_t *)(buff + bytesWrite), leftBytes); + bytesWritten += bytesWrite; + + if (bytesWrite != leftBytes) { + // failed again + log_d("short write, asked for %d but got %d failed.", leftBytes, bytesWrite); + free(buff); return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); - } else { - log_d("Stream payload written: %d", bytesWritten); + } } - } else { - log_d("too less ram! need %d", HTTP_TCP_BUFFER_SIZE); - return returnError(HTTPC_ERROR_TOO_LESS_RAM); + // check for write error + if (_client->getWriteError()) { + log_d("stream write error %d", _client->getWriteError()); + free(buff); + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } + + // count bytes to read left + if (len > 0) { + len -= readBytes; + } + + delay(0); + } else { + delay(1); + } } - // handle Server Response (Header) - return returnError(handleHeaderResponse()); + free(buff); + + if (size && (int)size != bytesWritten) { + log_d("Stream payload bytesWritten %d and size %d mismatch!.", bytesWritten, size); + log_d("ERROR SEND PAYLOAD FAILED!"); + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } else { + log_d("Stream payload written: %d", bytesWritten); + } + + } else { + log_d("too less ram! need %d", buff_size); + return returnError(HTTPC_ERROR_TOO_LESS_RAM); + } + + // handle Server Response (Header) + return returnError(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; +int HTTPClient::getSize(void) { + return _size; } /** * returns the stream of the tcp connection - * @return WiFiClient + * @return NetworkClient */ -WiFiClient& HTTPClient::getStream(void) -{ - if (connected()) { - return *_client; - } +NetworkClient &HTTPClient::getStream(void) { + if (connected()) { + return *_client; + } - log_w("getStream: not connected"); - static WiFiClient empty; - return empty; + log_w("getStream: not connected"); + static NetworkClient empty; + return empty; } /** * returns a pointer to the stream of the tcp connection - * @return WiFiClient* + * @return NetworkClient* */ -WiFiClient* HTTPClient::getStreamPtr(void) -{ - if(connected()) { - return _client; - } +NetworkClient *HTTPClient::getStreamPtr(void) { + if (connected()) { + return _client; + } - log_w("getStreamPtr: not connected"); - return nullptr; + log_w("getStreamPtr: not connected"); + return nullptr; } /** @@ -906,106 +861,104 @@ WiFiClient* HTTPClient::getStreamPtr(void) * @param stream Stream * * @return bytes written ( negative values are error codes ) */ -int HTTPClient::writeToStream(Stream * stream) -{ +int HTTPClient::writeToStream(Stream *stream) { - if(!stream) { - return returnError(HTTPC_ERROR_NO_STREAM); + if (!stream) { + return returnError(HTTPC_ERROR_NO_STREAM); + } + + if (!connected()) { + return returnError(HTTPC_ERROR_NOT_CONNECTED); + } + + // get length of document (is -1 when Server sends no Content-Length header) + int len = _size; + int ret = 0; + + if (_transferEncoding == HTTPC_TE_IDENTITY) { + ret = writeToStreamDataBlock(stream, len); + + // have we an error? + if (ret < 0) { + return returnError(ret); } + } else if (_transferEncoding == HTTPC_TE_CHUNKED) { + int size = 0; + while (1) { + if (!connected()) { + return returnError(HTTPC_ERROR_CONNECTION_LOST); + } + String chunkHeader = _client->readStringUntil('\n'); - if(!connected()) { - return returnError(HTTPC_ERROR_NOT_CONNECTED); - } + if (chunkHeader.length() <= 0) { + return returnError(HTTPC_ERROR_READ_TIMEOUT); + } - // get length of document (is -1 when Server sends no Content-Length header) - int len = _size; - int ret = 0; + chunkHeader.trim(); // remove \r - if(_transferEncoding == HTTPC_TE_IDENTITY) { - ret = writeToStreamDataBlock(stream, len); + // read size of chunk + len = (uint32_t)strtol((const char *)chunkHeader.c_str(), NULL, 16); + size += len; + log_v(" read chunk len: %d", len); - // have we an error? - if(ret < 0) { - return returnError(ret); + // data left? + if (len > 0) { + int r = writeToStreamDataBlock(stream, len); + if (r < 0) { + // error in writeToStreamDataBlock + return returnError(r); } - } else if(_transferEncoding == HTTPC_TE_CHUNKED) { - int size = 0; - while(1) { - if(!connected()) { - return returnError(HTTPC_ERROR_CONNECTION_LOST); - } - String chunkHeader = _client->readStringUntil('\n'); + ret += r; + } else { - if(chunkHeader.length() <= 0) { - return returnError(HTTPC_ERROR_READ_TIMEOUT); - } - - chunkHeader.trim(); // remove \r - - // read size of chunk - len = (uint32_t) strtol((const char *) chunkHeader.c_str(), NULL, 16); - size += len; - log_d(" read chunk len: %d", len); - - // data left? - if(len > 0) { - int r = writeToStreamDataBlock(stream, len); - if(r < 0) { - // error in writeToStreamDataBlock - return returnError(r); - } - ret += r; - } else { - - // if no length Header use global chunk size - if(_size <= 0) { - _size = size; - } - - // check if we have write all data out - if(ret != _size) { - return returnError(HTTPC_ERROR_STREAM_WRITE); - } - break; - } - - // read trailing \r\n at the end of the chunk - char buf[2]; - auto trailing_seq_len = _client->readBytes((uint8_t*)buf, 2); - if (trailing_seq_len != 2 || buf[0] != '\r' || buf[1] != '\n') { - return returnError(HTTPC_ERROR_READ_TIMEOUT); - } - - delay(0); + // if no length Header use global chunk size + if (_size <= 0) { + _size = size; } - } else { - return returnError(HTTPC_ERROR_ENCODING); - } -// end(); - disconnect(true); - return ret; + // check if we have write all data out + if (ret != _size) { + return returnError(HTTPC_ERROR_STREAM_WRITE); + } + break; + } + + // read trailing \r\n at the end of the chunk + char buf[2]; + auto trailing_seq_len = _client->readBytes((uint8_t *)buf, 2); + if (trailing_seq_len != 2 || buf[0] != '\r' || buf[1] != '\n') { + return returnError(HTTPC_ERROR_READ_TIMEOUT); + } + + delay(0); + } + } else { + return returnError(HTTPC_ERROR_ENCODING); + } + + // end(); + disconnect(true); + return ret; } /** * return all payload as String (may need lot of ram or trigger out of memory!) * @return String */ -String HTTPClient::getString(void) -{ - // _size can be -1 when Server sends no Content-Length header - if(_size > 0 || _size == -1) { - StreamString sstring; - // try to reserve needed memory (noop if _size == -1) - if(sstring.reserve((_size + 1))) { - writeToStream(&sstring); - return sstring; - } else { - log_d("not enough memory to reserve a string! need: %d", (_size + 1)); - } +String HTTPClient::getString(void) { + // _size can be -1 when Server sends no Content-Length header + if (_size > 0 || _size == -1) { + StreamString sstring; + // try to reserve needed memory (noop if _size == -1) + if (sstring.reserve((_size + 1))) { + writeToStream(&sstring); + return sstring; + } else { + log_d("not enough memory to reserve a string! need: %d", (_size + 1)); } + } - return ""; + return ""; } /** @@ -1013,34 +966,21 @@ String HTTPClient::getString(void) * @param error int * @return String */ -String HTTPClient::errorToString(int error) -{ - switch(error) { - case HTTPC_ERROR_CONNECTION_REFUSED: - return F("connection refused"); - case HTTPC_ERROR_SEND_HEADER_FAILED: - return F("send header failed"); - case HTTPC_ERROR_SEND_PAYLOAD_FAILED: - return F("send payload failed"); - case HTTPC_ERROR_NOT_CONNECTED: - return F("not connected"); - case HTTPC_ERROR_CONNECTION_LOST: - return F("connection lost"); - case HTTPC_ERROR_NO_STREAM: - return F("no stream"); - case HTTPC_ERROR_NO_HTTP_SERVER: - return F("no HTTP server"); - case HTTPC_ERROR_TOO_LESS_RAM: - return F("too less ram"); - case HTTPC_ERROR_ENCODING: - return F("Transfer-Encoding not supported"); - case HTTPC_ERROR_STREAM_WRITE: - return F("Stream write error"); - case HTTPC_ERROR_READ_TIMEOUT: - return F("read Timeout"); - default: - return String(); - } +String HTTPClient::errorToString(int error) { + switch (error) { + case HTTPC_ERROR_CONNECTION_REFUSED: return F("connection refused"); + case HTTPC_ERROR_SEND_HEADER_FAILED: return F("send header failed"); + case HTTPC_ERROR_SEND_PAYLOAD_FAILED: return F("send payload failed"); + case HTTPC_ERROR_NOT_CONNECTED: return F("not connected"); + case HTTPC_ERROR_CONNECTION_LOST: return F("connection lost"); + case HTTPC_ERROR_NO_STREAM: return F("no stream"); + case HTTPC_ERROR_NO_HTTP_SERVER: return F("no HTTP server"); + case HTTPC_ERROR_TOO_LESS_RAM: return F("too less ram"); + case HTTPC_ERROR_ENCODING: return F("Transfer-Encoding not supported"); + case HTTPC_ERROR_STREAM_WRITE: return F("Stream write error"); + case HTTPC_ERROR_READ_TIMEOUT: return F("read Timeout"); + default: return String(); + } } /** @@ -1049,145 +989,134 @@ String HTTPClient::errorToString(int error) * @param value * @param first */ -void HTTPClient::addHeader(const String& name, const String& value, bool first, bool replace) -{ - // not allow set of Header handled by code - if(!name.equalsIgnoreCase(F("Connection")) && - !name.equalsIgnoreCase(F("User-Agent")) && - !name.equalsIgnoreCase(F("Host")) && - !(name.equalsIgnoreCase(F("Authorization")) && _base64Authorization.length())){ +void HTTPClient::addHeader(const String &name, const String &value, bool first, bool replace) { + // not allow set of Header handled by code + if (!name.equalsIgnoreCase(F("Connection")) && !name.equalsIgnoreCase(F("User-Agent")) && !name.equalsIgnoreCase(F("Accept-Encoding")) + && !name.equalsIgnoreCase(F("Host")) && !(name.equalsIgnoreCase(F("Authorization")) && _base64Authorization.length())) { - String headerLine = name; - headerLine += ": "; + String headerLine = name; + headerLine += ": "; - if (replace) { - int headerStart = _headers.indexOf(headerLine); - if (headerStart != -1 && (headerStart == 0 || _headers[headerStart - 1] == '\n')) { - int headerEnd = _headers.indexOf('\n', headerStart); - _headers = _headers.substring(0, headerStart) + _headers.substring(headerEnd + 1); - } - } - - headerLine += value; - headerLine += "\r\n"; - if(first) { - _headers = headerLine + _headers; - } else { - _headers += headerLine; - } + if (replace) { + int headerStart = _headers.indexOf(headerLine); + if (headerStart != -1 && (headerStart == 0 || _headers[headerStart - 1] == '\n')) { + int headerEnd = _headers.indexOf('\n', headerStart); + _headers = _headers.substring(0, headerStart) + _headers.substring(headerEnd + 1); + } } + + 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]; - } +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.equalsIgnoreCase(name)) { - return _currentHeaders[i].value; - } +String HTTPClient::header(const char *name) { + for (size_t i = 0; i < _headerKeysCount; ++i) { + if (_currentHeaders[i].key.equalsIgnoreCase(name)) { + return _currentHeaders[i].value; } - return String(); + } + return String(); } -String HTTPClient::header(size_t i) -{ - if(i < _headerKeysCount) { - 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(); +String HTTPClient::headerName(size_t i) { + if (i < _headerKeysCount) { + return _currentHeaders[i].key; + } + return String(); } -int HTTPClient::headers() -{ - return _headerKeysCount; +int HTTPClient::headers() { + return _headerKeysCount; } -bool HTTPClient::hasHeader(const char* name) -{ - for(size_t i = 0; i < _headerKeysCount; ++i) { - if((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) { - return true; - } +bool HTTPClient::hasHeader(const char *name) { + for (size_t i = 0; i < _headerKeysCount; ++i) { + if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) { + return true; } - return false; + } + return false; } /** * init TCP connection and handle ssl verify if needed * @return true if connection is ok */ -bool HTTPClient::connect(void) -{ - if(connected()) { - if(_reuse) { - log_d("already connected, reusing connection"); - } else { - log_d("already connected, try reuse!"); - } - while(_client->available() > 0) { - _client->read(); - } - return true; +bool HTTPClient::connect(void) { + if (connected()) { + if (_reuse) { + log_d("already connected, reusing connection"); + } else { + log_d("already connected, try reuse!"); } + while (_client->available() > 0) { + _client->read(); + } + return true; + } #ifdef HTTPCLIENT_1_1_COMPATIBLE - if(_transportTraits && !_client) { - _tcpDeprecated = _transportTraits->create(); - if(!_tcpDeprecated) { - log_e("failed to create client"); - return false; - } - _client = _tcpDeprecated.get(); - } + if (_transportTraits && !_client) { + _tcpDeprecated = _transportTraits->create(); + if (!_tcpDeprecated) { + log_e("failed to create client"); + return false; + } + _client = _tcpDeprecated.get(); + } #endif - if (!_client) { - log_d("HTTPClient::begin was not called or returned error"); - return false; - } + if (!_client) { + log_d("HTTPClient::begin was not called or returned error"); + return false; + } #ifdef HTTPCLIENT_1_1_COMPATIBLE - if (_tcpDeprecated && !_transportTraits->verify(*_client, _host.c_str())) { - log_d("transport level verify failed"); - _client->stop(); - return false; - } + if (_tcpDeprecated && !_transportTraits->verify(*_client, _host.c_str())) { + log_d("transport level verify failed"); + _client->stop(); + return false; + } #endif - if(!_client->connect(_host.c_str(), _port, _connectTimeout)) { - log_d("failed connect to %s:%u", _host.c_str(), _port); - return false; - } + if (!_client->connect(_host.c_str(), _port, _connectTimeout)) { + log_d("failed connect to %s:%u", _host.c_str(), _port); + return false; + } - // set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil() - _client->setTimeout((_tcpTimeout + 500) / 1000); + // set Timeout for NetworkClient and for Stream::readBytesUntil() and Stream::readStringUntil() + _client->setTimeout(_tcpTimeout); - log_d(" connected to %s:%u", _host.c_str(), _port); + log_d(" connected to %s:%u", _host.c_str(), _port); - -/* + /* #ifdef ESP8266 _client->setNoDelay(true); #endif */ - return connected(); + return connected(); } /** @@ -1195,177 +1124,172 @@ bool HTTPClient::connect(void) * @param type (GET, POST, ...) * @return status */ -bool HTTPClient::sendHeader(const char * type) -{ - if(!connected()) { - return false; - } +bool HTTPClient::sendHeader(const char *type) { + if (!connected()) { + return false; + } - String header = String(type) + " " + _uri + F(" HTTP/1."); + String header = String(type) + " " + _uri + F(" HTTP/1."); - if(_useHTTP10) { - header += "0"; - } else { - header += "1"; - } + if (_useHTTP10) { + header += "0"; + } else { + header += "1"; + } - header += String(F("\r\nHost: ")) + _host; - if (_port != 80 && _port != 443) - { - header += ':'; - header += String(_port); - } - header += String(F("\r\nUser-Agent: ")) + _userAgent + - F("\r\nConnection: "); + header += String(F("\r\nHost: ")) + _host; + if (_port != 80 && _port != 443) { + header += ':'; + header += String(_port); + } + header += String(F("\r\nUser-Agent: ")) + _userAgent + F("\r\nConnection: "); - if(_reuse) { - header += F("keep-alive"); - } else { - header += F("close"); - } + if (_reuse) { + header += F("keep-alive"); + } else { + header += F("close"); + } + header += "\r\n"; + + if (!_useHTTP10) { + header += String(F("Accept-Encoding: ")) + _acceptEncoding + F("\r\n"); + } + + if (_base64Authorization.length()) { + _base64Authorization.replace("\n", ""); + header += F("Authorization: "); + header += _authorizationType; + header += " "; + header += _base64Authorization; header += "\r\n"; + } - if(!_useHTTP10) { - header += F("Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0\r\n"); - } + header += _headers + "\r\n"; - if(_base64Authorization.length()) { - _base64Authorization.replace("\n", ""); - header += F("Authorization: "); - header += _authorizationType; - header += " "; - header += _base64Authorization; - header += "\r\n"; - } - - header += _headers + "\r\n"; - - return (_client->write((const uint8_t *) header.c_str(), header.length()) == header.length()); + return (_client->write((const uint8_t *)header.c_str(), header.length()) == header.length()); } /** * reads the response from the server * @return int http code */ -int HTTPClient::handleHeaderResponse() -{ +int HTTPClient::handleHeaderResponse() { - if(!connected()) { - return HTTPC_ERROR_NOT_CONNECTED; - } + if (!connected()) { + return HTTPC_ERROR_NOT_CONNECTED; + } - _returnCode = 0; - _size = -1; - _canReuse = _reuse; + _returnCode = 0; + _size = -1; + _canReuse = _reuse; - String transferEncoding; + String transferEncoding; - _transferEncoding = HTTPC_TE_IDENTITY; - unsigned long lastDataTime = millis(); - bool firstLine = true; - String date; + _transferEncoding = HTTPC_TE_IDENTITY; + unsigned long lastDataTime = millis(); + bool firstLine = true; + String date; - while(connected()) { - size_t len = _client->available(); - if(len > 0) { - String headerLine = _client->readStringUntil('\n'); - headerLine.trim(); // remove \r + while (connected()) { + size_t len = _client->available(); + if (len > 0) { + String headerLine = _client->readStringUntil('\n'); + headerLine.trim(); // remove \r - lastDataTime = millis(); + lastDataTime = millis(); - log_v("RX: '%s'", headerLine.c_str()); + log_v("RX: '%s'", headerLine.c_str()); - if(firstLine) { - firstLine = false; - if(_canReuse && headerLine.startsWith("HTTP/1.")) { - _canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0'); - } - int codePos = headerLine.indexOf(' ') + 1; - _returnCode = headerLine.substring(codePos, headerLine.indexOf(' ', codePos)).toInt(); - } else if(headerLine.indexOf(':')) { - String headerName = headerLine.substring(0, headerLine.indexOf(':')); - String headerValue = headerLine.substring(headerLine.indexOf(':') + 1); - headerValue.trim(); - - if(headerName.equalsIgnoreCase("Date")) { - date = headerValue; - } - - if(headerName.equalsIgnoreCase("Content-Length")) { - _size = headerValue.toInt(); - } - - if(_canReuse && headerName.equalsIgnoreCase("Connection")) { - if(headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) { - _canReuse = false; - } - } - - if(headerName.equalsIgnoreCase("Transfer-Encoding")) { - transferEncoding = headerValue; - } - - if (headerName.equalsIgnoreCase("Location")) { - _location = headerValue; - } - - if (headerName.equalsIgnoreCase("Set-Cookie")) { - setCookie(date, headerValue); - } - - for (size_t i = 0; i < _headerKeysCount; i++) { - if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { - // Uncomment the following lines if you need to add support for multiple headers with the same key: - // if (!_currentHeaders[i].value.isEmpty()) { - // // Existing value, append this one with a comma - // _currentHeaders[i].value += ','; - // _currentHeaders[i].value += headerValue; - // } else { - _currentHeaders[i].value = headerValue; - // } - break; // We found a match, stop looking - } - } - - } - - if(headerLine == "") { - log_d("code: %d", _returnCode); - - if(_size > 0) { - log_d("size: %d", _size); - } - - if(transferEncoding.length() > 0) { - log_d("Transfer-Encoding: %s", transferEncoding.c_str()); - if(transferEncoding.equalsIgnoreCase("chunked")) { - _transferEncoding = HTTPC_TE_CHUNKED; - } else if(transferEncoding.equalsIgnoreCase("identity")) { - _transferEncoding = HTTPC_TE_IDENTITY; - } else { - return HTTPC_ERROR_ENCODING; - } - } else { - _transferEncoding = HTTPC_TE_IDENTITY; - } - - if(_returnCode) { - return _returnCode; - } else { - log_d("Remote host is not an HTTP Server!"); - return HTTPC_ERROR_NO_HTTP_SERVER; - } - } - - } else { - if((millis() - lastDataTime) > _tcpTimeout) { - return HTTPC_ERROR_READ_TIMEOUT; - } - delay(10); + if (firstLine) { + firstLine = false; + if (_canReuse && headerLine.startsWith("HTTP/1.")) { + _canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0'); } - } + int codePos = headerLine.indexOf(' ') + 1; + _returnCode = headerLine.substring(codePos, headerLine.indexOf(' ', codePos)).toInt(); + } else if (headerLine.indexOf(':')) { + String headerName = headerLine.substring(0, headerLine.indexOf(':')); + String headerValue = headerLine.substring(headerLine.indexOf(':') + 1); + headerValue.trim(); - return HTTPC_ERROR_CONNECTION_LOST; + if (headerName.equalsIgnoreCase("Date")) { + date = headerValue; + } + + if (headerName.equalsIgnoreCase("Content-Length")) { + _size = headerValue.toInt(); + } + + if (_canReuse && headerName.equalsIgnoreCase("Connection")) { + if (headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) { + _canReuse = false; + } + } + + if (headerName.equalsIgnoreCase("Transfer-Encoding")) { + transferEncoding = headerValue; + } + + if (headerName.equalsIgnoreCase("Location")) { + _location = headerValue; + } + + if (headerName.equalsIgnoreCase("Set-Cookie")) { + setCookie(date, headerValue); + } + + for (size_t i = 0; i < _headerKeysCount; i++) { + if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { + // Uncomment the following lines if you need to add support for multiple headers with the same key: + // if (!_currentHeaders[i].value.isEmpty()) { + // // Existing value, append this one with a comma + // _currentHeaders[i].value += ','; + // _currentHeaders[i].value += headerValue; + // } else { + _currentHeaders[i].value = headerValue; + // } + break; // We found a match, stop looking + } + } + } + + if (headerLine == "") { + log_d("code: %d", _returnCode); + + if (_size > 0) { + log_d("size: %d", _size); + } + + if (transferEncoding.length() > 0) { + log_d("Transfer-Encoding: %s", transferEncoding.c_str()); + if (transferEncoding.equalsIgnoreCase("chunked")) { + _transferEncoding = HTTPC_TE_CHUNKED; + } else if (transferEncoding.equalsIgnoreCase("identity")) { + _transferEncoding = HTTPC_TE_IDENTITY; + } else { + return HTTPC_ERROR_ENCODING; + } + } else { + _transferEncoding = HTTPC_TE_IDENTITY; + } + + if (_returnCode) { + return _returnCode; + } else { + log_d("Remote host is not an HTTP Server!"); + return HTTPC_ERROR_NO_HTTP_SERVER; + } + } + + } else { + if ((millis() - lastDataTime) > _tcpTimeout) { + return HTTPC_ERROR_READ_TIMEOUT; + } + delay(10); + } + } + + return HTTPC_ERROR_CONNECTION_LOST; } /** @@ -1374,114 +1298,117 @@ int HTTPClient::handleHeaderResponse() * @param size int * @return < 0 = error >= 0 = size written */ -int HTTPClient::writeToStreamDataBlock(Stream * stream, int size) -{ - int buff_size = HTTP_TCP_BUFFER_SIZE; - int len = size; - int bytesWritten = 0; +int HTTPClient::writeToStreamDataBlock(Stream *stream, int size) { + int buff_size = HTTP_TCP_RX_BUFFER_SIZE; + int len = size; + int bytesWritten = 0; - // if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE - if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) { - buff_size = len; - } + // if possible create smaller buffer then HTTP_TCP_RX_BUFFER_SIZE + if ((len > 0) && (len < buff_size)) { + buff_size = len; + } - // create buffer for read - uint8_t * buff = (uint8_t *) malloc(buff_size); + // create buffer for read + uint8_t *buff = (uint8_t *)malloc(buff_size); - if(buff) { - // read all data from server - while(connected() && (len > 0 || len == -1)) { + if (buff) { + // read all data from server + while (connected() && (len > 0 || len == -1)) { - // get available data size - size_t sizeAvailable = _client->available(); + // get available data size + size_t sizeAvailable = buff_size; + if (len < 0) { + sizeAvailable = _client->available(); + } - if(sizeAvailable) { + if (sizeAvailable) { - int readBytes = sizeAvailable; + int readBytes = sizeAvailable; - // read only the asked bytes - if(len > 0 && readBytes > len) { - readBytes = len; - } - - // not read more the buffer can handle - if(readBytes > buff_size) { - readBytes = buff_size; - } - - // stop if no more reading - if (readBytes == 0) - break; - - // read data - int bytesRead = _client->readBytes(buff, readBytes); - - // write it to Stream - int bytesWrite = stream->write(buff, bytesRead); - bytesWritten += bytesWrite; - - // are all Bytes a writen to stream ? - if(bytesWrite != bytesRead) { - log_d("short write asked for %d but got %d retry...", bytesRead, bytesWrite); - - // check for write error - if(stream->getWriteError()) { - log_d("stream write error %d", stream->getWriteError()); - - //reset write error for retry - stream->clearWriteError(); - } - - // some time for the stream - delay(1); - - int leftBytes = (readBytes - bytesWrite); - - // retry to send the missed bytes - bytesWrite = stream->write((buff + bytesWrite), leftBytes); - bytesWritten += bytesWrite; - - if(bytesWrite != leftBytes) { - // failed again - log_w("short write asked for %d but got %d failed.", leftBytes, bytesWrite); - free(buff); - return HTTPC_ERROR_STREAM_WRITE; - } - } - - // check for write error - if(stream->getWriteError()) { - log_w("stream write error %d", stream->getWriteError()); - free(buff); - return HTTPC_ERROR_STREAM_WRITE; - } - - // count bytes to read left - if(len > 0) { - len -= readBytes; - } - - delay(0); - } else { - delay(1); - } + // read only the asked bytes + if (len > 0 && readBytes > len) { + readBytes = len; } - free(buff); + // not read more the buffer can handle + if (readBytes > buff_size) { + readBytes = buff_size; + } - log_d("connection closed or file end (written: %d).", bytesWritten); + // stop if no more reading + if (readBytes == 0) { + break; + } - if((size > 0) && (size != bytesWritten)) { - log_d("bytesWritten %d and size %d mismatch!.", bytesWritten, size); + // read data + int bytesRead = _client->readBytes(buff, readBytes); + + // write it to Stream + int bytesWrite = stream->write(buff, bytesRead); + bytesWritten += bytesWrite; + + // are all Bytes a written to stream ? + if (bytesWrite != bytesRead) { + log_d("short write asked for %d but got %d retry...", bytesRead, bytesWrite); + + // check for write error + if (stream->getWriteError()) { + log_d("stream write error %d", stream->getWriteError()); + + //reset write error for retry + stream->clearWriteError(); + } + + // some time for the stream + delay(1); + + int leftBytes = (bytesRead - bytesWrite); + + // retry to send the missed bytes + bytesWrite = stream->write((buff + bytesWrite), leftBytes); + bytesWritten += bytesWrite; + + if (bytesWrite != leftBytes) { + // failed again + log_w("short write asked for %d but got %d failed.", leftBytes, bytesWrite); + free(buff); return HTTPC_ERROR_STREAM_WRITE; + } } - } else { - log_w("too less ram! need %d", HTTP_TCP_BUFFER_SIZE); - return HTTPC_ERROR_TOO_LESS_RAM; + // check for write error + if (stream->getWriteError()) { + log_w("stream write error %d", stream->getWriteError()); + free(buff); + return HTTPC_ERROR_STREAM_WRITE; + } + + // count bytes to read left + if (len > 0) { + len -= bytesRead; + } + + delay(0); + } else { + delay(1); + } } - return bytesWritten; + free(buff); + + log_v("connection closed or file end (written: %d).", bytesWritten); + + if ((size > 0) && (size != bytesWritten)) { + log_d("bytesWritten %d and size %d mismatch!.", bytesWritten, size); + return HTTPC_ERROR_STREAM_WRITE; + } + + } else { + log_w("too less ram! need %d", buff_size); + return HTTPC_ERROR_TOO_LESS_RAM; + } + + return bytesWritten; } /** @@ -1489,232 +1416,230 @@ int HTTPClient::writeToStreamDataBlock(Stream * stream, int size) * @param error * @return error */ -int HTTPClient::returnError(int error) -{ - if(error < 0) { - log_w("error(%d): %s", error, errorToString(error).c_str()); - if(connected()) { - log_d("tcp stop"); - _client->stop(); - } +int HTTPClient::returnError(int error) { + if (error < 0) { + log_w("error(%d): %s", error, errorToString(error).c_str()); + if (connected()) { + log_d("tcp stop"); + _client->stop(); } - return error; + } + return error; } -void HTTPClient::setFollowRedirects(followRedirects_t follow) -{ - _followRedirects = follow; +void HTTPClient::setFollowRedirects(followRedirects_t follow) { + _followRedirects = follow; } -void HTTPClient::setRedirectLimit(uint16_t limit) -{ - _redirectLimit = limit; +void HTTPClient::setRedirectLimit(uint16_t limit) { + _redirectLimit = limit; } /** * set the URL to a new value. Handy for following redirects. * @param url */ -bool HTTPClient::setURL(const String& url) -{ - // if the new location is only a path then only update the URI - if (url && url[0] == '/') { - _uri = url; - clear(); - return true; - } +bool HTTPClient::setURL(const String &url) { + // if the new location is only a path then only update the URI + if (url && url[0] == '/') { + _uri = url; + clear(); + return true; + } - if (!url.startsWith(_protocol + ':')) { - log_d("new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str()); - return false; - } + if (!url.startsWith(_protocol + ':')) { + log_d("new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str()); + return false; + } - // check if the port is specified - int indexPort = url.indexOf(':', 6); // find the first ':' excluding the one from the protocol - int indexURI = url.indexOf('/', 7); // find where the URI starts to make sure the ':' is not part of it - if (indexPort == -1 || indexPort > indexURI) { - // the port is not specified - _port = (_protocol == "https" ? 443 : 80); - } + // check if the port is specified + int indexPort = url.indexOf(':', 6); // find the first ':' excluding the one from the protocol + int indexURI = url.indexOf('/', 7); // find where the URI starts to make sure the ':' is not part of it + if (indexPort == -1 || indexPort > indexURI) { + // the port is not specified + _port = (_protocol == "https" ? 443 : 80); + } - // disconnect but preserve _client. - // Also have to keep the connection otherwise it will free some of the memory used by _client - // and will blow up later when trying to do _client->available() or similar - _canReuse = true; - disconnect(true); - return beginInternal(url, _protocol.c_str()); + // disconnect but preserve _client. + // Also have to keep the connection otherwise it will free some of the memory used by _client + // and will blow up later when trying to do _client->available() or similar + _canReuse = true; + disconnect(true); + return beginInternal(url, _protocol.c_str()); } -const String &HTTPClient::getLocation(void) -{ - return _location; +const String &HTTPClient::getLocation(void) { + return _location; } -void HTTPClient::setCookieJar(CookieJar* cookieJar) -{ - _cookieJar = cookieJar; +void HTTPClient::setCookieJar(CookieJar *cookieJar) { + _cookieJar = cookieJar; } -void HTTPClient::resetCookieJar() -{ - _cookieJar = nullptr; +void HTTPClient::resetCookieJar() { + _cookieJar = nullptr; } -void HTTPClient::clearAllCookies() -{ - if (_cookieJar) _cookieJar->clear(); +void HTTPClient::clearAllCookies() { + if (_cookieJar) { + _cookieJar->clear(); + } } -void HTTPClient::setCookie(String date, String headerValue) -{ - if (!_cookieJar) - { - return; - } - #define HTTP_TIME_PATTERN "%a, %d %b %Y %H:%M:%S" +void HTTPClient::setCookie(String date, String headerValue) { + if (!_cookieJar) { + return; + } +#define HTTP_TIME_PATTERN "%a, %d %b %Y %H:%M:%S" - Cookie cookie; - String value; - int pos1, pos2; + Cookie cookie; + String value; + int pos1, pos2; - struct tm tm; - strptime(date.c_str(), HTTP_TIME_PATTERN, &tm); - cookie.date = mktime(&tm); + struct tm tm; + strptime(date.c_str(), HTTP_TIME_PATTERN, &tm); + cookie.date = mktime(&tm); - pos1 = headerValue.indexOf('='); - pos2 = headerValue.indexOf(';'); + pos1 = headerValue.indexOf('='); + pos2 = headerValue.indexOf(';'); - if (pos1 >= 0 && pos2 > pos1){ - cookie.name = headerValue.substring(0, pos1); - cookie.value = headerValue.substring(pos1 + 1, pos2); + if (pos1 >= 0 && pos2 > pos1) { + cookie.name = headerValue.substring(0, pos1); + cookie.value = headerValue.substring(pos1 + 1, pos2); + } else { + return; // invalid cookie header + } + + // only Cookie Attributes are case insensitive from this point on + headerValue.toLowerCase(); + + // expires + if (headerValue.indexOf("expires=") >= 0) { + pos1 = headerValue.indexOf("expires=") + strlen("expires="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) { + value = headerValue.substring(pos1, pos2); } else { - return; // invalid cookie header + value = headerValue.substring(pos1); } - // only Cookie Attributes are case insensitive from this point on - headerValue.toLowerCase(); + strptime(value.c_str(), HTTP_TIME_PATTERN, &tm); + cookie.expires.date = mktime(&tm); + cookie.expires.valid = true; + } - // expires - if (headerValue.indexOf("expires=") >= 0){ - pos1 = headerValue.indexOf("expires=") + strlen("expires="); - pos2 = headerValue.indexOf(';', pos1); + // max-age + if (headerValue.indexOf("max-age=") >= 0) { + pos1 = headerValue.indexOf("max-age=") + strlen("max-age="); + pos2 = headerValue.indexOf(';', pos1); - if (pos2 > pos1) - value = headerValue.substring(pos1, pos2); - else - value = headerValue.substring(pos1); - - strptime(value.c_str(), HTTP_TIME_PATTERN, &tm); - cookie.expires.date = mktime(&tm); - cookie.expires.valid = true; - } - - // max-age - if (headerValue.indexOf("max-age=") >= 0){ - pos1 = headerValue.indexOf("max-age=") + strlen("max-age="); - pos2 = headerValue.indexOf(';', pos1); - - if (pos2 > pos1) - value = headerValue.substring(pos1, pos2); - else - value = headerValue.substring(pos1); - - cookie.max_age.duration = value.toInt(); - cookie.max_age.valid = true; - } - - // domain - if (headerValue.indexOf("domain=") >= 0){ - pos1 = headerValue.indexOf("domain=") + strlen("domain="); - pos2 = headerValue.indexOf(';', pos1); - - if (pos2 > pos1) - value = headerValue.substring(pos1, pos2); - else - value = headerValue.substring(pos1); - - if (value.startsWith(".")) value.remove(0, 1); - - if (_host.indexOf(value) >= 0) { - cookie.domain = value; - } else { - return; // server tries to set a cookie on a different domain; ignore it - } + if (pos2 > pos1) { + value = headerValue.substring(pos1, pos2); } else { - pos1 = _host.lastIndexOf('.', _host.lastIndexOf('.') - 1); - if (pos1 >= 0) - cookie.domain = _host.substring(pos1 + 1); - else - cookie.domain = _host; + value = headerValue.substring(pos1); } - // path - if (headerValue.indexOf("path=") >= 0){ - pos1 = headerValue.indexOf("path=") + strlen("path="); - pos2 = headerValue.indexOf(';', pos1); + cookie.max_age.duration = value.toInt(); + cookie.max_age.valid = true; + } - if (pos2 > pos1) - cookie.path = headerValue.substring(pos1, pos2); - else - cookie.path = headerValue.substring(pos1); + // domain + if (headerValue.indexOf("domain=") >= 0) { + pos1 = headerValue.indexOf("domain=") + strlen("domain="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) { + value = headerValue.substring(pos1, pos2); + } else { + value = headerValue.substring(pos1); } - // HttpOnly - cookie.http_only = (headerValue.indexOf("httponly") >= 0); - - // secure - cookie.secure = (headerValue.indexOf("secure") >= 0); - - // overwrite or delete cookie in/from cookie jar - time_t now_local = time(NULL); - time_t now_gmt = mktime(gmtime(&now_local)); - - bool found = false; - - for (auto c = _cookieJar->begin(); c != _cookieJar->end(); ++c) { - if (c->domain == cookie.domain && c->name == cookie.name) { - // when evaluating, max-age takes precedence over expires if both are defined - if ((cookie.max_age.valid && ((cookie.date + cookie.max_age.duration) < now_gmt)) || cookie.max_age.duration <= 0 - || (!cookie.max_age.valid && cookie.expires.valid && cookie.expires.date < now_gmt)) { - _cookieJar->erase(c); - c--; - } else { - *c = cookie; - } - found = true; - } + if (value.startsWith(".")) { + value.remove(0, 1); } - // add cookie to jar - if (!found && !(cookie.max_age.valid && cookie.max_age.duration <= 0)) - _cookieJar->push_back(cookie); + if (_host.indexOf(value) >= 0) { + cookie.domain = value; + } else { + return; // server tries to set a cookie on a different domain; ignore it + } + } else { + pos1 = _host.lastIndexOf('.', _host.lastIndexOf('.') - 1); + if (pos1 >= 0) { + cookie.domain = _host.substring(pos1 + 1); + } else { + cookie.domain = _host; + } + } + // path + if (headerValue.indexOf("path=") >= 0) { + pos1 = headerValue.indexOf("path=") + strlen("path="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) { + cookie.path = headerValue.substring(pos1, pos2); + } else { + cookie.path = headerValue.substring(pos1); + } + } + + // HttpOnly + cookie.http_only = (headerValue.indexOf("httponly") >= 0); + + // secure + cookie.secure = (headerValue.indexOf("secure") >= 0); + + // overwrite or delete cookie in/from cookie jar + time_t now_local = time(NULL); + time_t now_gmt = mktime(gmtime(&now_local)); + + bool found = false; + + for (auto c = _cookieJar->begin(); c != _cookieJar->end(); ++c) { + if (c->domain == cookie.domain && c->name == cookie.name) { + // when evaluating, max-age takes precedence over expires if both are defined + if ((cookie.max_age.valid && ((cookie.date + cookie.max_age.duration) < now_gmt)) || cookie.max_age.duration <= 0 + || (!cookie.max_age.valid && cookie.expires.valid && cookie.expires.date < now_gmt)) { + _cookieJar->erase(c); + c--; + } else { + *c = cookie; + } + found = true; + } + } + + // add cookie to jar + if (!found && !(cookie.max_age.valid && cookie.max_age.duration <= 0)) { + _cookieJar->push_back(cookie); + } } -bool HTTPClient::generateCookieString(String *cookieString) -{ - time_t now_local = time(NULL); - time_t now_gmt = mktime(gmtime(&now_local)); +bool HTTPClient::generateCookieString(String *cookieString) { + time_t now_local = time(NULL); + time_t now_gmt = mktime(gmtime(&now_local)); - *cookieString = ""; - bool found = false; + *cookieString = ""; + bool found = false; - if (!_cookieJar) - { - return false; - } - for (auto c = _cookieJar->begin(); c != _cookieJar->end(); ++c) { - if ((c->max_age.valid && ((c->date + c->max_age.duration) < now_gmt)) || (!c->max_age.valid && c->expires.valid && c->expires.date < now_gmt)) { - _cookieJar->erase(c); - c--; - } else if (_host.indexOf(c->domain) >= 0 && (!c->secure || _secure) ) { - if (*cookieString == "") - *cookieString = c->name + "=" + c->value; - else - *cookieString += " ;" + c->name + "=" + c->value; - found = true; - } + if (!_cookieJar) { + return false; + } + for (auto c = _cookieJar->begin(); c != _cookieJar->end(); ++c) { + if ((c->max_age.valid && ((c->date + c->max_age.duration) < now_gmt)) || (!c->max_age.valid && c->expires.valid && c->expires.date < now_gmt)) { + _cookieJar->erase(c); + c--; + } else if (_host.indexOf(c->domain) >= 0 && (!c->secure || _secure)) { + if (*cookieString == "") { + *cookieString = c->name + "=" + c->value; + } else { + *cookieString += " ;" + c->name + "=" + c->value; + } + found = true; } + } - return found; -} \ No newline at end of file + return found; +} diff --git a/lib/HTTPClient/src/HTTPClient.h b/lib/HTTPClient/src/HTTPClient.h index b1527ad..80f6da2 100644 --- a/lib/HTTPClient/src/HTTPClient.h +++ b/lib/HTTPClient/src/HTTPClient.h @@ -5,8 +5,8 @@ * * Copyright (c) 2015 Markus Sattler. All rights reserved. * This file is part of the HTTPClient for Arduino. - * Port to ESP32 by Evandro Luis Copercini (2017), - * changed fingerprints to CA verification. + * Port to ESP32 by Evandro Luis Copercini (2017), + * changed fingerprints to CA verification. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,12 +33,10 @@ #include #include -#include -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) -#include -#else +#include +#ifndef HTTPCLIENT_NOSECURE #include -#endif +#endif // HTTPCLIENT_NOSECURE /// Cookie jar support #include @@ -59,73 +57,74 @@ #define HTTPC_ERROR_READ_TIMEOUT (-11) /// size for the stream handling -#define HTTP_TCP_BUFFER_SIZE (1460) +#define HTTP_TCP_RX_BUFFER_SIZE (4096) +#define HTTP_TCP_TX_BUFFER_SIZE (1460) /// HTTP codes see RFC7231 typedef enum { - HTTP_CODE_CONTINUE = 100, - HTTP_CODE_SWITCHING_PROTOCOLS = 101, - HTTP_CODE_PROCESSING = 102, - HTTP_CODE_OK = 200, - HTTP_CODE_CREATED = 201, - HTTP_CODE_ACCEPTED = 202, - HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203, - HTTP_CODE_NO_CONTENT = 204, - HTTP_CODE_RESET_CONTENT = 205, - HTTP_CODE_PARTIAL_CONTENT = 206, - HTTP_CODE_MULTI_STATUS = 207, - HTTP_CODE_ALREADY_REPORTED = 208, - HTTP_CODE_IM_USED = 226, - HTTP_CODE_MULTIPLE_CHOICES = 300, - HTTP_CODE_MOVED_PERMANENTLY = 301, - HTTP_CODE_FOUND = 302, - HTTP_CODE_SEE_OTHER = 303, - HTTP_CODE_NOT_MODIFIED = 304, - HTTP_CODE_USE_PROXY = 305, - HTTP_CODE_TEMPORARY_REDIRECT = 307, - HTTP_CODE_PERMANENT_REDIRECT = 308, - HTTP_CODE_BAD_REQUEST = 400, - HTTP_CODE_UNAUTHORIZED = 401, - HTTP_CODE_PAYMENT_REQUIRED = 402, - HTTP_CODE_FORBIDDEN = 403, - HTTP_CODE_NOT_FOUND = 404, - HTTP_CODE_METHOD_NOT_ALLOWED = 405, - HTTP_CODE_NOT_ACCEPTABLE = 406, - HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407, - HTTP_CODE_REQUEST_TIMEOUT = 408, - HTTP_CODE_CONFLICT = 409, - HTTP_CODE_GONE = 410, - HTTP_CODE_LENGTH_REQUIRED = 411, - HTTP_CODE_PRECONDITION_FAILED = 412, - HTTP_CODE_PAYLOAD_TOO_LARGE = 413, - HTTP_CODE_URI_TOO_LONG = 414, - HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415, - HTTP_CODE_RANGE_NOT_SATISFIABLE = 416, - HTTP_CODE_EXPECTATION_FAILED = 417, - HTTP_CODE_MISDIRECTED_REQUEST = 421, - HTTP_CODE_UNPROCESSABLE_ENTITY = 422, - HTTP_CODE_LOCKED = 423, - HTTP_CODE_FAILED_DEPENDENCY = 424, - HTTP_CODE_UPGRADE_REQUIRED = 426, - HTTP_CODE_PRECONDITION_REQUIRED = 428, - HTTP_CODE_TOO_MANY_REQUESTS = 429, - HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, - HTTP_CODE_INTERNAL_SERVER_ERROR = 500, - HTTP_CODE_NOT_IMPLEMENTED = 501, - HTTP_CODE_BAD_GATEWAY = 502, - HTTP_CODE_SERVICE_UNAVAILABLE = 503, - HTTP_CODE_GATEWAY_TIMEOUT = 504, - HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505, - HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506, - HTTP_CODE_INSUFFICIENT_STORAGE = 507, - HTTP_CODE_LOOP_DETECTED = 508, - HTTP_CODE_NOT_EXTENDED = 510, - HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511 + HTTP_CODE_CONTINUE = 100, + HTTP_CODE_SWITCHING_PROTOCOLS = 101, + HTTP_CODE_PROCESSING = 102, + HTTP_CODE_OK = 200, + HTTP_CODE_CREATED = 201, + HTTP_CODE_ACCEPTED = 202, + HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203, + HTTP_CODE_NO_CONTENT = 204, + HTTP_CODE_RESET_CONTENT = 205, + HTTP_CODE_PARTIAL_CONTENT = 206, + HTTP_CODE_MULTI_STATUS = 207, + HTTP_CODE_ALREADY_REPORTED = 208, + HTTP_CODE_IM_USED = 226, + HTTP_CODE_MULTIPLE_CHOICES = 300, + HTTP_CODE_MOVED_PERMANENTLY = 301, + HTTP_CODE_FOUND = 302, + HTTP_CODE_SEE_OTHER = 303, + HTTP_CODE_NOT_MODIFIED = 304, + HTTP_CODE_USE_PROXY = 305, + HTTP_CODE_TEMPORARY_REDIRECT = 307, + HTTP_CODE_PERMANENT_REDIRECT = 308, + HTTP_CODE_BAD_REQUEST = 400, + HTTP_CODE_UNAUTHORIZED = 401, + HTTP_CODE_PAYMENT_REQUIRED = 402, + HTTP_CODE_FORBIDDEN = 403, + HTTP_CODE_NOT_FOUND = 404, + HTTP_CODE_METHOD_NOT_ALLOWED = 405, + HTTP_CODE_NOT_ACCEPTABLE = 406, + HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407, + HTTP_CODE_REQUEST_TIMEOUT = 408, + HTTP_CODE_CONFLICT = 409, + HTTP_CODE_GONE = 410, + HTTP_CODE_LENGTH_REQUIRED = 411, + HTTP_CODE_PRECONDITION_FAILED = 412, + HTTP_CODE_PAYLOAD_TOO_LARGE = 413, + HTTP_CODE_URI_TOO_LONG = 414, + HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_CODE_RANGE_NOT_SATISFIABLE = 416, + HTTP_CODE_EXPECTATION_FAILED = 417, + HTTP_CODE_MISDIRECTED_REQUEST = 421, + HTTP_CODE_UNPROCESSABLE_ENTITY = 422, + HTTP_CODE_LOCKED = 423, + HTTP_CODE_FAILED_DEPENDENCY = 424, + HTTP_CODE_UPGRADE_REQUIRED = 426, + HTTP_CODE_PRECONDITION_REQUIRED = 428, + HTTP_CODE_TOO_MANY_REQUESTS = 429, + HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HTTP_CODE_INTERNAL_SERVER_ERROR = 500, + HTTP_CODE_NOT_IMPLEMENTED = 501, + HTTP_CODE_BAD_GATEWAY = 502, + HTTP_CODE_SERVICE_UNAVAILABLE = 503, + HTTP_CODE_GATEWAY_TIMEOUT = 504, + HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506, + HTTP_CODE_INSUFFICIENT_STORAGE = 507, + HTTP_CODE_LOOP_DETECTED = 508, + HTTP_CODE_NOT_EXTENDED = 510, + HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511 } t_http_codes; typedef enum { - HTTPC_TE_IDENTITY, - HTTPC_TE_CHUNKED + HTTPC_TE_IDENTITY, + HTTPC_TE_CHUNKED } transferEncoding_t; /** @@ -140,176 +139,184 @@ typedef enum { * In the sense of the RFC, it's just like every redirection is confirmed. */ typedef enum { - HTTPC_DISABLE_FOLLOW_REDIRECTS, - HTTPC_STRICT_FOLLOW_REDIRECTS, - HTTPC_FORCE_FOLLOW_REDIRECTS + HTTPC_DISABLE_FOLLOW_REDIRECTS, + HTTPC_STRICT_FOLLOW_REDIRECTS, + HTTPC_FORCE_FOLLOW_REDIRECTS } followRedirects_t; - #ifdef HTTPCLIENT_1_1_COMPATIBLE class TransportTraits; typedef std::unique_ptr TransportTraitsPtr; #endif // cookie jar support -typedef struct { - String host; // host which tries to set the cookie - time_t date; // timestamp of the response that set the cookie - String name; - String value; - String domain; - String path = ""; - struct { - time_t date = 0; - bool valid = false; - } expires; - struct { - time_t duration = 0; - bool valid = false; - } max_age; - bool http_only = false; - bool secure = false; +typedef struct { + String host; // host which tries to set the cookie + time_t date; // timestamp of the response that set the cookie + String name; + String value; + String domain; + String path = ""; + struct { + time_t date = 0; + bool valid = false; + } expires; + struct { + time_t duration = 0; + bool valid = false; + } max_age; + bool http_only = false; + bool secure = false; } Cookie; typedef std::vector CookieJar; - -class HTTPClient -{ +class HTTPClient { public: - HTTPClient(); - ~HTTPClient(); + HTTPClient(); + ~HTTPClient(); -/* - * Since both begin() functions take a reference to client as a parameter, you need to + /* + * Since both begin() functions take a reference to client as a parameter, you need to * ensure the client object lives the entire time of the HTTPClient */ - bool begin(WiFiClient &client, String url); - bool begin(WiFiClient &client, String host, uint16_t port, String uri = "/", bool https = false); + bool begin(NetworkClient &client, String url); + bool begin(NetworkClient &client, String host, uint16_t port, String uri = "/", bool https = false); #ifdef HTTPCLIENT_1_1_COMPATIBLE - bool begin(String url); - bool begin(String url, const char* CAcert); - bool begin(String host, uint16_t port, String uri = "/"); - bool begin(String host, uint16_t port, String uri, const char* CAcert); - bool begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key); + bool begin(String url); + bool begin(String host, uint16_t port, String uri = "/"); +#ifndef HTTPCLIENT_NOSECURE + bool begin(String url, const char *CAcert); + bool begin(String host, uint16_t port, String uri, const char *CAcert); + bool begin(String host, uint16_t port, String uri, const char *CAcert, const char *cli_cert, const char *cli_key); +#else + bool begin(String url, const char *CAcert) { + return false; + }; + bool begin(String host, uint16_t port, String uri, const char *CAcert) { + return false; + }; + bool begin(String host, uint16_t port, String uri, const char *CAcert, const char *cli_cert, const char *cli_key) { + return false; + }; +#endif // HTTPCLIENT_NOSECURE + #endif - void end(void); + void end(void); - bool connected(void); + bool connected(void); - void setReuse(bool reuse); /// keep-alive - void setUserAgent(const String& userAgent); - void setAuthorization(const char * user, const char * password); - void setAuthorization(const char * auth); - void setAuthorizationType(const char * authType); - void setConnectTimeout(int32_t connectTimeout); - void setTimeout(uint16_t timeout); + void setReuse(bool reuse); /// keep-alive + void setUserAgent(const String &userAgent); + void setAcceptEncoding(const String &acceptEncoding); + void setAuthorization(const char *user, const char *password); + void setAuthorization(const char *auth); + void setAuthorizationType(const char *authType); + void setConnectTimeout(int32_t connectTimeout); + void setTimeout(uint16_t timeout); - // Redirections - void setFollowRedirects(followRedirects_t follow); - void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request + // Redirections + void setFollowRedirects(followRedirects_t follow); + void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request - bool setURL(const String &url); - void useHTTP10(bool usehttp10 = true); + bool setURL(const String &url); + void useHTTP10(bool usehttp10 = true); - /// request handling - int GET(); - int PATCH(uint8_t * payload, size_t size); - int PATCH(String payload); - int POST(uint8_t * payload, size_t size); - int POST(String payload); - int PUT(uint8_t * payload, size_t size); - int PUT(String payload); - int sendRequest(const char * type, String payload); - int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0); - int sendRequest(const char * type, Stream * stream, size_t size = 0); + /// request handling + int GET(); + int PATCH(uint8_t *payload, size_t size); + int PATCH(String payload); + int POST(uint8_t *payload, size_t size); + int POST(String payload); + int PUT(uint8_t *payload, size_t size); + int PUT(String payload); + int sendRequest(const char *type, String payload); + int sendRequest(const char *type, uint8_t *payload = NULL, size_t size = 0); + int sendRequest(const char *type, Stream *stream, size_t size = 0); - void addHeader(const String& name, const String& value, bool first = false, bool replace = true); + void addHeader(const String &name, const String &value, bool first = false, bool replace = true); - /// 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 + /// 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); + const String &getLocation(void); - int getSize(void); - const String &getLocation(void); + NetworkClient &getStream(void); + NetworkClient *getStreamPtr(void); + int writeToStream(Stream *stream); + String getString(void); - WiFiClient& getStream(void); - WiFiClient* getStreamPtr(void); - int writeToStream(Stream* stream); - String getString(void); + static String errorToString(int error); - static String errorToString(int error); - - /// Cookie jar support - void setCookieJar(CookieJar* cookieJar); - void resetCookieJar(); - void clearAllCookies(); + /// Cookie jar support + void setCookieJar(CookieJar *cookieJar); + void resetCookieJar(); + void clearAllCookies(); protected: - struct RequestArgument { - String key; - String value; - }; + struct RequestArgument { + String key; + String value; + }; - bool beginInternal(String url, const char* expectedProtocol); - void disconnect(bool preserveClient = false); - void clear(); - int returnError(int error); - bool connect(void); - bool sendHeader(const char * type); - int handleHeaderResponse(); - int writeToStreamDataBlock(Stream * stream, int len); + bool beginInternal(String url, const char *expectedProtocol); + void disconnect(bool preserveClient = false); + void clear(); + int returnError(int error); + bool connect(void); + bool sendHeader(const char *type); + int handleHeaderResponse(); + int writeToStreamDataBlock(Stream *stream, int len); - /// Cookie jar support - void setCookie(String date, String headerValue); - bool generateCookieString(String *cookieString); + /// Cookie jar support + void setCookie(String date, String headerValue); + bool generateCookieString(String *cookieString); #ifdef HTTPCLIENT_1_1_COMPATIBLE - TransportTraitsPtr _transportTraits; - std::unique_ptr _tcpDeprecated; + TransportTraitsPtr _transportTraits; + std::unique_ptr _tcpDeprecated; #endif - WiFiClient* _client = nullptr; + NetworkClient *_client = nullptr; - /// request handling - String _host; - uint16_t _port = 0; - int32_t _connectTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; - bool _reuse = true; - uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; - bool _useHTTP10 = false; - bool _secure = false; + /// request handling + String _host; + uint16_t _port = 0; + int32_t _connectTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; + bool _reuse = true; + uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; + bool _useHTTP10 = false; + bool _secure = false; - String _uri; - String _protocol; - String _headers; - String _userAgent = "ESP32HTTPClient"; - String _base64Authorization; - String _authorizationType = "Basic"; + String _uri; + String _protocol; + String _headers; + String _userAgent = "ESP32HTTPClient"; + String _base64Authorization; + String _authorizationType = "Basic"; + String _acceptEncoding = "identity;q=1,chunked;q=0.1,*;q=0"; - /// Response handling - RequestArgument* _currentHeaders = nullptr; - size_t _headerKeysCount = 0; + /// Response handling + RequestArgument *_currentHeaders = nullptr; + size_t _headerKeysCount = 0; - int _returnCode = 0; - int _size = -1; - bool _canReuse = false; - followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS; - uint16_t _redirectLimit = 10; - String _location; - transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY; - - /// Cookie jar support - CookieJar* _cookieJar = nullptr; + int _returnCode = 0; + int _size = -1; + bool _canReuse = false; + followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS; + uint16_t _redirectLimit = 10; + String _location; + transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY; + /// Cookie jar support + CookieJar *_cookieJar = nullptr; }; - - -#endif /* HTTPClient_H_ */ \ No newline at end of file +#endif /* HTTPClient_H_ */ diff --git a/lib/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino b/lib/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino index 3339068..0f95826 100644 --- a/lib/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino +++ b/lib/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino @@ -18,27 +18,37 @@ const char *server = "www.howsmyssl.com"; // Server URL // change it to your server root CA // SHA1 fingerprint is broken now! -const char *test_root_ca = "-----BEGIN CERTIFICATE-----\n" - "MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" - "MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" - "DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" - "PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" - "Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" - "AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" - "rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" - "OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" - "xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" - "7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" - "aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" - "HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" - "SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" - "ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" - "AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" - "R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" - "JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" - "Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" - "-----END CERTIFICATE-----\n"; - +const char *test_root_ca = R"literal( +-----BEGIN CERTIFICATE----- +MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL +YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a +/6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4 +FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR +mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3 +DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG +MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/ +AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5 +tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG +Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD +VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B +AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo +zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd +u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9 +1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0 +GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh +1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ +QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N +4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz +rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei +RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx +KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54= +-----END CERTIFICATE----- +)literal"; // You can use x.509 client certificates if you want //const char* test_client_key = ""; //to verify the client //const char* test_client_cert = ""; //to verify the client diff --git a/lib/NetworkClientSecure/library.properties b/lib/NetworkClientSecure/library.properties index dd4b6a1..e7dab6a 100644 --- a/lib/NetworkClientSecure/library.properties +++ b/lib/NetworkClientSecure/library.properties @@ -1,5 +1,5 @@ name=NetworkClientSecure -version=2.0.0 +version=3.0.3 author=Evandro Luis Copercini maintainer=Github Community sentence=Enables secure network connection (local and Internet) using the ESP32 built-in WiFi. diff --git a/lib/NetworkClientSecure/src/NetworkClientSecure.cpp b/lib/NetworkClientSecure/src/NetworkClientSecure.cpp index d5e3b63..908ddb2 100644 --- a/lib/NetworkClientSecure/src/NetworkClientSecure.cpp +++ b/lib/NetworkClientSecure/src/NetworkClientSecure.cpp @@ -305,9 +305,11 @@ int NetworkClientSecure::available() { res = data_to_read(sslclient.get()); if (res < 0 && !_stillinPlainStart) { - log_e("Closing connection on failed available check"); + if (res != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + log_e("Closing connection on failed available check"); + } stop(); - return peeked ? peeked : res; + return peeked; } return res + peeked; } @@ -337,9 +339,9 @@ void NetworkClientSecure::setCACert(const char *rootCA) { _use_insecure = false; } -void NetworkClientSecure::setCACertBundle(const uint8_t *bundle) { - if (bundle != NULL) { - esp_crt_bundle_set(bundle, sizeof(bundle)); +void NetworkClientSecure::setCACertBundle(const uint8_t *bundle, size_t size) { + if (bundle != NULL && size > 0) { + esp_crt_bundle_set(bundle, size); attach_ssl_certificate_bundle(sslclient.get(), true); _use_ca_bundle = true; } else { @@ -349,6 +351,11 @@ void NetworkClientSecure::setCACertBundle(const uint8_t *bundle) { } } +void NetworkClientSecure::setDefaultCACertBundle() { + attach_ssl_certificate_bundle(sslclient.get(), true); + _use_ca_bundle = true; +} + void NetworkClientSecure::setCertificate(const char *client_ca) { if (_cert_free && _cert) { free((void *)_cert); diff --git a/lib/NetworkClientSecure/src/NetworkClientSecure.h b/lib/NetworkClientSecure/src/NetworkClientSecure.h index 147acbe..ebfcf76 100644 --- a/lib/NetworkClientSecure/src/NetworkClientSecure.h +++ b/lib/NetworkClientSecure/src/NetworkClientSecure.h @@ -73,7 +73,8 @@ public: void setCertificate(const char *client_ca); void setPrivateKey(const char *private_key); bool loadCACert(Stream &stream, size_t size); - void setCACertBundle(const uint8_t *bundle); + void setCACertBundle(const uint8_t *bundle, size_t size); + void setDefaultCACertBundle(); bool loadCertificate(Stream &stream, size_t size); bool loadPrivateKey(Stream &stream, size_t size); bool verify(const char *fingerprint, const char *domain_name); diff --git a/lib/NetworkClientSecure/src/WiFiClientSecure.h b/lib/NetworkClientSecure/src/WiFiClientSecure.h index b4d6962..56e7f28 100644 --- a/lib/NetworkClientSecure/src/WiFiClientSecure.h +++ b/lib/NetworkClientSecure/src/WiFiClientSecure.h @@ -1,3 +1,3 @@ #pragma once #include "NetworkClientSecure.h" -#define WiFiClientSecure NetworkClientSecure +typedef NetworkClientSecure WiFiClientSecure; diff --git a/lib/NetworkClientSecure/src/ssl_client.cpp b/lib/NetworkClientSecure/src/ssl_client.cpp index c8d5bbd..0f93f5c 100644 --- a/lib/NetworkClientSecure/src/ssl_client.cpp +++ b/lib/NetworkClientSecure/src/ssl_client.cpp @@ -27,7 +27,7 @@ const char *pers = "esp32-tls"; static int _handle_error(int err, const char *function, int line) { - if (err == -30848) { + if (err == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { return err; } #ifdef MBEDTLS_ERROR_C diff --git a/pio_package.py b/pio_package.py index f142e26..46e1135 100644 --- a/pio_package.py +++ b/pio_package.py @@ -7,8 +7,6 @@ from pathlib import Path def get_board_name(env): board = env.get('BOARD_MCU') - if env.get('BOARD') == 'esp32-solo1': - board = env.get('BOARD').replace('-', '') return board def create_target_dir(env): @@ -37,9 +35,6 @@ def merge_bin(source, target, env): #if not env.get('BUILD_TYPE') in ['release']: # return - if env.get('BOARD') in ['esp32-solo1']: - return - board = get_board_name(env) chip = env.get('BOARD_MCU') target_dir = create_target_dir(env) diff --git a/platformio.ini b/platformio.ini index a19c296..1ac47d0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,7 +59,7 @@ monitor_filters = [env:esp32dev] board = esp32dev -extra_scripts = +extra_scripts = pre:pio_package_pre.py post:pio_package.py build_flags = @@ -86,29 +86,6 @@ board = nuki-esp32-s3 extends = env:esp32dev board = esp32-c6-devkitm-1 -[env:esp32solo1] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32-2023.10.03.zip -framework = arduino -board = esp32-solo1 -extra_scripts = - pre:pio_package_pre.py - post:pio_package.py -build_flags = - ${env.build_flags} - -DFRAMEWORK_ARDUINO_SOLO1 - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE - -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0 - -DCONFIG_BT_NIMBLE_LOG_LEVEL=0 - -DNUKI_ALT_CONNECT - -DNUKI_64BIT_TIME -lib_deps = - BleScanner=symlink://lib/BleScanner -lib_ignore = - esp-nimble-cpp - NetworkClientSecure - ESPAsyncTCP-esphome - AsyncTCP_RP2040W - [env:esp32dev_dbg] extends = env:esp32dev custom_build = debug @@ -195,22 +172,4 @@ build_flags = -DDEBUG_NUKI_CONNECT -DDEBUG_NUKI_COMMUNICATION ;-DDEBUG_NUKI_HEX_DATA - -DDEBUG_NUKI_READABLE_DATA - -[env:esp32solo1_dbg] -extends = env:esp32solo1 -custom_build = debug -build_flags = - ${env.build_flags} - -DFRAMEWORK_ARDUINO_SOLO1 - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG - -DCONFIG_NIMBLE_CPP_LOG_LEVEL=0 - -DNUKI_ALT_CONNECT - -DNUKI_64BIT_TIME - -DDEBUG_NUKIHUB - -DDEBUG_SENSE_NUKI - -DDEBUG_NUKI_COMMAND - -DDEBUG_NUKI_CONNECT - -DDEBUG_NUKI_COMMUNICATION - ;-DDEBUG_NUKI_HEX_DATA -DDEBUG_NUKI_READABLE_DATA \ No newline at end of file diff --git a/resources/how-to-flash.txt b/resources/how-to-flash.txt index c282568..9c4e243 100644 --- a/resources/how-to-flash.txt +++ b/resources/how-to-flash.txt @@ -15,8 +15,6 @@ Howto flash (Webflash) -Click on "Next" -Click on "Install" -NOTE: Webflash is not available for the ESP32-Solo1 - Howto flash (Espressif Flash Download Tools) -- @@ -52,13 +50,6 @@ e000 boot_app0.bin 10000 nuki_hub_esp32c6.bin 280000 nuki_hub_updater_esp32c6.bin -ESP32SOLO1 -e000 boot_app0.bin -1000 bootloader.bin -8000 nuki_hub.partitions.bin -10000 nuki_hub_esp32solo1.bin -280000 nuki_hub_updater_esp32solo1.bin - Make sure the checkmarks for all files are enabled. - Select the COM-Port the ESP device is connected to @@ -87,8 +78,4 @@ esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 921600 --before default_res esptool.py --chip esp32c6 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0xe000 boot_app0.bin 0x0 bootloader.bin 0x10000 nuki_hub_esp32c6.bin 0x280000 nuki_hub_updater_esp32c6.bin 0x8000 nuki_hub.partitions.bin -## ESP32SOLO1 - -esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader.bin 0x10000 nuki_hub_esp32solo1.bin 0x280000 nuki_hub_updater_esp32solo1.bin 0x8000 nuki_hub.partitions.bin - Adjust the serial device and path to the binaries if necessary. \ No newline at end of file diff --git a/src/Config.h b/src/Config.h index af8a0c6..c90a0e3 100644 --- a/src/Config.h +++ b/src/Config.h @@ -7,7 +7,6 @@ #define NUKI_HUB_DATE "unknownbuilddate" #define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" -#define GITHUB_LATEST_RELEASE_API_URL (char*)"https://api.github.com/repos/technyon/nuki_hub/releases/latest" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json" #if defined(CONFIG_IDF_TARGET_ESP32C3) @@ -32,14 +31,6 @@ #define GITHUB_MASTER_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/master/nuki_hub_esp32c6.bin" #define GITHUB_MASTER_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/master/nuki_hub_updater_esp32c6.bin" #else -#if defined(FRAMEWORK_ARDUINO_SOLO1) -#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32solo1.bin" -#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32solo1.bin" -#define GITHUB_BETA_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/beta/nuki_hub_esp32solo1.bin" -#define GITHUB_BETA_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/beta/nuki_hub_updater_esp32solo1.bin" -#define GITHUB_MASTER_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/master/nuki_hub_esp32solo1.bin" -#define GITHUB_MASTER_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/master/nuki_hub_updater_esp32solo1.bin" -#else #define GITHUB_LATEST_RELEASE_BINARY_URL "https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32.bin" #define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32.bin" #define GITHUB_BETA_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/beta/nuki_hub_esp32.bin" @@ -47,7 +38,6 @@ #define GITHUB_MASTER_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/master/nuki_hub_esp32.bin" #define GITHUB_MASTER_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/master/nuki_hub_updater_esp32.bin" #endif -#endif #ifndef NUKI_HUB_UPDATER #define MQTT_QOS_LEVEL 1 diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp index 5a4b263..6571d56 100644 --- a/src/NukiNetwork.cpp +++ b/src/NukiNetwork.cpp @@ -5,6 +5,8 @@ #include "Logger.h" #include "Config.h" #include "RestartReason.h" +#include +#include #if defined(CONFIG_IDF_TARGET_ESP32) #include "networkDevices/EthLan8720Device.h" #endif @@ -484,30 +486,38 @@ bool NukiNetwork::update() { _lastUpdateCheckTs = ts; - https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - https.useHTTP10(true); - https.begin(GITHUB_OTA_MANIFEST_URL); - - int httpResponseCode = https.GET(); - - if (httpResponseCode == HTTP_CODE_OK || httpResponseCode == HTTP_CODE_MOVED_PERMANENTLY) - { - JsonDocument doc; - DeserializationError jsonError = deserializeJson(doc, https.getStream()); - - if (!jsonError) + NetworkClientSecure *client = new NetworkClientSecure; + if (client) { + client->setDefaultCACertBundle(); { - _latestVersion = doc["release"]["version"]; - publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_latest, _latestVersion, true); + HTTPClient https; + https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + https.useHTTP10(true); - if (_latestVersion != _preferences->getString(preference_latest_version).c_str()) - { - _preferences->putString(preference_latest_version, _latestVersion); - } + if (https.begin(*client, GITHUB_OTA_MANIFEST_URL)) { + int httpResponseCode = https.GET(); + + if (httpResponseCode == HTTP_CODE_OK || httpResponseCode == HTTP_CODE_MOVED_PERMANENTLY) + { + JsonDocument doc; + DeserializationError jsonError = deserializeJson(doc, https.getStream()); + + if (!jsonError) + { + _latestVersion = doc["release"]["version"]; + publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_latest, _latestVersion, true); + + if (_latestVersion != _preferences->getString(preference_latest_version).c_str()) + { + _preferences->putString(preference_latest_version, _latestVersion); + } + } + } + } + https.end(); } + delete client; } - - https.end(); } } diff --git a/src/NukiNetwork.h b/src/NukiNetwork.h index 54daece..753248a 100644 --- a/src/NukiNetwork.h +++ b/src/NukiNetwork.h @@ -5,7 +5,6 @@ #include #include "networkDevices/NetworkDevice.h" #include "networkDevices/IPConfiguration.h" -#include #ifndef NUKI_HUB_UPDATER #include "MqttReceiver.h" @@ -112,7 +111,6 @@ private: static NukiNetwork* _inst; const char* _latestVersion; - HTTPClient https; Preferences* _preferences; IPConfiguration* _ipConfiguration = nullptr; diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp index 069bdcb..bf57be3 100644 --- a/src/NukiNetworkLock.cpp +++ b/src/NukiNetworkLock.cpp @@ -71,10 +71,8 @@ void NukiNetworkLock::initialize() if(_preferences->getBool(preference_update_from_mqtt, false)) { - #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) _network->subscribe(_mqttPath, mqtt_topic_update); _network->initTopic(_mqttPath, mqtt_topic_update, "0"); - #endif } _network->subscribe(_mqttPath, mqtt_topic_webserver_action); @@ -195,7 +193,6 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const delay(200); restartEsp(RestartReason::RequestedViaMqtt); } - #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(value, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false)) { Log->println(F("Update requested via MQTT.")); @@ -204,7 +201,6 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const delay(200); restartEsp(RestartReason::OTAReboot); } - #endif else if(comparePrefixedPath(topic, mqtt_topic_webserver_action)) { if(strcmp(value, "") == 0 || diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 157186c..ad7bda1 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -10,6 +10,7 @@ #ifndef NUKI_HUB_UPDATER #include +#include #include "ArduinoJson.h" WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType) @@ -318,7 +319,6 @@ void WebCfgServer::initialize() esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL)); restartEsp(RestartReason::OTAReboot); }); - #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) _server.on("/autoupdate", [&]() { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) { return _server.requestAuthentication(); @@ -347,7 +347,6 @@ void WebCfgServer::initialize() waitAndProcess(true, 1000); restartEsp(RestartReason::OTAReboot); }); - #endif _server.on("/uploadota", HTTP_POST, [&]() { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) { return _server.requestAuthentication(); @@ -415,7 +414,6 @@ void WebCfgServer::buildOtaHtml(String &response, bool errored) response.concat("
Initiating Over-the-air update. This will take about two minutes, please be patient.
You will be forwarded automatically when the update is complete.
"); - #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) response.concat("

Update Nuki Hub

"); response.concat("Click on the button to reboot and automatically update Nuki Hub and the Nuki Hub updater to the latest versions from GitHub"); response.concat("
"); @@ -433,53 +431,58 @@ void WebCfgServer::buildOtaHtml(String &response, bool errored) response.concat("
"); #ifndef NUKI_HUB_UPDATER - HTTPClient https; - https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - https.setTimeout(2500); - https.useHTTP10(true); - https.begin(GITHUB_OTA_MANIFEST_URL); - - int httpResponseCode = https.GET(); - - if (httpResponseCode == HTTP_CODE_OK || httpResponseCode == HTTP_CODE_MOVED_PERMANENTLY) - { - JsonDocument doc; - DeserializationError jsonError = deserializeJson(doc, https.getStream()); - - if (!jsonError) + NetworkClientSecure *client = new NetworkClientSecure; + if (client) { + client->setDefaultCACertBundle(); { - response.concat("Latest release version: "); - response.concat(doc["release"]["fullversion"].as()); - response.concat(" ("); - response.concat(doc["release"]["build"].as()); - response.concat("), "); - response.concat(doc["release"]["time"].as()); - response.concat("
"); - response.concat("Latest beta version: "); - response.concat(doc["beta"]["fullversion"].as()); - if(doc["beta"]["fullversion"] != "No beta available") - { - response.concat(" ("); - response.concat(doc["beta"]["build"].as()); - response.concat("), "); - response.concat(doc["beta"]["time"].as()); + HTTPClient https; + https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + https.setTimeout(2500); + https.useHTTP10(true); + + if (https.begin(*client, GITHUB_OTA_MANIFEST_URL)) { + int httpResponseCode = https.GET(); + + if (httpResponseCode == HTTP_CODE_OK || httpResponseCode == HTTP_CODE_MOVED_PERMANENTLY) + { + JsonDocument doc; + DeserializationError jsonError = deserializeJson(doc, https.getStream()); + + if (!jsonError) + { + response.concat("Latest release version: "); + response.concat(doc["release"]["fullversion"].as()); + response.concat(" ("); + response.concat(doc["release"]["build"].as()); + response.concat("), "); + response.concat(doc["release"]["time"].as()); + response.concat("
"); + response.concat("Latest beta version: "); + response.concat(doc["beta"]["fullversion"].as()); + if(doc["beta"]["fullversion"] != "No beta available") + { + response.concat(" ("); + response.concat(doc["beta"]["build"].as()); + response.concat("), "); + response.concat(doc["beta"]["time"].as()); + } + response.concat("
"); + response.concat("Latest development version: "); + response.concat(doc["master"]["fullversion"].as()); + response.concat(" ("); + response.concat(doc["master"]["build"].as()); + response.concat("), "); + response.concat(doc["master"]["time"].as()); + response.concat("
"); + } + } + https.end(); } - response.concat("
"); - response.concat("Latest development version: "); - response.concat(doc["master"]["fullversion"].as()); - response.concat(" ("); - response.concat(doc["master"]["build"].as()); - response.concat("), "); - response.concat(doc["master"]["time"].as()); - response.concat("
"); } + delete client; } - - https.end(); #endif - response.concat("
"); - #endif if(_partitionType == 1) { @@ -612,16 +615,12 @@ void WebCfgServer::handleOtaUpload() filename = "/" + filename; } _otaStartTs = esp_timer_get_time() / 1000; - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - esp_task_wdt_init(30, false); - #else esp_task_wdt_config_t twdt_config = { .timeout_ms = 30000, .idle_core_mask = 0, .trigger_panic = false, }; esp_task_wdt_reconfigure(&twdt_config); - #endif #ifndef NUKI_HUB_UPDATER _network->disableAutoRestarts(); @@ -2539,7 +2538,7 @@ void WebCfgServer::buildNukiConfigHtml(String &response) #endif printInputField(response, "RSBC", "Restart if bluetooth beacons not received (seconds; -1 to disable)", _preferences->getInt(preference_restart_ble_beacon_lost), 10, ""); printInputField(response, "TXPWR", "BLE transmit power in dB (minimum -12, maximum 9)", _preferences->getInt(preference_ble_tx_power, 9), 10, ""); - + response.concat(""); response.concat("
"); response.concat(""); diff --git a/src/main.cpp b/src/main.cpp index 02756d1..0468d43 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -244,16 +244,13 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) case HTTP_EVENT_DISCONNECTED: Log->println("HTTP_EVENT_DISCONNECTED"); break; - #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) case HTTP_EVENT_REDIRECT: Log->println("HTTP_EVENT_REDIRECT"); break; - #endif } return ESP_OK; } -#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) void otaTask(void *pvParameter) { uint8_t partitionType = checkPartition(); @@ -297,36 +294,21 @@ void otaTask(void *pvParameter) esp_task_wdt_reset(); } -#endif void setupTasks(bool ota) { // configMAX_PRIORITIES is 25 - - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - esp_task_wdt_init(300, true); - #else esp_task_wdt_config_t twdt_config = { .timeout_ms = 300000, .idle_core_mask = 0, .trigger_panic = true, }; esp_task_wdt_reconfigure(&twdt_config); - #endif if(ota) { - #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1); - esp_task_wdt_add(networkTaskHandle); - #ifndef NUKI_HUB_UPDATER - xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 1); - esp_task_wdt_add(nukiTaskHandle); - #endif - #else xTaskCreatePinnedToCore(otaTask, "ota", 8192, NULL, 2, &otaTaskHandle, 1); esp_task_wdt_add(otaTaskHandle); - #endif } else { diff --git a/src/networkDevices/EthLan8720Device.cpp b/src/networkDevices/EthLan8720Device.cpp index c399355..98b8497 100644 --- a/src/networkDevices/EthLan8720Device.cpp +++ b/src/networkDevices/EthLan8720Device.cpp @@ -76,13 +76,11 @@ void EthLan8720Device::initialize() WiFi.setHostname(_hostname.c_str()); -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) - _hardwareInitialized = ETH.begin(_phy_addr, _power, _mdc, _mdio, _type, _clock_mode, _use_mac_from_efuse); -#elif CONFIG_IDF_TARGET_ESP32 + #if CONFIG_IDF_TARGET_ESP32 _hardwareInitialized = ETH.begin(_type, _phy_addr, _mdc, _mdio, _power, _clock_mode); -#else + #else _hardwareInitialized = false; -#endif + #endif ETH.setHostname(_hostname.c_str()); if(!_ipConfiguration->dhcpEnabled()) diff --git a/src/networkDevices/EthLan8720Device.h b/src/networkDevices/EthLan8720Device.h index 22062c8..12a4197 100644 --- a/src/networkDevices/EthLan8720Device.h +++ b/src/networkDevices/EthLan8720Device.h @@ -1,33 +1,26 @@ #pragma once -#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0)) - #ifndef CONFIG_IDF_TARGET_ESP32 - typedef enum { - ETH_CLOCK_GPIO0_IN = 0, - ETH_CLOCK_GPIO16_OUT = 2, - ETH_CLOCK_GPIO17_OUT = 3 - } eth_clock_mode_t; +#ifndef CONFIG_IDF_TARGET_ESP32 + typedef enum { + ETH_CLOCK_GPIO0_IN = 0, + ETH_CLOCK_GPIO16_OUT = 2, + ETH_CLOCK_GPIO17_OUT = 3 + } eth_clock_mode_t; - #define ETH_PHY_TYPE ETH_PHY_MAX - #else - #define ETH_PHY_TYPE ETH_PHY_LAN8720 - #endif + #define ETH_PHY_TYPE ETH_PHY_MAX +#else + #define ETH_PHY_TYPE ETH_PHY_LAN8720 +#endif #define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN - #define ETH_PHY_ADDR 0 #define ETH_PHY_MDC 23 #define ETH_PHY_MDIO 18 #define ETH_PHY_POWER -1 #define ETH_RESET_PIN 1 -#endif #include -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) -#include -#else #include -#endif #include #include "NetworkDevice.h" #ifndef NUKI_HUB_UPDATER diff --git a/src/networkDevices/WifiDevice.h b/src/networkDevices/WifiDevice.h index 1d4ce8e..1455eea 100644 --- a/src/networkDevices/WifiDevice.h +++ b/src/networkDevices/WifiDevice.h @@ -1,11 +1,7 @@ #pragma once #include -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)) -#include -#else #include -#endif #include #include "NetworkDevice.h" #include "WiFiManager.h" diff --git a/updater/pio_package.py b/updater/pio_package.py index 01143bf..f7fe86e 100644 --- a/updater/pio_package.py +++ b/updater/pio_package.py @@ -8,8 +8,6 @@ from pathlib import Path def get_board_name(env): board = env.get('BOARD_MCU') - if env.get('BOARD') == 'esp32-solo1': - board = env.get('BOARD').replace('-', '') return board def create_target_dir(env): diff --git a/updater/pio_package_pre_solo1.py b/updater/pio_package_pre_solo1.py deleted file mode 100644 index b04f92e..0000000 --- a/updater/pio_package_pre_solo1.py +++ /dev/null @@ -1,42 +0,0 @@ -import re, shutil, os -from datetime import datetime, timezone - -if not os.path.exists('src/networkDevices/'): - os.mkdir('src/networkDevices') - -shutil.copy("../src/main.cpp", "src/main.cpp") -shutil.copy("../src/Config.h", "src/Config.h") -shutil.copy("../src/Logger.h", "src/Logger.h") -shutil.copy("../src/NukiNetwork.h", "src/NukiNetwork.h") -shutil.copy("../src/Ota.h", "src/Ota.h") -shutil.copy("../src/PreferencesKeys.h", "src/PreferencesKeys.h") -shutil.copy("../src/RestartReason.h", "src/RestartReason.h") -shutil.copy("../src/WebCfgServer.h", "src/WebCfgServer.h") -shutil.copy("../src/WebCfgServerConstants.h", "src/WebCfgServerConstants.h") - -shutil.copy("../src/Logger.cpp", "src/Logger.cpp") -shutil.copy("../src/NukiNetwork.cpp", "src/NukiNetwork.cpp") -shutil.copy("../src/Ota.cpp", "src/Ota.cpp") -shutil.copy("../src/WebCfgServer.cpp", "src/WebCfgServer.cpp") - -shutil.copy("../src/networkDevices/EthLan8720Device.h", "src/networkDevices/EthLan8720Device.h") -shutil.copy("../src/networkDevices/IPConfiguration.h", "src/networkDevices/IPConfiguration.h") -shutil.copy("../src/networkDevices/NetworkDevice.h", "src/networkDevices/NetworkDevice.h") -shutil.copy("../src/networkDevices/W5500Device.h", "src/networkDevices/W5500Device.h") -shutil.copy("../src/networkDevices/WifiDevice.h", "src/networkDevices/WifiDevice.h") - -shutil.copy("../src/networkDevices/EthLan8720Device.cpp", "src/networkDevices/EthLan8720Device.cpp") -shutil.copy("../src/networkDevices/IPConfiguration.cpp", "src/networkDevices/IPConfiguration.cpp") -shutil.copy("../src/networkDevices/NetworkDevice.cpp", "src/networkDevices/NetworkDevice.cpp") -shutil.copy("../src/networkDevices/W5500Device.cpp", "src/networkDevices/W5500Device.cpp") -shutil.copy("../src/networkDevices/WifiDevice.cpp", "src/networkDevices/WifiDevice.cpp") - -regex = r"\#define NUKI_HUB_DATE \"(.*)\"" -content_new = "" - -with open ('src/Config.h', 'r' ) as readfile: - file_content = readfile.read() - content_new = re.sub(regex, "#define NUKI_HUB_DATE \"" + datetime.now(timezone.utc).strftime("%Y-%m-%d") + "\"", file_content, flags = re.M) - -with open('src/Config.h', 'w') as writefile: - writefile.write(content_new) diff --git a/updater/platformio.ini b/updater/platformio.ini index afdaa1c..68d985f 100644 --- a/updater/platformio.ini +++ b/updater/platformio.ini @@ -63,23 +63,4 @@ board = nuki-esp32-s3 [env:updater_esp32-c6] extends = env:updater_esp32dev -board = esp32-c6-devkitm-1 - -[env:updater_esp32solo1] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32-2023.10.03.zip -framework = arduino -board = esp32-solo1 -extra_scripts = - pre:pio_package_pre_solo1.py - post:pio_package.py -build_flags = - ${env.build_flags} - -DFRAMEWORK_ARDUINO_SOLO1 -lib_deps = - AsyncTCP=symlink://../lib/AsyncTCP - Ethernet=symlink://../lib/Ethernet - HTTPClient=symlink://../lib/HTTPClient - WebServer=symlink://../lib/WebServer - WiFiManager=symlink://../lib/WiFiManager -lib_ignore = - NetworkClientSecure \ No newline at end of file +board = esp32-c6-devkitm-1 \ No newline at end of file