Feature/http client (#1973)
* Pass client parameter into two new begin() functions. Set other begin() functions deprecated. Updated library version to 1.2 * Added working HTTPS example on a public url with a certificate * Remove two unnecessary tests in ::disconnect() * Add a scoping block to BasicHttpsClient.ino to assure HTTPClient is destroyed before WiFiClientSecure * Added check to handle mixup of old and present api properly * Correct HTTPClient::setTimeout() to convert milliseconds to seconds. Correct WiFiClient::setTimeout() to call Stream::setTimeout() with seconds converted back to milliseconds. Remove inproper checks for _insecure. * Added small comment because it looked like the Travis build did not finish
This commit is contained in:
parent
b70737d276
commit
01d22c8807
@ -0,0 +1,147 @@
|
|||||||
|
/**
|
||||||
|
BasicHTTPSClient.ino
|
||||||
|
|
||||||
|
Created on: 14.10.2018
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiMulti.h>
|
||||||
|
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
|
// This is GandiStandardSSLCA2.pem, the root Certificate Authority that signed
|
||||||
|
// the server certifcate for the demo server https://jigsaw.w3.org in this
|
||||||
|
// example. This certificate is valid until Sep 11 23:59:59 2024 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" \
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
|
// Not sure if WiFiClientSecure checks the validity date of the certificate.
|
||||||
|
// Setting clock just to be sure...
|
||||||
|
void setClock() {
|
||||||
|
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print(F("Waiting for NTP time sync: "));
|
||||||
|
time_t nowSecs = time(nullptr);
|
||||||
|
while (nowSecs < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(F("."));
|
||||||
|
yield();
|
||||||
|
nowSecs = time(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&nowSecs, &timeinfo);
|
||||||
|
Serial.print(F("Current time: "));
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WiFiMulti WiFiMulti;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
// Serial.setDebugOutput(true);
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFiMulti.addAP("SSID", "PASSWORD");
|
||||||
|
|
||||||
|
// wait for WiFi connection
|
||||||
|
Serial.print("Waiting for WiFi to connect...");
|
||||||
|
while ((WiFiMulti.run() != WL_CONNECTED)) {
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println(" connected");
|
||||||
|
|
||||||
|
setClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
WiFiClientSecure *client = new WiFiClientSecure;
|
||||||
|
if(client) {
|
||||||
|
client -> setCACert(rootCACertificate);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Add a scoping block for HTTPClient https to make sure it is destroyed before WiFiClientSecure *client is
|
||||||
|
HTTPClient https;
|
||||||
|
|
||||||
|
Serial.print("[HTTPS] begin...\n");
|
||||||
|
if (https.begin(*client, "https://jigsaw.w3.org/HTTP/connection.html")) { // HTTPS
|
||||||
|
Serial.print("[HTTPS] GET...\n");
|
||||||
|
// start connection and send HTTP header
|
||||||
|
int httpCode = https.GET();
|
||||||
|
|
||||||
|
// httpCode will be negative on error
|
||||||
|
if (httpCode > 0) {
|
||||||
|
// HTTP header has been send and Server response header has been handled
|
||||||
|
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
|
||||||
|
|
||||||
|
// file found at server
|
||||||
|
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
|
||||||
|
String payload = https.getString();
|
||||||
|
Serial.println(payload);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
https.end();
|
||||||
|
} else {
|
||||||
|
Serial.printf("[HTTPS] Unable to connect\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// End extra scoping block
|
||||||
|
}
|
||||||
|
|
||||||
|
delete client;
|
||||||
|
} else {
|
||||||
|
Serial.println("Unable to create client");
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Waiting 10s before the next round...");
|
||||||
|
delay(10000);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
name=HTTPClient
|
name=HTTPClient
|
||||||
version=1.1
|
version=1.2
|
||||||
author=Markus Sattler
|
author=Markus Sattler
|
||||||
maintainer=Markus Sattler
|
maintainer=Markus Sattler
|
||||||
sentence=http Client for ESP32
|
sentence=http Client for ESP32
|
||||||
|
@ -22,17 +22,23 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
|
* Adapted in October 2018
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <esp32-hal-log.h>
|
#include <esp32-hal-log.h>
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFiClientSecure.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <StreamString.h>
|
#include <StreamString.h>
|
||||||
#include <base64.h>
|
#include <base64.h>
|
||||||
|
|
||||||
#include "HTTPClient.h"
|
#include "HTTPClient.h"
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
class TransportTraits
|
class TransportTraits
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -78,6 +84,7 @@ protected:
|
|||||||
const char* _clicert;
|
const char* _clicert;
|
||||||
const char* _clikey;
|
const char* _clikey;
|
||||||
};
|
};
|
||||||
|
#endif // HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
@ -91,8 +98,8 @@ HTTPClient::HTTPClient()
|
|||||||
*/
|
*/
|
||||||
HTTPClient::~HTTPClient()
|
HTTPClient::~HTTPClient()
|
||||||
{
|
{
|
||||||
if(_tcp) {
|
if(_client) {
|
||||||
_tcp->stop();
|
_client->stop();
|
||||||
}
|
}
|
||||||
if(_currentHeaders) {
|
if(_currentHeaders) {
|
||||||
delete[] _currentHeaders;
|
delete[] _currentHeaders;
|
||||||
@ -107,9 +114,81 @@ void HTTPClient::clear()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parsing the url for all needed parameters
|
||||||
|
* @param client Client&
|
||||||
|
* @param url String
|
||||||
|
* @param https bool
|
||||||
|
* @return success bool
|
||||||
|
*/
|
||||||
|
bool HTTPClient::begin(WiFiClient &client, String url) {
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
if(_tcpDeprecated) {
|
||||||
|
log_d("mix up of new and deprecated api");
|
||||||
|
_canReuse = false;
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_client = &client;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_port = (protocol == "https" ? 443 : 80);
|
||||||
|
return beginInternal(url, protocol.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* directly supply all needed parameters
|
||||||
|
* @param client Client&
|
||||||
|
* @param host String
|
||||||
|
* @param port uint16_t
|
||||||
|
* @param uri String
|
||||||
|
* @param https bool
|
||||||
|
* @return success bool
|
||||||
|
*/
|
||||||
|
bool HTTPClient::begin(WiFiClient &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();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_client = &client;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
_host = host;
|
||||||
|
_port = port;
|
||||||
|
_uri = uri;
|
||||||
|
_protocol = (https ? "https" : "http");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
bool HTTPClient::begin(String url, const char* CAcert)
|
bool HTTPClient::begin(String url, const char* CAcert)
|
||||||
{
|
{
|
||||||
_transportTraits.reset(nullptr);
|
if(_client && !_tcpDeprecated) {
|
||||||
|
log_d("mix up of new and deprecated api");
|
||||||
|
_canReuse = false;
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
_port = 443;
|
_port = 443;
|
||||||
if (!beginInternal(url, "https")) {
|
if (!beginInternal(url, "https")) {
|
||||||
return false;
|
return false;
|
||||||
@ -125,8 +204,12 @@ bool HTTPClient::begin(String url, const char* CAcert)
|
|||||||
*/
|
*/
|
||||||
bool HTTPClient::begin(String url)
|
bool HTTPClient::begin(String url)
|
||||||
{
|
{
|
||||||
|
if(_client && !_tcpDeprecated) {
|
||||||
|
log_d("mix up of new and deprecated api");
|
||||||
|
_canReuse = false;
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
_transportTraits.reset(nullptr);
|
|
||||||
_port = 80;
|
_port = 80;
|
||||||
if (!beginInternal(url, "http")) {
|
if (!beginInternal(url, "http")) {
|
||||||
return begin(url, (const char*)NULL);
|
return begin(url, (const char*)NULL);
|
||||||
@ -134,6 +217,7 @@ bool HTTPClient::begin(String url)
|
|||||||
_transportTraits = TransportTraitsPtr(new TransportTraits());
|
_transportTraits = TransportTraitsPtr(new TransportTraits());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif // HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
|
||||||
bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
|
bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
|
||||||
{
|
{
|
||||||
@ -182,8 +266,15 @@ bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
bool HTTPClient::begin(String host, uint16_t port, String uri)
|
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();
|
clear();
|
||||||
_host = host;
|
_host = host;
|
||||||
_port = port;
|
_port = port;
|
||||||
@ -195,6 +286,12 @@ bool HTTPClient::begin(String host, uint16_t port, String uri)
|
|||||||
|
|
||||||
bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcert)
|
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();
|
clear();
|
||||||
_host = host;
|
_host = host;
|
||||||
_port = port;
|
_port = port;
|
||||||
@ -210,6 +307,12 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcer
|
|||||||
|
|
||||||
bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key)
|
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();
|
clear();
|
||||||
_host = host;
|
_host = host;
|
||||||
_port = port;
|
_port = port;
|
||||||
@ -222,37 +325,60 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcer
|
|||||||
_transportTraits = TransportTraitsPtr(new TLSTraits(CAcert, cli_cert, cli_key));
|
_transportTraits = TransportTraitsPtr(new TLSTraits(CAcert, cli_cert, cli_key));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif // HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* end
|
* end
|
||||||
* called after the payload is handled
|
* called after the payload is handled
|
||||||
*/
|
*/
|
||||||
void HTTPClient::end(void)
|
void HTTPClient::end(void)
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disconnect
|
||||||
|
* close the TCP socket
|
||||||
|
*/
|
||||||
|
void HTTPClient::disconnect()
|
||||||
{
|
{
|
||||||
if(connected()) {
|
if(connected()) {
|
||||||
if(_tcp->available() > 0) {
|
if(_client->available() > 0) {
|
||||||
log_d("still data in buffer (%d), clean up.", _tcp->available());
|
log_d("still data in buffer (%d), clean up.\n", _client->available());
|
||||||
_tcp->flush();
|
while(_client->available() > 0) {
|
||||||
|
_client->read();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_reuse && _canReuse) {
|
if(_reuse && _canReuse) {
|
||||||
log_d("tcp keep open for reuse");
|
log_d("tcp keep open for reuse\n");
|
||||||
} else {
|
} else {
|
||||||
log_d("tcp stop");
|
log_d("tcp stop\n");
|
||||||
_tcp->stop();
|
_client->stop();
|
||||||
|
_client = nullptr;
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
if(_tcpDeprecated) {
|
||||||
|
_transportTraits.reset(nullptr);
|
||||||
|
_tcpDeprecated.reset(nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_v("tcp is closed");
|
log_d("tcp is closed\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connected
|
* connected
|
||||||
* @return connected status
|
* @return connected status
|
||||||
*/
|
*/
|
||||||
bool HTTPClient::connected()
|
bool HTTPClient::connected()
|
||||||
{
|
{
|
||||||
if(_tcp) {
|
if(_client) {
|
||||||
return ((_tcp->available() > 0) || _tcp->connected());
|
return ((_client->available() > 0) || _client->connected());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -309,8 +435,8 @@ void HTTPClient::setAuthorization(const char * auth)
|
|||||||
void HTTPClient::setTimeout(uint16_t timeout)
|
void HTTPClient::setTimeout(uint16_t timeout)
|
||||||
{
|
{
|
||||||
_tcpTimeout = timeout;
|
_tcpTimeout = timeout;
|
||||||
if(connected() && !_secure) {
|
if(connected()) {
|
||||||
_tcp->setTimeout(timeout);
|
_client->setTimeout((timeout + 500) / 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +524,7 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size)
|
|||||||
|
|
||||||
// send Payload if needed
|
// send Payload if needed
|
||||||
if(payload && size > 0) {
|
if(payload && size > 0) {
|
||||||
if(_tcp->write(&payload[0], size) != size) {
|
if(_client->write(&payload[0], size) != size) {
|
||||||
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,7 +603,7 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
|
|||||||
int bytesRead = stream->readBytes(buff, readBytes);
|
int bytesRead = stream->readBytes(buff, readBytes);
|
||||||
|
|
||||||
// write it to Stream
|
// write it to Stream
|
||||||
int bytesWrite = _tcp->write((const uint8_t *) buff, bytesRead);
|
int bytesWrite = _client->write((const uint8_t *) buff, bytesRead);
|
||||||
bytesWritten += bytesWrite;
|
bytesWritten += bytesWrite;
|
||||||
|
|
||||||
// are all Bytes a writen to stream ?
|
// are all Bytes a writen to stream ?
|
||||||
@ -485,11 +611,11 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
|
|||||||
log_d("short write, asked for %d but got %d retry...", bytesRead, bytesWrite);
|
log_d("short write, asked for %d but got %d retry...", bytesRead, bytesWrite);
|
||||||
|
|
||||||
// check for write error
|
// check for write error
|
||||||
if(_tcp->getWriteError()) {
|
if(_client->getWriteError()) {
|
||||||
log_d("stream write error %d", _tcp->getWriteError());
|
log_d("stream write error %d", _client->getWriteError());
|
||||||
|
|
||||||
//reset write error for retry
|
//reset write error for retry
|
||||||
_tcp->clearWriteError();
|
_client->clearWriteError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// some time for the stream
|
// some time for the stream
|
||||||
@ -498,7 +624,7 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
|
|||||||
int leftBytes = (readBytes - bytesWrite);
|
int leftBytes = (readBytes - bytesWrite);
|
||||||
|
|
||||||
// retry to send the missed bytes
|
// retry to send the missed bytes
|
||||||
bytesWrite = _tcp->write((const uint8_t *) (buff + bytesWrite), leftBytes);
|
bytesWrite = _client->write((const uint8_t *) (buff + bytesWrite), leftBytes);
|
||||||
bytesWritten += bytesWrite;
|
bytesWritten += bytesWrite;
|
||||||
|
|
||||||
if(bytesWrite != leftBytes) {
|
if(bytesWrite != leftBytes) {
|
||||||
@ -510,8 +636,8 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for write error
|
// check for write error
|
||||||
if(_tcp->getWriteError()) {
|
if(_client->getWriteError()) {
|
||||||
log_d("stream write error %d", _tcp->getWriteError());
|
log_d("stream write error %d", _client->getWriteError());
|
||||||
free(buff);
|
free(buff);
|
||||||
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||||
}
|
}
|
||||||
@ -561,8 +687,8 @@ int HTTPClient::getSize(void)
|
|||||||
*/
|
*/
|
||||||
WiFiClient& HTTPClient::getStream(void)
|
WiFiClient& HTTPClient::getStream(void)
|
||||||
{
|
{
|
||||||
if (connected() && !_secure) {
|
if (connected()) {
|
||||||
return *_tcp;
|
return *_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_w("getStream: not connected");
|
log_w("getStream: not connected");
|
||||||
@ -577,7 +703,7 @@ WiFiClient& HTTPClient::getStream(void)
|
|||||||
WiFiClient* HTTPClient::getStreamPtr(void)
|
WiFiClient* HTTPClient::getStreamPtr(void)
|
||||||
{
|
{
|
||||||
if(connected()) {
|
if(connected()) {
|
||||||
return _tcp.get();
|
return _client;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_w("getStreamPtr: not connected");
|
log_w("getStreamPtr: not connected");
|
||||||
@ -617,7 +743,7 @@ int HTTPClient::writeToStream(Stream * stream)
|
|||||||
if(!connected()) {
|
if(!connected()) {
|
||||||
return returnError(HTTPC_ERROR_CONNECTION_LOST);
|
return returnError(HTTPC_ERROR_CONNECTION_LOST);
|
||||||
}
|
}
|
||||||
String chunkHeader = _tcp->readStringUntil('\n');
|
String chunkHeader = _client->readStringUntil('\n');
|
||||||
|
|
||||||
if(chunkHeader.length() <= 0) {
|
if(chunkHeader.length() <= 0) {
|
||||||
return returnError(HTTPC_ERROR_READ_TIMEOUT);
|
return returnError(HTTPC_ERROR_READ_TIMEOUT);
|
||||||
@ -654,7 +780,7 @@ int HTTPClient::writeToStream(Stream * stream)
|
|||||||
|
|
||||||
// read trailing \r\n at the end of the chunk
|
// read trailing \r\n at the end of the chunk
|
||||||
char buf[2];
|
char buf[2];
|
||||||
auto trailing_seq_len = _tcp->readBytes((uint8_t*)buf, 2);
|
auto trailing_seq_len = _client->readBytes((uint8_t*)buf, 2);
|
||||||
if (trailing_seq_len != 2 || buf[0] != '\r' || buf[1] != '\n') {
|
if (trailing_seq_len != 2 || buf[0] != '\r' || buf[1] != '\n') {
|
||||||
return returnError(HTTPC_ERROR_READ_TIMEOUT);
|
return returnError(HTTPC_ERROR_READ_TIMEOUT);
|
||||||
}
|
}
|
||||||
@ -822,38 +948,46 @@ bool HTTPClient::connect(void)
|
|||||||
|
|
||||||
if(connected()) {
|
if(connected()) {
|
||||||
log_d("already connected, try reuse!");
|
log_d("already connected, try reuse!");
|
||||||
while(_tcp->available() > 0) {
|
while(_client->available() > 0) {
|
||||||
_tcp->read();
|
_client->read();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_transportTraits) {
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
if(!_client) {
|
||||||
|
_tcpDeprecated = _transportTraits->create();
|
||||||
|
_client = _tcpDeprecated.get();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!_client) {
|
||||||
log_d("HTTPClient::begin was not called or returned error");
|
log_d("HTTPClient::begin was not called or returned error");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_tcp = _transportTraits->create();
|
// set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil()
|
||||||
|
_client->setTimeout((_tcpTimeout + 500) / 1000);
|
||||||
|
|
||||||
if (!_transportTraits->verify(*_tcp, _host.c_str())) {
|
if(!_client->connect(_host.c_str(), _port)) {
|
||||||
log_d("transport level verify failed");
|
|
||||||
_tcp->stop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!_tcp->connect(_host.c_str(), _port)) {
|
|
||||||
log_d("failed connect to %s:%u", _host.c_str(), _port);
|
log_d("failed connect to %s:%u", _host.c_str(), _port);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_d(" connected to %s:%u", _host.c_str(), _port);
|
log_d(" connected to %s:%u", _host.c_str(), _port);
|
||||||
|
|
||||||
// set Timeout for readBytesUntil and readStringUntil
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
setTimeout(_tcpTimeout);
|
if (_tcpDeprecated && !_transportTraits->verify(*_client, _host.c_str())) {
|
||||||
|
log_d("transport level verify failed");
|
||||||
|
_client->stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
_tcp->setNoDelay(true);
|
_client->setNoDelay(true);
|
||||||
#endif
|
#endif
|
||||||
*/
|
*/
|
||||||
return connected();
|
return connected();
|
||||||
@ -907,7 +1041,7 @@ bool HTTPClient::sendHeader(const char * type)
|
|||||||
|
|
||||||
header += _headers + "\r\n";
|
header += _headers + "\r\n";
|
||||||
|
|
||||||
return (_tcp->write((const uint8_t *) header.c_str(), header.length()) == header.length());
|
return (_client->write((const uint8_t *) header.c_str(), header.length()) == header.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -928,9 +1062,9 @@ int HTTPClient::handleHeaderResponse()
|
|||||||
unsigned long lastDataTime = millis();
|
unsigned long lastDataTime = millis();
|
||||||
|
|
||||||
while(connected()) {
|
while(connected()) {
|
||||||
size_t len = _tcp->available();
|
size_t len = _client->available();
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
String headerLine = _tcp->readStringUntil('\n');
|
String headerLine = _client->readStringUntil('\n');
|
||||||
headerLine.trim(); // remove \r
|
headerLine.trim(); // remove \r
|
||||||
|
|
||||||
lastDataTime = millis();
|
lastDataTime = millis();
|
||||||
@ -1026,7 +1160,7 @@ int HTTPClient::writeToStreamDataBlock(Stream * stream, int size)
|
|||||||
while(connected() && (len > 0 || len == -1)) {
|
while(connected() && (len > 0 || len == -1)) {
|
||||||
|
|
||||||
// get available data size
|
// get available data size
|
||||||
size_t sizeAvailable = _tcp->available();
|
size_t sizeAvailable = _client->available();
|
||||||
|
|
||||||
if(sizeAvailable) {
|
if(sizeAvailable) {
|
||||||
|
|
||||||
@ -1043,7 +1177,7 @@ int HTTPClient::writeToStreamDataBlock(Stream * stream, int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read data
|
// read data
|
||||||
int bytesRead = _tcp->readBytes(buff, readBytes);
|
int bytesRead = _client->readBytes(buff, readBytes);
|
||||||
|
|
||||||
// write it to Stream
|
// write it to Stream
|
||||||
int bytesWrite = stream->write(buff, bytesRead);
|
int bytesWrite = stream->write(buff, bytesRead);
|
||||||
@ -1124,7 +1258,7 @@ int HTTPClient::returnError(int error)
|
|||||||
log_w("error(%d): %s", error, errorToString(error).c_str());
|
log_w("error(%d): %s", error, errorToString(error).c_str());
|
||||||
if(connected()) {
|
if(connected()) {
|
||||||
log_d("tcp stop");
|
log_d("tcp stop");
|
||||||
_tcp->stop();
|
_client->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#ifndef HTTPClient_H_
|
#ifndef HTTPClient_H_
|
||||||
#define HTTPClient_H_
|
#define HTTPClient_H_
|
||||||
|
|
||||||
|
#define HTTPCLIENT_1_1_COMPATIBLE
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <WiFiClient.h>
|
#include <WiFiClient.h>
|
||||||
@ -117,8 +119,10 @@ typedef enum {
|
|||||||
HTTPC_TE_CHUNKED
|
HTTPC_TE_CHUNKED
|
||||||
} transferEncoding_t;
|
} transferEncoding_t;
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
class TransportTraits;
|
class TransportTraits;
|
||||||
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
|
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
|
||||||
|
#endif
|
||||||
|
|
||||||
class HTTPClient
|
class HTTPClient
|
||||||
{
|
{
|
||||||
@ -126,11 +130,20 @@ public:
|
|||||||
HTTPClient();
|
HTTPClient();
|
||||||
~HTTPClient();
|
~HTTPClient();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
bool begin(String url);
|
bool begin(String url);
|
||||||
bool begin(String url, const char* CAcert);
|
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 = "/");
|
||||||
bool begin(String host, uint16_t port, String uri, 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);
|
bool begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key);
|
||||||
|
#endif
|
||||||
|
|
||||||
void end(void);
|
void end(void);
|
||||||
|
|
||||||
@ -181,6 +194,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool beginInternal(String url, const char* expectedProtocol);
|
bool beginInternal(String url, const char* expectedProtocol);
|
||||||
|
void disconnect();
|
||||||
void clear();
|
void clear();
|
||||||
int returnError(int error);
|
int returnError(int error);
|
||||||
bool connect(void);
|
bool connect(void);
|
||||||
@ -189,8 +203,12 @@ protected:
|
|||||||
int writeToStreamDataBlock(Stream * stream, int len);
|
int writeToStreamDataBlock(Stream * stream, int len);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||||
TransportTraitsPtr _transportTraits;
|
TransportTraitsPtr _transportTraits;
|
||||||
std::unique_ptr<WiFiClient> _tcp;
|
std::unique_ptr<WiFiClient> _tcpDeprecated;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WiFiClient* _client;
|
||||||
|
|
||||||
/// request handling
|
/// request handling
|
||||||
String _host;
|
String _host;
|
||||||
|
@ -240,6 +240,7 @@ int WiFiClient::setSocketOption(int option, char* value, size_t len)
|
|||||||
|
|
||||||
int WiFiClient::setTimeout(uint32_t seconds)
|
int WiFiClient::setTimeout(uint32_t seconds)
|
||||||
{
|
{
|
||||||
|
Client::setTimeout(seconds * 1000);
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = seconds;
|
tv.tv_sec = seconds;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user