Skip to content

optionally allow redirects on HTTPClient & OTA updates #5009

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

Merged
merged 53 commits into from
Mar 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
02438bf
optionally allow redirects on http OTA updates
liebman Aug 5, 2018
f7c01aa
Merge branch 'master' into feature/http_update_follow_redirects
liebman Aug 15, 2018
3a078f6
Merge branch 'master' into feature/http_update_follow_redirects
liebman Aug 22, 2018
7d4db69
Merge branch 'master' into feature/http_update_follow_redirects
liebman Sep 29, 2018
8721924
Refactored HTTPClient::begin(url...) & setURL functions, now only beg…
liebman Sep 29, 2018
a552dbd
fix indentation for style check
liebman Sep 30, 2018
ac453c3
add space after while for style check
liebman Sep 30, 2018
65310f9
Merge remote-tracking branch 'origin/master' into feature/http_update…
liebman Nov 1, 2018
686ae07
don't use deprecated begin method in redirect example
liebman Nov 1, 2018
4e62aec
moved redirect handling code to HTTPClient.
liebman Nov 4, 2018
adab162
Merge branch 'master' into feature/http_update_follow_redirects
liebman Nov 5, 2018
91bdf81
Merge branch 'master' into feature/http_update_follow_redirects
liebman Nov 7, 2018
ca8c891
added support for POST/303 redirect
liebman Nov 8, 2018
12f7ad7
add missing getLocation() implementation
liebman Nov 8, 2018
1dc0c83
Merge branch 'master' into feature/http_update_follow_redirects
liebman Nov 8, 2018
deb7ac3
Merge branch 'master' into feature/http_update_follow_redirects
liebman Nov 8, 2018
eb3e3e8
Merge branch 'master' into feature/http_update_follow_redirects
liebman Nov 13, 2018
5199ef9
Merge branch 'master' into feature/http_update_follow_redirects
liebman Nov 27, 2018
3c81567
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 5, 2018
8fdfa52
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 5, 2018
99f2b9a
Merge branch 'feature/http_update_follow_redirects' of github.com:lie…
liebman Dec 5, 2018
0aafb71
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 6, 2018
94a448e
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 6, 2018
78629b0
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 8, 2018
3cef864
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 9, 2018
497857a
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 9, 2018
077eb5a
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 11, 2018
7432a57
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 14, 2018
9c0e431
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 15, 2018
7e5ea6c
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 15, 2018
0a8f23d
Merge branch 'master' into feature/http_update_follow_redirects
liebman Dec 16, 2018
c34807a
Merge branch 'master' into feature/http_update_follow_redirects
liebman Jan 8, 2019
f022a61
Merge branch 'master' into feature/http_update_follow_redirects
liebman Jan 16, 2019
b65433c
Merge branch 'master' into feature/http_update_follow_redirects
liebman Jan 19, 2019
4ef1450
Merge branch 'master' into feature/http_update_follow_redirects
liebman Jan 20, 2019
18016eb
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 3, 2019
7870245
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 3, 2019
e9a2c23
if the new location is only a path then only update the URI
liebman Feb 3, 2019
feebd7f
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 6, 2019
f7e0d3f
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 7, 2019
0b4cdbf
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 8, 2019
5b4a184
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 11, 2019
dc11d31
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 14, 2019
8521153
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 17, 2019
06d4434
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 18, 2019
edb75e5
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 22, 2019
1032ab3
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 22, 2019
d3643d0
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 23, 2019
03a2cfa
Merge branch 'master' into feature/http_update_follow_redirects
liebman Feb 26, 2019
b959a48
Merge branch 'master' into feature/http_update_follow_redirects
liebman Mar 3, 2019
fdc2b22
Merge branch 'master' into feature/http_update_follow_redirects
liebman Mar 9, 2019
766810d
Merge branch 'master' into feature/http_update_follow_redirects
earlephilhower Mar 12, 2019
4988824
Merge branch 'master' into feature/http_update_follow_redirects
d-a-v Mar 12, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 136 additions & 22 deletions libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ void HTTPClient::clear()
_size = -1;
_headers = "";
_payload.reset();
_location = "";
}


Expand Down Expand Up @@ -217,7 +218,6 @@ bool HTTPClient::begin(String url, String httpsFingerprint)
end();
}

_port = 443;
if (httpsFingerprint.length() == 0) {
return false;
}
Expand All @@ -238,7 +238,6 @@ bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
end();
}

_port = 443;
if (!beginInternal(url, "https")) {
return false;
}
Expand All @@ -264,7 +263,6 @@ bool HTTPClient::begin(String url)
end();
}

_port = 80;
if (!beginInternal(url, "http")) {
return false;
}
Expand All @@ -288,6 +286,17 @@ bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
_protocol = url.substring(0, index);
url.remove(0, (index + 3)); // remove http:// or https://

if (_protocol == "http") {
// set default port for 'http'
_port = 80;
} else if (_protocol == "https") {
// set default port for 'https'
_port = 443;
} else {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] unsupported protocol: %s\n", _protocol.c_str());
return false;
}

index = url.indexOf('/');
String host = url.substring(0, index);
url.remove(0, index); // remove host part
Expand All @@ -312,7 +321,7 @@ bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
}
_uri = url;

if (_protocol != expectedProtocol) {
if ( expectedProtocol != nullptr && _protocol != expectedProtocol) {
DEBUG_HTTPCLIENT("[HTTP-Client][begin] unexpected protocol: %s, expected %s\n", _protocol.c_str(), expectedProtocol);
return false;
}
Expand Down Expand Up @@ -402,13 +411,14 @@ void HTTPClient::end(void)
{
disconnect();
clear();
_redirectCount = 0;
}

/**
* disconnect
* close the TCP socket
*/
void HTTPClient::disconnect()
void HTTPClient::disconnect(bool preserveClient)
{
if(connected()) {
if(_client->available() > 0) {
Expand All @@ -424,7 +434,9 @@ void HTTPClient::disconnect()
DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop\n");
if(_client) {
_client->stop();
_client = nullptr;
if (!preserveClient) {
_client = nullptr;
}
}
#if HTTPCLIENT_1_1_COMPATIBLE
if(_tcpDeprecated) {
Expand Down Expand Up @@ -507,6 +519,43 @@ void HTTPClient::setTimeout(uint16_t timeout)
}
}

/**
* set the URL to a new value. Handy for following redirects.
* @param url
*/
bool HTTPClient::setURL(String url)
{
// if the new location is only a path then only update the URI
if (_location.startsWith("/")) {
_uri = _location;
clear();
return true;
}

if (!url.startsWith(_protocol + ":")) {
DEBUG_HTTPCLIENT("[HTTP-Client][setURL] new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str());
return false;
}
// disconnect but preserve _client
disconnect(true);
clear();
return beginInternal(url, nullptr);
}

/**
* set true to follow redirects.
* @param follow
*/
void HTTPClient::setFollowRedirects(bool follow)
{
_followRedirects = follow;
}

void HTTPClient::setRedirectLimit(uint16_t limit)
{
_redirectLimit = limit;
}

/**
* use HTTP1.0
* @param timeout
Expand Down Expand Up @@ -589,29 +638,82 @@ int HTTPClient::sendRequest(const char * type, String payload)
*/
int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size)
{
// connect to server
if(!connect()) {
return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
}
bool redirect = false;
int code = 0;
do {
// wipe out any existing headers from previous request
for(size_t i = 0; i < _headerKeysCount; i++) {
if (_currentHeaders[i].value.length() > 0) {
_currentHeaders[i].value = "";
}
}

if(payload && size > 0) {
addHeader(F("Content-Length"), String(size));
}
redirect = false;
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] type: '%s' redirCount: %d\n", type, _redirectCount);

// send Header
if(!sendHeader(type)) {
return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
}
// connect to server
if(!connect()) {
return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
}

// send Payload if needed
if(payload && size > 0) {
if(_client->write(&payload[0], size) != size) {
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
if(payload && size > 0) {
addHeader(F("Content-Length"), String(size));
}

// send Header
if(!sendHeader(type)) {
return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
}

// send Payload if needed
if(payload && size > 0) {
if(_client->write(&payload[0], size) != size) {
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
}
}

// handle Server Response (Header)
code = handleHeaderResponse();

//
// We can follow redirects for 301/302/307 for GET and HEAD requests and
// and we have not exceeded the redirect limit preventing an infinite
// redirect loop.
//
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
//
if (_followRedirects &&
(_redirectCount < _redirectLimit) &&
(_location.length() > 0) &&
(code == 301 || code == 302 || code == 307) &&
(!strcmp(type, "GET") || !strcmp(type, "HEAD"))
) {
_redirectCount += 1; // increment the count for redirect.
redirect = true;
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect:: '%s' redirCount: %d\n", _location.c_str(), _redirectCount);
if (!setURL(_location)) {
// return the redirect instead of handling on failure of setURL()
redirect = false;
}
}

} while (redirect);

// handle 303 redirect for non GET/HEAD by changing to GET and requesting new url
if (_followRedirects &&
(_redirectCount < _redirectLimit) &&
(_location.length() > 0) &&
(code == 303) &&
strcmp(type, "GET") && strcmp(type, "HEAD")
) {
_redirectCount += 1;
if (setURL(_location)) {
code = sendRequest("GET");
}
}

// handle Server Response (Header)
return returnError(handleHeaderResponse());
return returnError(code);
}

/**
Expand Down Expand Up @@ -762,6 +864,14 @@ int HTTPClient::getSize(void)
return _size;
}

/**
* Location if redirect
*/
const String& HTTPClient::getLocation(void)
{
return _location;
}

/**
* returns the stream of the tcp connection
* @return WiFiClient
Expand Down Expand Up @@ -1173,6 +1283,10 @@ int HTTPClient::handleHeaderResponse()
transferEncoding = headerValue;
}

if(headerName.equalsIgnoreCase("Location")) {
_location = headerValue;
}

for(size_t i = 0; i < _headerKeysCount; i++) {
if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
if (_currentHeaders[i].value != "") {
Expand Down
12 changes: 9 additions & 3 deletions libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ class HTTPClient
void setAuthorization(const char * user, const char * password);
void setAuthorization(const char * auth);
void setTimeout(uint16_t timeout);

void setFollowRedirects(bool follow);
void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request
bool setURL(String url); // handy for handling redirects
void useHTTP10(bool usehttp10 = true);

/// request handling
Expand All @@ -200,12 +202,12 @@ class HTTPClient


int getSize(void);
const String& getLocation(void); // Location header from redirect if 3XX

WiFiClient& getStream(void);
WiFiClient* getStreamPtr(void);
int writeToStream(Stream* stream);
const String& getString(void);

static String errorToString(int error);

protected:
Expand All @@ -215,7 +217,7 @@ class HTTPClient
};

bool beginInternal(String url, const char* expectedProtocol);
void disconnect();
void disconnect(bool preserveClient = false);
void clear();
int returnError(int error);
bool connect(void);
Expand Down Expand Up @@ -250,6 +252,10 @@ class HTTPClient
int _returnCode = 0;
int _size = -1;
bool _canReuse = false;
bool _followRedirects = false;
uint16_t _redirectCount = 0;
uint16_t _redirectLimit = 10;
String _location;
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;
std::unique_ptr<StreamString> _payload;
};
Expand Down
5 changes: 3 additions & 2 deletions libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ extern "C" uint32_t _SPIFFS_start;
extern "C" uint32_t _SPIFFS_end;

ESP8266HTTPUpdate::ESP8266HTTPUpdate(void)
: _httpClientTimeout(8000), _ledPin(-1)
: _httpClientTimeout(8000), _followRedirects(false), _ledPin(-1)
{
}

ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout)
: _httpClientTimeout(httpClientTimeout), _ledPin(-1)
: _httpClientTimeout(httpClientTimeout), _followRedirects(false), _ledPin(-1)
{
}

Expand Down Expand Up @@ -261,6 +261,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
// use HTTP/1.0 for update since the update handler not support any transfer Encoding
http.useHTTP10(true);
http.setTimeout(_httpClientTimeout);
http.setFollowRedirects(_followRedirects);
http.setUserAgent(F("ESP8266-http-Update"));
http.addHeader(F("x-ESP8266-STA-MAC"), WiFi.macAddress());
http.addHeader(F("x-ESP8266-AP-MAC"), WiFi.softAPmacAddress());
Expand Down
6 changes: 6 additions & 0 deletions libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class ESP8266HTTPUpdate
_rebootOnUpdate = reboot;
}

void followRedirects(bool follow)
{
_followRedirects = follow;
}

void setLedPin(int ledPin = -1, uint8_t ledOn = HIGH)
{
_ledPin = ledPin;
Expand Down Expand Up @@ -129,6 +134,7 @@ class ESP8266HTTPUpdate
bool _rebootOnUpdate = true;
private:
int _httpClientTimeout;
bool _followRedirects;

int _ledPin;
uint8_t _ledOn;
Expand Down
Loading