1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Add WiFiClient parameter to HTTPClient (#4980)

Make HTTPClient take a WiFiClient parameter, allowing you to pass in a
simple HTTP WiFiClient or a BearSSL or axTLS WiFiClientSecure with
any desired verification options.  Deprecate the older, TLSTraits methods.
Add basic HttpsClient example.

Add optional LED feedback to the Update class
This commit is contained in:
Jeroen88 2018-10-06 16:50:03 +02:00 committed by Earle F. Philhower, III
parent 9bc8ea1b58
commit 13f374666d
18 changed files with 765 additions and 168 deletions

View File

@ -35,9 +35,13 @@ void UpdaterClass::_reset() {
_currentAddress = 0; _currentAddress = 0;
_size = 0; _size = 0;
_command = U_FLASH; _command = U_FLASH;
if(_ledPin != -1) {
digitalWrite(_ledPin, _ledStateRestore);
}
} }
bool UpdaterClass::begin(size_t size, int command) { bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
if(_size > 0){ if(_size > 0){
#ifdef DEBUG_UPDATER #ifdef DEBUG_UPDATER
DEBUG_UPDATER.println(F("[begin] already running")); DEBUG_UPDATER.println(F("[begin] already running"));
@ -45,6 +49,12 @@ bool UpdaterClass::begin(size_t size, int command) {
return false; return false;
} }
_ledPin = ledPin;
_ledOn = ledOn;
if(_ledPin != -1) {
_ledStateRestore = digitalRead(_ledPin);
}
/* Check boot mode; if boot mode is 1 (UART download mode), /* Check boot mode; if boot mode is 1 (UART download mode),
we will not be able to reset into normal mode once update is done. we will not be able to reset into normal mode once update is done.
Fail early to avoid frustration. Fail early to avoid frustration.
@ -360,11 +370,22 @@ size_t UpdaterClass::writeStream(Stream &data) {
return 0; return 0;
} }
if(_ledPin != -1) {
pinMode(_ledPin, OUTPUT);
}
while(remaining()) { while(remaining()) {
toRead = data.readBytes(_buffer + _bufferLen, (_bufferSize - _bufferLen)); if(_ledPin != -1) {
digitalWrite(LED_BUILTIN, _ledOn); // Switch LED on
}
size_t bytesToRead = _bufferSize - _bufferLen;
if(bytesToRead > remaining()) {
bytesToRead = remaining();
}
toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
if(toRead == 0) { //Timeout if(toRead == 0) { //Timeout
delay(100); delay(100);
toRead = data.readBytes(_buffer + _bufferLen, (_bufferSize - _bufferLen)); toRead = data.readBytes(_buffer + _bufferLen, bytesToRead);
if(toRead == 0) { //Timeout if(toRead == 0) { //Timeout
_currentAddress = (_startAddress + _size); _currentAddress = (_startAddress + _size);
_setError(UPDATE_ERROR_STREAM); _setError(UPDATE_ERROR_STREAM);
@ -372,6 +393,9 @@ size_t UpdaterClass::writeStream(Stream &data) {
return written; return written;
} }
} }
if(_ledPin != -1) {
digitalWrite(LED_BUILTIN, _ledOn == HIGH ? LOW : HIGH); // Switch LED off
}
_bufferLen += toRead; _bufferLen += toRead;
if((_bufferLen == remaining() || _bufferLen == _bufferSize) && !_writeBuffer()) if((_bufferLen == remaining() || _bufferLen == _bufferSize) && !_writeBuffer())
return written; return written;

View File

@ -35,7 +35,7 @@ class UpdaterClass {
Call this to check the space needed for the update Call this to check the space needed for the update
Will return false if there is not enough space Will return false if there is not enough space
*/ */
bool begin(size_t size, int command = U_FLASH); bool begin(size_t size, int command = U_FLASH, int ledPin = -1, uint8_t ledOn = LOW);
/* /*
Run Updater from asynchronous callbacs Run Updater from asynchronous callbacs
@ -162,6 +162,10 @@ class UpdaterClass {
String _target_md5; String _target_md5;
MD5Builder _md5; MD5Builder _md5;
int _ledPin;
uint8_t _ledOn;
int _ledStateRestore;
}; };
extern UpdaterClass Update; extern UpdaterClass Update;

View File

@ -12,22 +12,22 @@
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
#define USE_SERIAL Serial #include <WiFiClient.h>
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
void setup() { void setup() {
USE_SERIAL.begin(115200); Serial.begin(115200);
// USE_SERIAL.setDebugOutput(true); // Serial.setDebugOutput(true);
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
for (uint8_t t = 4; t > 0; t--) { for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); Serial.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush(); Serial.flush();
delay(1000); delay(1000);
} }
@ -40,41 +40,43 @@ void loop() {
// wait for WiFi connection // wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http; HTTPClient http;
USE_SERIAL.print("[HTTP] begin...\n"); Serial.print("[HTTP] begin...\n");
// configure traged server and url // configure traged server and url
http.begin("http://user:password@192.168.1.12/test.html"); http.begin(client, "http://guest:guest@jigsaw.w3.org/HTTP/Basic/");
/* /*
// or // or
http.begin("http://192.168.1.12/test.html"); http.begin(client, "http://jigsaw.w3.org/HTTP/Basic/");
http.setAuthorization("user", "password"); http.setAuthorization("guest", "guest");
// or // or
http.begin("http://192.168.1.12/test.html"); http.begin(client, "http://jigsaw.w3.org/HTTP/Basic/");
http.setAuthorization("dXNlcjpwYXN3b3Jk"); http.setAuthorization("Z3Vlc3Q6Z3Vlc3Q=");
*/ */
USE_SERIAL.print("[HTTP] GET...\n"); Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header // start connection and send HTTP header
int httpCode = http.GET(); int httpCode = http.GET();
// httpCode will be negative on error // httpCode will be negative on error
if (httpCode > 0) { if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled // HTTP header has been send and Server response header has been handled
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server // file found at server
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
String payload = http.getString(); String payload = http.getString();
USE_SERIAL.println(payload); Serial.println(payload);
} }
} else { } else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
} }
http.end(); http.end();
@ -82,4 +84,3 @@ void loop() {
delay(10000); delay(10000);
} }

View File

@ -12,22 +12,22 @@
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
#define USE_SERIAL Serial #include <WiFiClient.h>
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
void setup() { void setup() {
USE_SERIAL.begin(115200); Serial.begin(115200);
// USE_SERIAL.setDebugOutput(true); // Serial.setDebugOutput(true);
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
for (uint8_t t = 4; t > 0; t--) { for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); Serial.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush(); Serial.flush();
delay(1000); delay(1000);
} }
@ -40,34 +40,37 @@ void loop() {
// wait for WiFi connection // wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http; HTTPClient http;
USE_SERIAL.print("[HTTP] begin...\n"); Serial.print("[HTTP] begin...\n");
// configure traged server and url if (http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html")) { // HTTP
//http.begin("https://192.168.1.12/test.html", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
http.begin("http://192.168.1.12/test.html"); //HTTP
USE_SERIAL.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error Serial.print("[HTTP] GET...\n");
if (httpCode > 0) { // start connection and send HTTP header
// HTTP header has been send and Server response header has been handled int httpCode = http.GET();
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server // httpCode will be negative on error
if (httpCode == HTTP_CODE_OK) { if (httpCode > 0) {
String payload = http.getString(); // HTTP header has been send and Server response header has been handled
USE_SERIAL.println(payload); Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
} }
} else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
} }
delay(10000); delay(10000);
} }

View File

@ -0,0 +1,78 @@
/**
BasicHTTPSClient.ino
Created on: 20.08.2018
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
// Fingerprint for demo URL, expires on June 2, 2019, needs to be updated well before this date
const uint8_t fingerprint[20] = {0x5A, 0xCF, 0xFE, 0xF0, 0xF1, 0xA6, 0xF4, 0x5F, 0xD2, 0x11, 0x11, 0xC6, 0x1D, 0x2F, 0x0E, 0xBC, 0x39, 0x8D, 0x50, 0xE0};
ESP8266WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD");
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
BearSSL::WiFiClientSecure client;
client.setFingerprint(fingerprint);
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");
}
}
delay(10000);
}

View File

@ -11,8 +11,8 @@
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
const char* ssid = "........"; const char* ssid = "SSID";
const char* ssidPassword = "........"; const char* ssidPassword = "PASSWORD";
const char *username = "admin"; const char *username = "admin";
const char *password = "admin"; const char *password = "admin";
@ -76,7 +76,7 @@ String getDigestAuth(String& authReq, const String& username, const String& pass
} }
void setup() { void setup() {
Serial.begin(9600); Serial.begin(115200);
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(ssid, ssidPassword); WiFi.begin(ssid, ssidPassword);
@ -95,10 +95,12 @@ void setup() {
void loop() { void loop() {
HTTPClient http; HTTPClient http;
WiFiClient client;
Serial.print("[HTTP] begin...\n"); Serial.print("[HTTP] begin...\n");
// configure traged server and url // configure traged server and url
http.begin(String(server) + String(uri)); http.begin(client, String(server) + String(uri));
const char *keys[] = {"WWW-Authenticate"}; const char *keys[] = {"WWW-Authenticate"};
@ -115,7 +117,7 @@ void loop() {
String authorization = getDigestAuth(authReq, String(username), String(password), String(uri), 1); String authorization = getDigestAuth(authReq, String(username), String(password), String(uri), 1);
http.end(); http.end();
http.begin(String(server) + String(uri)); http.begin(client, String(server) + String(uri));
http.addHeader("Authorization", authorization); http.addHeader("Authorization", authorization);

View File

@ -13,24 +13,22 @@
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
#define USE_SERIAL Serial
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
HTTPClient http; HTTPClient http;
void setup() { void setup() {
USE_SERIAL.begin(115200); Serial.begin(115200);
// USE_SERIAL.setDebugOutput(true); // Serial.setDebugOutput(true);
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
for (uint8_t t = 4; t > 0; t--) { for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); Serial.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush(); Serial.flush();
delay(1000); delay(1000);
} }
@ -45,19 +43,21 @@ void loop() {
// wait for WiFi connection // wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
http.begin("http://192.168.1.12/test.html"); WiFiClient client;
//http.begin("192.168.1.12", 80, "/test.html");
http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
//http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
int httpCode = http.GET(); int httpCode = http.GET();
if (httpCode > 0) { if (httpCode > 0) {
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server // file found at server
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
http.writeToStream(&USE_SERIAL); http.writeToStream(&Serial);
} }
} else { } else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
} }
http.end(); http.end();
@ -65,6 +65,3 @@ void loop() {
delay(1000); delay(1000);
} }

View File

@ -12,22 +12,20 @@
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
#define USE_SERIAL Serial
ESP8266WiFiMulti WiFiMulti; ESP8266WiFiMulti WiFiMulti;
void setup() { void setup() {
USE_SERIAL.begin(115200); Serial.begin(115200);
// USE_SERIAL.setDebugOutput(true); // Serial.setDebugOutput(true);
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
USE_SERIAL.println(); Serial.println();
for (uint8_t t = 4; t > 0; t--) { for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); Serial.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush(); Serial.flush();
delay(1000); delay(1000);
} }
@ -42,18 +40,20 @@ void loop() {
HTTPClient http; HTTPClient http;
USE_SERIAL.print("[HTTP] begin...\n"); WiFiClient client;
Serial.print("[HTTP] begin...\n");
// configure server and url // configure server and url
http.begin("http://192.168.1.12/test.html"); http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
//http.begin("192.168.1.12", 80, "/test.html"); //http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
USE_SERIAL.print("[HTTP] GET...\n"); Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header // start connection and send HTTP header
int httpCode = http.GET(); int httpCode = http.GET();
if (httpCode > 0) { if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled // HTTP header has been send and Server response header has been handled
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server // file found at server
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
@ -65,7 +65,7 @@ void loop() {
uint8_t buff[128] = { 0 }; uint8_t buff[128] = { 0 };
// get tcp stream // get tcp stream
WiFiClient * stream = http.getStreamPtr(); WiFiClient * stream = &client;
// read all data from server // read all data from server
while (http.connected() && (len > 0 || len == -1)) { while (http.connected() && (len > 0 || len == -1)) {
@ -77,7 +77,7 @@ void loop() {
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// write it to Serial // write it to Serial
USE_SERIAL.write(buff, c); Serial.write(buff, c);
if (len > 0) { if (len > 0) {
len -= c; len -= c;
@ -86,12 +86,12 @@ void loop() {
delay(1); delay(1);
} }
USE_SERIAL.println(); Serial.println();
USE_SERIAL.print("[HTTP] connection closed or file end.\n"); Serial.print("[HTTP] connection closed or file end.\n");
} }
} else { } else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
} }
http.end(); http.end();
@ -99,4 +99,3 @@ void loop() {
delay(10000); delay(10000);
} }

View File

@ -0,0 +1,115 @@
/**
StreamHTTPClient.ino
Created on: 24.05.2015
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
ESP8266WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD");
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
HTTPClient http;
BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure ;
bool mfln = client->probeMaxFragmentLength("tls.mbed.org", 443, 1024);
Serial.printf("\nConnecting to https://tls.mbed.org\n");
Serial.printf("Maximum fragment Length negotiation supported: %s\n", mfln ? "yes" : "no");
if (mfln) {
client->setBufferSizes(1024, 1024);
}
Serial.print("[HTTPS] begin...\n");
// configure server and url
const uint8_t fingerprint[20] = {0xEB, 0xD9, 0xDF, 0x37, 0xC2, 0xCC, 0x84, 0x89, 0x00, 0xA0, 0x58, 0x52, 0x24, 0x04, 0xE4, 0x37, 0x3E, 0x2B, 0xF1, 0x41};
client->setFingerprint(fingerprint);
if (http.begin(*client, "https://tls.mbed.org/")) {
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
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) {
// get lenght of document (is -1 when Server sends no Content-Length header)
int len = http.getSize();
// create buffer for read
static uint8_t buff[128] = { 0 };
// get tcp stream
WiFiClient * stream = client;
// read all data from server
while (http.connected() && (len > 0 || len == -1)) {
// get available data size
size_t size = stream->available();
if (size) {
// read up to 128 byte
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// write it to Serial
Serial.write(buff, c);
if (len > 0) {
len -= c;
}
}
delay(1);
}
Serial.println();
Serial.print("[HTTPS] connection closed or file end.\n");
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("Unable to connect\n");
}
delete client;
}
delay(10000);
}

View File

@ -1,5 +1,5 @@
name=ESP8266HTTPClient name=ESP8266HTTPClient
version=1.1 version=1.2
author=Markus Sattler author=Markus Sattler
maintainer=Markus Sattler maintainer=Markus Sattler
sentence=http Client for ESP8266 sentence=http Client for ESP8266

View File

@ -21,15 +21,19 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* *
*/ */
#include <Arduino.h> #include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <StreamString.h>
#include <base64.h>
#include "ESP8266HTTPClient.h" #include "ESP8266HTTPClient.h"
#ifdef HTTPCLIENT_1_1_COMPATIBLE
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#endif
#include <StreamString.h>
#include <base64.h>
#ifdef HTTPCLIENT_1_1_COMPATIBLE
class TransportTraits class TransportTraits
{ {
public: public:
@ -100,12 +104,17 @@ public:
protected: protected:
uint8_t _fingerprint[20]; uint8_t _fingerprint[20];
}; };
#endif // HTTPCLIENT_1_1_COMPATIBLE
/** /**
* constructor * constructor
*/ */
HTTPClient::HTTPClient() HTTPClient::HTTPClient()
{ {
_client = nullptr;
#ifdef HTTPCLIENT_1_1_COMPATIBLE
_tcpDeprecated.reset(nullptr);
#endif
} }
/** /**
@ -113,8 +122,8 @@ HTTPClient::HTTPClient()
*/ */
HTTPClient::~HTTPClient() HTTPClient::~HTTPClient()
{ {
if(_tcp) { if(_client) {
_tcp->stop(); _client->stop();
} }
if(_currentHeaders) { if(_currentHeaders) {
delete[] _currentHeaders; delete[] _currentHeaders;
@ -130,9 +139,66 @@ 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) {
end();
_client = &client;
// check for : (http: or https:)
int index = url.indexOf(':');
if(index < 0) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] failed to parse protocol\n");
return false;
}
String protocol = url.substring(0, index);
if(protocol != "http" && protocol != "https") {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] unknown protocol '%s'\n", 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)
{
end();
_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, String httpsFingerprint) bool HTTPClient::begin(String url, String httpsFingerprint)
{ {
_transportTraits.reset(nullptr); if(_client) _canReuse = false;
end();
_port = 443; _port = 443;
if (httpsFingerprint.length() == 0) { if (httpsFingerprint.length() == 0) {
return false; return false;
@ -148,7 +214,9 @@ bool HTTPClient::begin(String url, String httpsFingerprint)
bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20]) bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
{ {
_transportTraits.reset(nullptr); if(_client) _canReuse = false;
end();
_port = 443; _port = 443;
if (!beginInternal(url, "https")) { if (!beginInternal(url, "https")) {
return false; return false;
@ -169,7 +237,9 @@ bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
*/ */
bool HTTPClient::begin(String url) bool HTTPClient::begin(String url)
{ {
_transportTraits.reset(nullptr); if(_client) _canReuse = false;
end();
_port = 80; _port = 80;
if (!beginInternal(url, "http")) { if (!beginInternal(url, "http")) {
return false; return false;
@ -177,6 +247,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)
{ {
@ -225,8 +296,12 @@ 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) _canReuse = false;
end();
clear(); clear();
_host = host; _host = host;
_port = port; _port = port;
@ -236,6 +311,8 @@ bool HTTPClient::begin(String host, uint16_t port, String uri)
return true; return true;
} }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
bool HTTPClient::begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) bool HTTPClient::begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint)
{ {
if (https) { if (https) {
@ -244,9 +321,13 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, bool https, Strin
return begin(host, port, uri); return begin(host, port, uri);
} }
} }
#pragma GCC diagnostic pop
bool HTTPClient::begin(String host, uint16_t port, String uri, String httpsFingerprint) bool HTTPClient::begin(String host, uint16_t port, String uri, String httpsFingerprint)
{ {
if(_client) _canReuse = false;
end();
clear(); clear();
_host = host; _host = host;
_port = port; _port = port;
@ -262,6 +343,9 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, String httpsFinge
bool HTTPClient::begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]) bool HTTPClient::begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20])
{ {
if(_client) _canReuse = false;
end();
clear(); clear();
_host = host; _host = host;
_port = port; _port = port;
@ -275,7 +359,7 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, const uint8_t htt
DEBUG_HTTPCLIENT("\n"); DEBUG_HTTPCLIENT("\n");
return true; return true;
} }
#endif // HTTPCLIENT_1_1_COMPATIBLE
/** /**
* end * end
@ -294,17 +378,29 @@ void HTTPClient::end(void)
void HTTPClient::disconnect() void HTTPClient::disconnect()
{ {
if(connected()) { if(connected()) {
if(_tcp->available() > 0) { if(_client) {
DEBUG_HTTPCLIENT("[HTTP-Client][end] still data in buffer (%d), clean up.\n", _tcp->available()); if(_client->available() > 0) {
while(_tcp->available() > 0) { DEBUG_HTTPCLIENT("[HTTP-Client][end] still data in buffer (%d), clean up.\n", _client->available());
_tcp->read(); while(_client->available() > 0) {
_client->read();
}
} }
} }
if(_reuse && _canReuse) { if(_reuse && _canReuse) {
DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n"); DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n");
} else { } else {
DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop\n"); DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop\n");
_tcp->stop(); if(_client) {
_client->stop();
_client = nullptr;
}
#ifdef HTTPCLIENT_1_1_COMPATIBLE
if(_tcpDeprecated) {
_transportTraits.reset(nullptr);
_tcpDeprecated.reset(nullptr);
}
#endif
} }
} else { } else {
DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp is closed\n"); DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp is closed\n");
@ -317,8 +413,8 @@ void HTTPClient::disconnect()
*/ */
bool HTTPClient::connected() bool HTTPClient::connected()
{ {
if(_tcp) { if(_client) {
return (_tcp->connected() || (_tcp->available() > 0)); return (_client->connected() || (_client->available() > 0));
} }
return false; return false;
} }
@ -376,7 +472,7 @@ void HTTPClient::setTimeout(uint16_t timeout)
{ {
_tcpTimeout = timeout; _tcpTimeout = timeout;
if(connected()) { if(connected()) {
_tcp->setTimeout(timeout); _client->setTimeout(timeout);
} }
} }
@ -478,7 +574,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);
} }
} }
@ -557,7 +653,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 ?
@ -565,11 +661,11 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d retry...\n", bytesRead, bytesWrite); DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d retry...\n", bytesRead, bytesWrite);
// check for write error // check for write error
if(_tcp->getWriteError()) { if(_client->getWriteError()) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _tcp->getWriteError()); DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _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
@ -578,7 +674,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) {
@ -590,8 +686,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()) {
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _tcp->getWriteError()); DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _client->getWriteError());
free(buff); free(buff);
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
} }
@ -642,7 +738,7 @@ int HTTPClient::getSize(void)
WiFiClient& HTTPClient::getStream(void) WiFiClient& HTTPClient::getStream(void)
{ {
if(connected()) { if(connected()) {
return *_tcp; return *_client;
} }
DEBUG_HTTPCLIENT("[HTTP-Client] getStream: not connected\n"); DEBUG_HTTPCLIENT("[HTTP-Client] getStream: not connected\n");
@ -657,7 +753,7 @@ WiFiClient& HTTPClient::getStream(void)
WiFiClient* HTTPClient::getStreamPtr(void) WiFiClient* HTTPClient::getStreamPtr(void)
{ {
if(connected()) { if(connected()) {
return _tcp.get(); return _client;
} }
DEBUG_HTTPCLIENT("[HTTP-Client] getStreamPtr: not connected\n"); DEBUG_HTTPCLIENT("[HTTP-Client] getStreamPtr: not connected\n");
@ -697,7 +793,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);
@ -734,7 +830,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);
} }
@ -903,39 +999,46 @@ bool HTTPClient::hasHeader(const char* name)
*/ */
bool HTTPClient::connect(void) bool HTTPClient::connect(void)
{ {
if(connected()) { if(connected()) {
DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, try reuse!\n"); DEBUG_HTTPCLIENT("[HTTP-Client] connect. already connected, try reuse!\n");
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) {
DEBUG_HTTPCLIENT("[HTTP-Client] connect: HTTPClient::begin was not called or returned error\n"); DEBUG_HTTPCLIENT("[HTTP-Client] connect: HTTPClient::begin was not called or returned error\n");
return false; return false;
} }
_tcp = _transportTraits->create(); _client->setTimeout(_tcpTimeout);
_tcp->setTimeout(_tcpTimeout);
if(!_tcp->connect(_host.c_str(), _port)) { if(!_client->connect(_host.c_str(), _port)) {
DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u\n", _host.c_str(), _port); DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u\n", _host.c_str(), _port);
return false; return false;
} }
DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u\n", _host.c_str(), _port); DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u\n", _host.c_str(), _port);
if (!_transportTraits->verify(*_tcp, _host.c_str())) { #ifdef HTTPCLIENT_1_1_COMPATIBLE
if (_tcpDeprecated && !_transportTraits->verify(*_tcpDeprecated, _host.c_str())) {
DEBUG_HTTPCLIENT("[HTTP-Client] transport level verify failed\n"); DEBUG_HTTPCLIENT("[HTTP-Client] transport level verify failed\n");
_tcp->stop(); _client->stop();
return false; return false;
} }
#endif
#ifdef ESP8266 #ifdef ESP8266
_tcp->setNoDelay(true); _client->setNoDelay(true);
#endif #endif
return connected(); return connected();
} }
@ -990,7 +1093,7 @@ bool HTTPClient::sendHeader(const char * type)
DEBUG_HTTPCLIENT("[HTTP-Client] sending request header\n-----\n%s-----\n", header.c_str()); DEBUG_HTTPCLIENT("[HTTP-Client] sending request header\n-----\n%s-----\n", header.c_str());
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());
} }
/** /**
@ -1011,9 +1114,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();
@ -1114,7 +1217,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) {
@ -1131,7 +1234,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);
@ -1212,7 +1315,7 @@ int HTTPClient::returnError(int error)
DEBUG_HTTPCLIENT("[HTTP-Client][returnError] error(%d): %s\n", error, errorToString(error).c_str()); DEBUG_HTTPCLIENT("[HTTP-Client][returnError] error(%d): %s\n", error, errorToString(error).c_str());
if(connected()) { if(connected()) {
DEBUG_HTTPCLIENT("[HTTP-Client][returnError] tcp stop\n"); DEBUG_HTTPCLIENT("[HTTP-Client][returnError] tcp stop\n");
_tcp->stop(); _client->stop();
} }
} }
return error; return error;

View File

@ -20,13 +20,17 @@
* 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
* *
* Modified by Jeroen Döll, June 2018
*/ */
#ifndef ESP8266HTTPClient_H_ #ifndef ESP8266HTTPClient_H_
#define ESP8266HTTPClient_H_ #define ESP8266HTTPClient_H_
#define HTTPCLIENT_1_1_COMPATIBLE
#include <memory> #include <memory>
#include <Arduino.h> #include <Arduino.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#ifdef DEBUG_ESP_HTTP_CLIENT #ifdef DEBUG_ESP_HTTP_CLIENT
@ -124,8 +128,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 StreamString; class StreamString;
@ -135,17 +141,26 @@ 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
// Plain HTTP connection, unencrypted // Plain HTTP connection, unencrypted
bool begin(String url); bool begin(String url) __attribute__ ((deprecated));
bool begin(String host, uint16_t port, String uri = "/"); bool begin(String host, uint16_t port, String uri = "/") __attribute__ ((deprecated));
// Use axTLS for secure HTTPS connection // Use axTLS for secure HTTPS connection
bool begin(String url, String httpsFingerprint); bool begin(String url, String httpsFingerprint) __attribute__ ((deprecated));
bool begin(String host, uint16_t port, String uri, String httpsFingerprint); bool begin(String host, uint16_t port, String uri, String httpsFingerprint) __attribute__ ((deprecated));
// Use BearSSL for secure HTTPS connection // Use BearSSL for secure HTTPS connection
bool begin(String url, const uint8_t httpsFingerprint[20]); bool begin(String url, const uint8_t httpsFingerprint[20]) __attribute__ ((deprecated));
bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]); bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]) __attribute__ ((deprecated));
// deprecated, use the overload above instead // deprecated, use the overload above instead
bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__ ((deprecated)); bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__ ((deprecated));
#endif
void end(void); void end(void);
@ -207,8 +222,11 @@ 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;

View File

@ -35,18 +35,30 @@ void setup() {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD"); WiFiMulti.addAP("SSID", "PASSWORD");
} }
void loop() { void loop() {
// wait for WiFi connection // wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
t_httpUpdate_return ret = ESPhttpUpdate.update("http://server/file.bin"); WiFiClient client;
//t_httpUpdate_return ret = ESPhttpUpdate.update("https://server/file.bin", "", "fingerprint");
// The line below is optional. It can be used to blink the LED on the board during flashing
// The LED will be on during download of one buffer of data from the network. The LED will
// be off during writing that buffer to flash
// On a good connection the LED should flash regularly. On a bad connection the LED will be
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://server/file.bin");
// Or:
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin");
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED:
USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break; break;
case HTTP_UPDATE_NO_UPDATES: case HTTP_UPDATE_NO_UPDATES:

View File

@ -42,10 +42,21 @@ void loop() {
if ((WiFiMulti.run() == WL_CONNECTED)) { if ((WiFiMulti.run() == WL_CONNECTED)) {
USE_SERIAL.println("Update SPIFFS..."); USE_SERIAL.println("Update SPIFFS...");
t_httpUpdate_return ret = ESPhttpUpdate.updateSpiffs("http://server/spiffs.bin");
WiFiClient client;
// The line below is optional. It can be used to blink the LED on the board during flashing
// The LED will be on during download of one buffer of data from the network. The LED will
// be off during writing that buffer to flash
// On a good connection the LED should flash regularly. On a bad connection the LED will be
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
t_httpUpdate_return ret = ESPhttpUpdate.updateSpiffs(client, "http://server/spiffs.bin");
if (ret == HTTP_UPDATE_OK) { if (ret == HTTP_UPDATE_OK) {
USE_SERIAL.println("Update sketch..."); USE_SERIAL.println("Update sketch...");
ret = ESPhttpUpdate.update("http://server/file.bin"); ret = ESPhttpUpdate.update(client, "http://server/file.bin");
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED:

View File

@ -0,0 +1,149 @@
/**
httpUpdateSecure.ino
Created on: 20.06.2018 as an adaptation of httpUpdate.ino
*/
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <time.h>
#define USE_SERIAL Serial
ESP8266WiFiMulti WiFiMulti;
// A single, global CertStore which can be used by all
// connections. Needs to stay live the entire time any of
// the WiFiClientBearSSLs are present.
#include <CertStoreBearSSL.h>
BearSSL::CertStore certStore;
#include <FS.h>
class SPIFFSCertStoreFile : public BearSSL::CertStoreFile {
public:
SPIFFSCertStoreFile(const char *name) {
_name = name;
};
virtual ~SPIFFSCertStoreFile() override {};
// The main API
virtual bool open(bool write = false) override {
_file = SPIFFS.open(_name, write ? "w" : "r");
return _file;
}
virtual bool seek(size_t absolute_pos) override {
return _file.seek(absolute_pos, SeekSet);
}
virtual ssize_t read(void *dest, size_t bytes) override {
return _file.readBytes((char*)dest, bytes);
}
virtual ssize_t write(void *dest, size_t bytes) override {
return _file.write((uint8_t*)dest, bytes);
}
virtual void close() override {
_file.close();
}
private:
File _file;
const char *_name;
};
SPIFFSCertStoreFile certs_idx("/certs.idx");
SPIFFSCertStoreFile certs_ar("/certs.ar");
// Set time via NTP, as required for x.509 validation
void setClock() {
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC
USE_SERIAL.print(F("Waiting for NTP time sync: "));
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) {
yield();
delay(500);
USE_SERIAL.print(F("."));
now = time(nullptr);
}
USE_SERIAL.println(F(""));
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
USE_SERIAL.print(F("Current time: "));
USE_SERIAL.print(asctime(&timeinfo));
}
void setup() {
USE_SERIAL.begin(115200);
// USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASSWORD");
SPIFFS.begin();
int numCerts = certStore.initCertStore(&certs_idx, &certs_ar);
USE_SERIAL.print(F("Number of CA certs read: ")); USE_SERIAL.println(numCerts);
if (numCerts == 0) {
USE_SERIAL.println(F("No certs found. Did you run certs-from-mozill.py and upload the SPIFFS directory before running?"));
return; // Can't connect to anything w/o certs!
}
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
setClock();
BearSSL::WiFiClientSecure client;
bool mfln = client.probeMaxFragmentLength("server", 443, 1024); // server must be the same as in ESPhttpUpdate.update()
USE_SERIAL.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
if (mfln) {
client.setBufferSizes(1024, 1024);
}
client.setCertStore(&certStore);
// The line below is optional. It can be used to blink the LED on the board during flashing
// The LED will be on during download of one buffer of data from the network. The LED will
// be off during writing that buffer to flash
// On a good connection the LED should flash regularly. On a bad connection the LED will be
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
t_httpUpdate_return ret = ESPhttpUpdate.update(client, "https://server/file.bin");
// Or:
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 443, "file.bin");
switch (ret) {
case HTTP_UPDATE_FAILED:
USE_SERIAL.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
USE_SERIAL.println("HTTP_UPDATE_OK");
break;
}
}
}

View File

@ -1,5 +1,5 @@
name=ESP8266httpUpdate name=ESP8266httpUpdate
version=1.2 version=1.3
author=Markus Sattler author=Markus Sattler
maintainer=Markus Sattler maintainer=Markus Sattler
sentence=Http Update for ESP8266 sentence=Http Update for ESP8266

View File

@ -30,12 +30,12 @@ extern "C" uint32_t _SPIFFS_start;
extern "C" uint32_t _SPIFFS_end; extern "C" uint32_t _SPIFFS_end;
ESP8266HTTPUpdate::ESP8266HTTPUpdate(void) ESP8266HTTPUpdate::ESP8266HTTPUpdate(void)
: _httpClientTimeout(8000) : _httpClientTimeout(8000), _ledPin(-1)
{ {
} }
ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout) ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout)
: _httpClientTimeout(httpClientTimeout) : _httpClientTimeout(httpClientTimeout), _ledPin(-1)
{ {
} }
@ -43,17 +43,24 @@ ESP8266HTTPUpdate::~ESP8266HTTPUpdate(void)
{ {
} }
#ifdef HTTPUPDATE_1_2_COMPATIBLE
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion, HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion,
const String& httpsFingerprint, bool reboot) const String& httpsFingerprint, bool reboot)
{ {
rebootOnUpdate(reboot); rebootOnUpdate(reboot);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return update(url, currentVersion, httpsFingerprint); return update(url, currentVersion, httpsFingerprint);
#pragma GCC diagnostic pop
} }
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion) HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& currentVersion)
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(url); http.begin(url);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, false); return handleUpdate(http, currentVersion, false);
} }
@ -61,7 +68,10 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& curr
const String& httpsFingerprint) const String& httpsFingerprint)
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(url, httpsFingerprint); http.begin(url, httpsFingerprint);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, false); return handleUpdate(http, currentVersion, false);
} }
@ -69,40 +79,73 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(const String& url, const String& curr
const uint8_t httpsFingerprint[20]) const uint8_t httpsFingerprint[20])
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(url, httpsFingerprint); http.begin(url, httpsFingerprint);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, false);
}
#endif
HTTPUpdateResult ESP8266HTTPUpdate::update(WiFiClient& client, const String& url, const String& currentVersion)
{
HTTPClient http;
http.begin(client, url);
return handleUpdate(http, currentVersion, false); return handleUpdate(http, currentVersion, false);
} }
#ifdef HTTPUPDATE_1_2_COMPATIBLE
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint) HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint)
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(url, httpsFingerprint); http.begin(url, httpsFingerprint);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, true); return handleUpdate(http, currentVersion, true);
} }
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion, const uint8_t httpsFingerprint[20]) HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion, const uint8_t httpsFingerprint[20])
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(url, httpsFingerprint); http.begin(url, httpsFingerprint);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, true); return handleUpdate(http, currentVersion, true);
} }
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion) HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(const String& url, const String& currentVersion)
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(url); http.begin(url);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, true);
}
#endif
HTTPUpdateResult ESP8266HTTPUpdate::updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion)
{
HTTPClient http;
http.begin(client, url);
return handleUpdate(http, currentVersion, true); return handleUpdate(http, currentVersion, true);
} }
#ifdef HTTPUPDATE_1_2_COMPATIBLE
HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, const String& uri, const String& currentVersion, HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
bool https, const String& httpsFingerprint, bool reboot) bool https, const String& httpsFingerprint, bool reboot)
{ {
(void)https; (void)https;
rebootOnUpdate(reboot); rebootOnUpdate(reboot);
if (httpsFingerprint.length() == 0) { if (httpsFingerprint.length() == 0) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return update(host, port, uri, currentVersion); return update(host, port, uri, currentVersion);
} else { } else {
return update(host, port, uri, currentVersion, httpsFingerprint); return update(host, port, uri, currentVersion, httpsFingerprint);
#pragma GCC diagnostic pop
} }
} }
@ -110,7 +153,10 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, co
const String& currentVersion) const String& currentVersion)
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(host, port, uri); http.begin(host, port, uri);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, false); return handleUpdate(http, currentVersion, false);
} }
@ -118,7 +164,10 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, co
const String& currentVersion, const String& httpsFingerprint) const String& currentVersion, const String& httpsFingerprint)
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(host, port, url, httpsFingerprint); http.begin(host, port, url, httpsFingerprint);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, false); return handleUpdate(http, currentVersion, false);
} }
@ -126,7 +175,19 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, co
const String& currentVersion, const uint8_t httpsFingerprint[20]) const String& currentVersion, const uint8_t httpsFingerprint[20])
{ {
HTTPClient http; HTTPClient http;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
http.begin(host, port, url, httpsFingerprint); http.begin(host, port, url, httpsFingerprint);
#pragma GCC diagnostic pop
return handleUpdate(http, currentVersion, false);
}
#endif
HTTPUpdateResult ESP8266HTTPUpdate::update(WiFiClient& client, const String& host, uint16_t port, const String& uri,
const String& currentVersion)
{
HTTPClient http;
http.begin(client, host, port, uri);
return handleUpdate(http, currentVersion, false); return handleUpdate(http, currentVersion, false);
} }
@ -321,7 +382,6 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
return HTTP_UPDATE_FAILED; return HTTP_UPDATE_FAILED;
} }
} }
if(runUpdate(*tcp, len, http.header("x-MD5"), command)) { if(runUpdate(*tcp, len, http.header("x-MD5"), command)) {
ret = HTTP_UPDATE_OK; ret = HTTP_UPDATE_OK;
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n"); DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
@ -378,7 +438,7 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int com
StreamString error; StreamString error;
if(!Update.begin(size, command)) { if(!Update.begin(size, command, _ledPin, _ledOn)) {
_lastError = Update.getError(); _lastError = Update.getError();
Update.printError(error); Update.printError(error);
error.trim(); // remove line ending error.trim(); // remove line ending

View File

@ -26,6 +26,8 @@
#ifndef ESP8266HTTPUPDATE_H_ #ifndef ESP8266HTTPUPDATE_H_
#define ESP8266HTTPUPDATE_H_ #define ESP8266HTTPUPDATE_H_
#define HTTPUPDATE_1_2_COMPATIBLE
#include <Arduino.h> #include <Arduino.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
@ -72,32 +74,48 @@ public:
_rebootOnUpdate = reboot; _rebootOnUpdate = reboot;
} }
void setLedPin(int ledPin = -1, uint8_t ledOn = HIGH)
{
_ledPin = ledPin;
_ledOn = ledOn;
}
#ifdef HTTPUPDATE_1_2_COMPATIBLE
// This function is deprecated, use rebootOnUpdate and the next one instead // This function is deprecated, use rebootOnUpdate and the next one instead
t_httpUpdate_return update(const String& url, const String& currentVersion, t_httpUpdate_return update(const String& url, const String& currentVersion,
const String& httpsFingerprint, bool reboot) __attribute__((deprecated)); const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
t_httpUpdate_return update(const String& url, const String& currentVersion = ""); t_httpUpdate_return update(const String& url, const String& currentVersion = "") __attribute__((deprecated));
t_httpUpdate_return update(const String& url, const String& currentVersion, t_httpUpdate_return update(const String& url, const String& currentVersion,
const String& httpsFingerprint); const String& httpsFingerprint) __attribute__((deprecated));
t_httpUpdate_return update(const String& url, const String& currentVersion, t_httpUpdate_return update(const String& url, const String& currentVersion,
const uint8_t httpsFingerprint[20]); // BearSSL const uint8_t httpsFingerprint[20]) __attribute__((deprecated)); // BearSSL
#endif
t_httpUpdate_return update(WiFiClient& client, const String& url, const String& currentVersion = "");
#ifdef HTTPUPDATE_1_2_COMPATIBLE
// This function is deprecated, use one of the overloads below along with rebootOnUpdate // This function is deprecated, use one of the overloads below along with rebootOnUpdate
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri, const String& currentVersion, t_httpUpdate_return update(const String& host, uint16_t port, const String& uri, const String& currentVersion,
bool https, const String& httpsFingerprint, bool reboot) __attribute__((deprecated)); bool https, const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri = "/", t_httpUpdate_return update(const String& host, uint16_t port, const String& uri = "/",
const String& currentVersion = "") __attribute__((deprecated));
t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
const String& currentVersion, const String& httpsFingerprint) __attribute__((deprecated));
t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
const String& currentVersion, const uint8_t httpsFingerprint[20]) __attribute__((deprecated)); // BearSSL
#endif
t_httpUpdate_return update(WiFiClient& client, const String& host, uint16_t port, const String& uri = "/",
const String& currentVersion = ""); const String& currentVersion = "");
t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
const String& currentVersion, const String& httpsFingerprint);
t_httpUpdate_return update(const String& host, uint16_t port, const String& url,
const String& currentVersion, const uint8_t httpsFingerprint[20]); // BearSSL
#ifdef HTTPUPDATE_1_2_COMPATIBLE
// This function is deprecated, use rebootOnUpdate and the next one instead // This function is deprecated, use rebootOnUpdate and the next one instead
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion, t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion,
const String& httpsFingerprint, bool reboot) __attribute__((deprecated)); const String& httpsFingerprint, bool reboot) __attribute__((deprecated));
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion = ""); t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion = "") __attribute__((deprecated));
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint); t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion, const String& httpsFingerprint) __attribute__((deprecated));
t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion, const uint8_t httpsFingerprint[20]); // BearSSL t_httpUpdate_return updateSpiffs(const String& url, const String& currentVersion, const uint8_t httpsFingerprint[20]) __attribute__((deprecated)); // BearSSL
#endif
t_httpUpdate_return updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion = "");
int getLastError(void); int getLastError(void);
@ -111,6 +129,9 @@ protected:
bool _rebootOnUpdate = true; bool _rebootOnUpdate = true;
private: private:
int _httpClientTimeout; int _httpClientTimeout;
int _ledPin;
uint8_t _ledOn;
}; };
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)