Skip to content

Commit 157ce57

Browse files
Jeroen88earlephilhower
Jeroen88
andauthored
bugfix2/ESP8266HTTPClient (#6476)
* Because of git problems, start from a new fork and create a new PR. This was PR #6457 * Style update to pass Travis * Update ReuseConnectionV2.ino * fix + enforce testing http code per @earlephilhower review * Close connection before ::connecting on HTTP/1.0 HTTPClient never actually closes the TCP connection on its own. It will leave the TCP connection open unless you explicitly do a getString which makes a StreamString and stuffs it with the HTTP server response, at which point the HTTP server itself will close the connection. If you check the HTTP error code and find failure, unless you do a getString and throw it away, it won't disconnect. Even in HTTP/1.0 or in cases when you haven't enabled _reuse. Change the logic in ::connect to only reuse the connection when it is specifically allowed. Otherwise, fall back to re-connection. * Adjust example per request Do single URL get in each loop, avoid infinite for loop at end. * Fix astyle * Clean up final pass notice * Fix example syntax error Editing code in a web textbox without running it is a painful process. Co-authored-by: Earle F. Philhower, III <[email protected]>
1 parent ed8add5 commit 157ce57

File tree

2 files changed

+104
-19
lines changed

2 files changed

+104
-19
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
reuseConnectionV2.ino
3+
4+
Created on: 22.11.2015
5+
6+
This example reuses the http connection and also restores the connection if the connection is lost
7+
*/
8+
9+
10+
#include <ESP8266WiFi.h>
11+
#include <ESP8266WiFiMulti.h>
12+
#include <ESP8266HTTPClient.h>
13+
14+
#ifndef STASSID
15+
#define STASSID "your-ssid"
16+
#define STAPSK "your-password"
17+
#endif
18+
19+
ESP8266WiFiMulti WiFiMulti;
20+
21+
HTTPClient http;
22+
WiFiClient client;
23+
24+
void setup() {
25+
26+
Serial.begin(115200);
27+
// Serial.setDebugOutput(true);
28+
29+
Serial.println();
30+
Serial.println();
31+
Serial.println("Connecting to WiFi...");
32+
33+
WiFi.mode(WIFI_STA);
34+
WiFiMulti.addAP(STASSID, STAPSK);
35+
36+
// wait for WiFi connection
37+
while ((WiFiMulti.run() != WL_CONNECTED)) {
38+
Serial.write('.');
39+
delay(500);
40+
}
41+
Serial.println(" connected to WiFi");
42+
43+
// allow reuse (if server supports it)
44+
http.setReuse(true);
45+
46+
47+
http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
48+
//http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
49+
}
50+
51+
int pass = 0;
52+
53+
void loop() {
54+
// First 10 loop()s, retrieve the URL
55+
if (pass < 10) {
56+
pass++;
57+
Serial.printf("Reuse connection example, GET url for the %d time\n", pass);
58+
int httpCode = http.GET();
59+
if (httpCode > 0) {
60+
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
61+
62+
// file found at server
63+
if (httpCode == HTTP_CODE_OK) {
64+
http.writeToStream(&Serial);
65+
}
66+
} else {
67+
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
68+
// Something went wrong with the connection, try to reconnect
69+
http.end();
70+
http.begin(client, "http://jigsaw.w3.org/HTTP/connection.html");
71+
//http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
72+
}
73+
74+
if (pass == 10) {
75+
http.end();
76+
Serial.println("Done testing");
77+
} else {
78+
Serial.println("\n\n\nWait 5 second...\n");
79+
delay(5000);
80+
}
81+
}
82+
}

libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp

+22-19
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,10 @@ void HTTPClient::disconnect(bool preserveClient)
457457
#endif
458458
}
459459
} else {
460+
if (!preserveClient && _client) { // Also destroy _client if not connected()
461+
_client = nullptr;
462+
}
463+
460464
DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp is closed\n");
461465
}
462466
}
@@ -970,7 +974,9 @@ int HTTPClient::writeToStream(Stream * stream)
970974
return returnError(HTTPC_ERROR_NO_STREAM);
971975
}
972976

973-
if(!connected()) {
977+
// Only return error if not connected and no data available, because otherwise ::getString() will return an error instead of an empty
978+
// string when the server returned a http code 204 (no content)
979+
if(!connected() && _transferEncoding != HTTPC_TE_IDENTITY && _size > 0) {
974980
return returnError(HTTPC_ERROR_NOT_CONNECTED);
975981
}
976982

@@ -979,11 +985,13 @@ int HTTPClient::writeToStream(Stream * stream)
979985
int ret = 0;
980986

981987
if(_transferEncoding == HTTPC_TE_IDENTITY) {
982-
ret = writeToStreamDataBlock(stream, len);
988+
if(len > 0) {
989+
ret = writeToStreamDataBlock(stream, len);
983990

984-
// have we an error?
985-
if(ret < 0) {
986-
return returnError(ret);
991+
// have we an error?
992+
if(ret < 0) {
993+
return returnError(ret);
994+
}
987995
}
988996
} else if(_transferEncoding == HTTPC_TE_CHUNKED) {
989997
int size = 0;
@@ -1198,12 +1206,8 @@ bool HTTPClient::hasHeader(const char* name)
11981206
*/
11991207
bool HTTPClient::connect(void)
12001208
{
1201-
if(connected()) {
1202-
if(_reuse) {
1203-
DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, reusing connection\n");
1204-
} else {
1205-
DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, try reuse!\n");
1206-
}
1209+
if(_reuse && _canReuse && connected()) {
1210+
DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, reusing connection\n");
12071211
while(_client->available() > 0) {
12081212
_client->read();
12091213
}
@@ -1334,22 +1338,21 @@ int HTTPClient::handleHeaderResponse()
13341338
while(connected()) {
13351339
size_t len = _client->available();
13361340
if(len > 0) {
1341+
int headerSeparator = -1;
13371342
String headerLine = _client->readStringUntil('\n');
13381343

13391344
lastDataTime = millis();
13401345

13411346
DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] RX: '%s'\n", headerLine.c_str());
13421347

13431348
if (headerLine.startsWith(F("HTTP/1."))) {
1344-
if (_canReuse) {
1345-
_canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0');
1346-
}
1347-
_returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
1348-
continue;
1349-
}
13501349

1351-
int headerSeparator = headerLine.indexOf(':');
1352-
if (headerSeparator > 0) {
1350+
constexpr auto httpVersionIdx = sizeof "HTTP/1." - 1;
1351+
_canReuse = _canReuse && (headerLine[httpVersionIdx] != '0');
1352+
_returnCode = headerLine.substring(httpVersionIdx + 2, headerLine.indexOf(' ', httpVersionIdx + 2)).toInt();
1353+
_canReuse = _canReuse && (_returnCode > 0) && (_returnCode < 500);
1354+
1355+
} else if ((headerSeparator = headerLine.indexOf(':')) > 0) {
13531356
String headerName = headerLine.substring(0, headerSeparator);
13541357
String headerValue = headerLine.substring(headerSeparator + 1);
13551358
headerValue.trim();

0 commit comments

Comments
 (0)