Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/esp8266 http client #5250

Merged
merged 14 commits into from
Oct 21, 2018
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -45,37 +45,41 @@ void loop() {

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);
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically correct: the client object must outlive the http object that uses it.
However, it is rather unclear at first glance that this is the reason for the scope. Also, someone looking at the example would be unlikely to realize the importance of the scope.
Instead, consider wrapping the allocation in a std::unique_ptr:

std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);

Then, the internal object can be passed by get():

if (https.begin(*client, "https://jigsaw.w3.org/HTTP/connection.html")) {  // HTTPS
...

Because both objects are in the same scope, and because the client must be declared before the http object, when exiting the scope their destruction will automatically happen in the correct order: inverse of their construction.
Also, no need to call delete.
Also, I don't like having manual handling of dynamic objects in an example ino, which will be viewed and used by inexperienced users, so smart pointers is better.

// Create a block arround HTTPClient, so it is destroyed before WiFiClientSecure *client is deleted
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] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
Serial.printf("[HTTPS] Unable to connect\n");
}

https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
// End block around HTTPClient
}

delete client;
}

Serial.println("Wait 10s before next round...");
delay(10000);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ 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);
Expand All @@ -55,61 +53,69 @@ void loop() {
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/")) {
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: consider wrapping in a std::unique_ptr, and removing the scope.

// Create a block arround HTTPClient, so it is destroyed before WiFiClientSecure *client is deleted
HTTPClient https;

if (https.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);
Serial.print("[HTTPS] GET...\n");
// start connection and send HTTP header
int httpCode = https.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) {
// 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();
// get lenght of document (is -1 when Server sends no Content-Length header)
int len = https.getSize();

// create buffer for read
static uint8_t buff[128] = { 0 };
// create buffer for read
static uint8_t buff[128] = { 0 };

// get tcp stream
WiFiClient * stream = client;
// 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();
// read all data from server
while (https.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));
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);
// write it to Serial
Serial.write(buff, c);

if (len > 0) {
len -= c;
if (len > 0) {
len -= c;
}
}
delay(1);
}
delay(1);
}

Serial.println();
Serial.print("[HTTPS] connection closed or file end.\n");
Serial.println();
Serial.print("[HTTPS] connection closed or file end.\n");

}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}

https.end();
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
Serial.printf("Unable to connect\n");
}

http.end();
} else {
Serial.printf("Unable to connect\n");
// End block around HTTPCLient
}

delete client;
}

Serial.println("Wait 10s before the next round...");
delay(10000);
}
73 changes: 50 additions & 23 deletions libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ HTTPClient::HTTPClient()
HTTPClient::~HTTPClient()
{
if(_client) {
DEBUG_HTTPCLIENT("[HTTP-Client][~HTTPClient] end() not called before destruction of HTTPClient\n");
_client->stop();
}
if(_currentHeaders) {
delete[] _currentHeaders;
Expand All @@ -147,7 +147,13 @@ void HTTPClient::clear()
* @return success bool
*/
bool HTTPClient::begin(WiFiClient &client, String url) {
end();
#ifdef HTTPCLIENT_1_1_COMPATIBLE
if(_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}
#endif

_client = &client;

Expand Down Expand Up @@ -180,7 +186,13 @@ bool HTTPClient::begin(WiFiClient &client, String url) {
*/
bool HTTPClient::begin(WiFiClient &client, String host, uint16_t port, String uri, bool https)
{
end();
#ifdef HTTPCLIENT_1_1_COMPATIBLE
if(_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}
#endif

_client = &client;

Expand All @@ -196,8 +208,11 @@ bool HTTPClient::begin(WiFiClient &client, String host, uint16_t port, String ur
#ifdef HTTPCLIENT_1_1_COMPATIBLE
bool HTTPClient::begin(String url, String httpsFingerprint)
{
_canReuse = false;
end();
if(_client && !_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}

_port = 443;
if (httpsFingerprint.length() == 0) {
Expand All @@ -214,8 +229,11 @@ bool HTTPClient::begin(String url, String httpsFingerprint)

bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
{
_canReuse = false;
end();
if(_client && !_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}

_port = 443;
if (!beginInternal(url, "https")) {
Expand All @@ -237,8 +255,11 @@ bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
*/
bool HTTPClient::begin(String url)
{
_canReuse = false;
end();
if(_client && !_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}

_port = 80;
if (!beginInternal(url, "http")) {
Expand Down Expand Up @@ -299,8 +320,11 @@ bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
#ifdef HTTPCLIENT_1_1_COMPATIBLE
bool HTTPClient::begin(String host, uint16_t port, String uri)
{
_canReuse = false;
end();
if(_client && !_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}

clear();
_host = host;
Expand All @@ -325,8 +349,11 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, bool https, Strin

bool HTTPClient::begin(String host, uint16_t port, String uri, String httpsFingerprint)
{
_canReuse = false;
end();
if(_client && !_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}

clear();
_host = host;
Expand All @@ -343,8 +370,11 @@ 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])
{
_canReuse = false;
end();
if(_client && !_tcpDeprecated) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
_canReuse = false;
end();
}

clear();
_host = host;
Expand All @@ -367,7 +397,6 @@ bool HTTPClient::begin(String host, uint16_t port, String uri, const uint8_t htt
*/
void HTTPClient::end(void)
{
_canReuse = false;
disconnect();
clear();
}
Expand All @@ -379,15 +408,13 @@ void HTTPClient::end(void)
void HTTPClient::disconnect()
{
if(connected()) {
if(_client) {
if(_client->available() > 0) {
DEBUG_HTTPCLIENT("[HTTP-Client][end] still data in buffer (%d), clean up.\n", _client->available());
while(_client->available() > 0) {
_client->read();
}
if(_client->available() > 0) {
DEBUG_HTTPCLIENT("[HTTP-Client][end] still data in buffer (%d), clean up.\n", _client->available());
while(_client->available() > 0) {
_client->read();
}

}

if(_reuse && _canReuse) {
DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n");
} else {
Expand Down