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

ESP8266HTTPUpdate: Get available firmware version from update server (#8968)

* added getAvailableVersion(), moved _httpClientTimeout and _followRedirects to protected, added enum HTTPUpdateError

* auto numbering of HTTPUpdateError enum

* added getAvailableVersion(), debug output current current Sketch MD5

* updated advanced updater php script

* switch case indention corrected

* Revert "added getAvailableVersion(), debug output current current Sketch MD5"

This reverts commit 60d2c7762e7fb1fed7fae37fa99be149e12f125c.

* Revert "auto numbering of HTTPUpdateError enum"

This reverts commit 61785b27da3f2d42f8f95316d78ce22e5b00103a.

* Revert "added getAvailableVersion(), moved _httpClientTimeout and _followRedirects to protected, added enum HTTPUpdateError"

This reverts commit cec84ed17ab149d3e48082293f9e2723246b7d0b.

* corrected incorrect merge with master
This commit is contained in:
Holger Müller 2023-11-05 00:01:49 +01:00 committed by GitHub
parent 30c6df4639
commit fb8d6d668d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 188 additions and 45 deletions

View File

@ -592,34 +592,42 @@ With this information the script now can check if an update is needed. It is als
<?PHP
header('Content-type: text/plain; charset=utf8', true);
function check_header($name, $value = false) {
if(!isset($_SERVER[$name])) {
global $headers;
if (!isset($headers[$name])) {
return false;
}
if($value && $_SERVER[$name] != $value) {
if ($value && $headers[$name] != $value) {
return false;
}
return true;
}
function sendFile($path) {
function sendFile($path, $version) {
header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
header('Content-Type: application/octet-stream', true);
header('Content-Disposition: attachment; filename='.basename($path));
header('Content-Length: '.filesize($path), true);
header('x-MD5: '.md5_file($path), true);
header('x-version: '.$version, true);
readfile($path);
}
if(!check_header('User-Agent', 'ESP8266-http-Update')) {
$headers = getallheaders();
header('Content-type: text/plain; charset=utf8', true);
//if (!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
if (!check_header('User-Agent', 'ESP8266-http-Update')) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "only for ESP8266 updater!\n";
echo "Only for ESP8266 updater!\n";
echo "User-Agent: ".$headers['User-Agent']." != ESP8266-http-Update\n";
exit();
}
if(
if (
!check_header('x-ESP8266-mode') ||
!check_header('x-ESP8266-STA-MAC') ||
!check_header('x-ESP8266-AP-MAC') ||
!check_header('x-ESP8266-free-space') ||
@ -629,32 +637,54 @@ With this information the script now can check if an update is needed. It is als
!check_header('x-ESP8266-sdk-version')
) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "only for ESP8266 updater! (header)\n";
echo "Only for ESP8266 updater! (header missing)\n";
exit();
}
$db = array(
"18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
"18:FE:AA:AA:AA:BB" => "TEMP-1.0.0"
);
$db_string = '{
"18:FE:AA:AA:AA:AA": {"file": "DOOR-7-g14f53a19.bin", "version": 1},
"18:FE:AA:AA:AA:BB": {"file": "TEMP-1.0.0".bin", "version": 1}}';
// $db_string = file_get_contents("arduino-db.json");
$db = json_decode($db_string, true);
$mode = $headers['x-ESP8266-mode'];
$mac = $headers['x-ESP8266-STA-MAC'];
if(!isset($db[$_SERVER['x-ESP8266-STA-MAC']])) {
header($_SERVER["SERVER_PROTOCOL"].' 500 ESP MAC not configured for updates', true, 500);
if (!isset($db[$mac])) {
header($_SERVER["SERVER_PROTOCOL"].' 404 ESP MAC not configured for updates', true, 404);
echo "MAC ".$mac." not configured for updates\n";
exit();
}
$localBinary = "./bin/".$db[$_SERVER['x-ESP8266-STA-MAC']].".bin";
$localBinary = $db[$mac]['file'];
$localVersion = $db[$mac]['version'];
// Check if version has been set and does not match, if not, check if
// MD5 hash between local binary and ESP8266 binary do not match if not.
// then no update has been found.
if((!check_header('x-ESP8266-sdk-version') && $db[$_SERVER['x-ESP8266-STA-MAC']] != $_SERVER['x-ESP8266-version'])
|| $_SERVER["x-ESP8266-sketch-md5"] != md5_file($localBinary)) {
sendFile($localBinary);
if (!is_readable($localBinary)) {
header($_SERVER["SERVER_PROTOCOL"].' 404 File not found', true, 404);
echo "File ".$localBinary." not found\n";
exit();
}
if ($mode == 'sketch') {
// Check if version has been set and does not match, if not, check if
// MD5 hash between local binary and ESP8266 binary do not match if not.
// then no update has been found.
if ((check_header('x-ESP8266-version') && $headers['x-ESP8266-version'] != $localVersion)) {
// || $headers["x-ESP8266-sketch-md5"] != md5_file($localBinary)) {
sendFile($localBinary, $localVersion);
} else {
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
echo "File ".$localBinary." not modified\n";
}
} else if ($mode == 'version') {
header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
header('x-MD5: '.md5_file($localBinary), true);
header('x-version: '.$localVersion, true);
} else {
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
header($_SERVER["SERVER_PROTOCOL"].' 404 Mode not supported', true, 404);
echo "mode: ".$mode." not supported\n";
exit();
}
header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true, 500);
?>
Stream Interface
----------------

View File

@ -235,6 +235,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
DEBUG_HTTP_UPDATE("[httpUpdate] ESP8266 info:\n");
DEBUG_HTTP_UPDATE("[httpUpdate] - free Space: %d\n", ESP.getFreeSketchSpace());
DEBUG_HTTP_UPDATE("[httpUpdate] - current Sketch Size: %d\n", ESP.getSketchSize());
DEBUG_HTTP_UPDATE("[httpUpdate] - current Sketch MD5: %s\n", ESP.getSketchMD5().c_str());
if(currentVersion && currentVersion[0] != 0x00) {
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", currentVersion.c_str() );
@ -440,6 +441,115 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, const String& md5,
return true;
}
/**
* @brief Get avialable firmware version from update server
* @author Holger Mueller
* @date 2023-08-03
*
* @param client WiFiClient to use (see HTTPClient::begin)
* @param host Update host name or IP (see HTTPClient::begin)
* @param port Port on host (see HTTPClient::begin)
* @param uri Update URI on server (see HTTPClient::begin)
* @param current_version Current firmware version
* @param available_version Firmware version available on update server
* @return ESP8266HTTPUpdate::HTTPUpdateResult, HTTP_UPDATE_OK in case of success
*/
HTTPUpdateResult ESP8266HTTPUpdate::getAvailableVersion(WiFiClient& client, const String& host, uint16_t port, const String& uri, const String& current_version, String& available_version) {
HTTPUpdateResult ret = HTTP_UPDATE_FAILED;
HTTPClient http;
http.begin(client, host, port, uri);
// 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-Chip-ID"), String(ESP.getChipId()));
http.addHeader(F("x-ESP8266-STA-MAC"), WiFi.macAddress());
http.addHeader(F("x-ESP8266-AP-MAC"), WiFi.softAPmacAddress());
http.addHeader(F("x-ESP8266-free-space"), String(ESP.getFreeSketchSpace()));
http.addHeader(F("x-ESP8266-sketch-size"), String(ESP.getSketchSize()));
http.addHeader(F("x-ESP8266-sketch-md5"), String(ESP.getSketchMD5()));
http.addHeader(F("x-ESP8266-chip-size"), String(ESP.getFlashChipRealSize()));
http.addHeader(F("x-ESP8266-sdk-version"), ESP.getSdkVersion());
http.addHeader(F("x-ESP8266-mode"), F("version"));
if (current_version && current_version[0] != 0x00) {
http.addHeader(F("x-ESP8266-version"), current_version);
}
if (!_user.isEmpty() && !_password.isEmpty()) {
http.setAuthorization(_user.c_str(), _password.c_str());
}
if (!_auth.isEmpty()) {
http.setAuthorization(_auth.c_str());
}
const char* headerkeys[] = {"x-MD5", "x-version"};
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*);
// track these headers
http.collectHeaders(headerkeys, headerkeyssize);
int code = http.GET();
if (code <= 0) {
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str());
_setLastError(code);
http.end();
return HTTP_UPDATE_FAILED;
}
DEBUG_HTTP_UPDATE("[httpUpdate] Header read fin.\n");
DEBUG_HTTP_UPDATE("[httpUpdate] Server header:\n");
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
DEBUG_HTTP_UPDATE("[httpUpdate] - len: %d\n", http.getSize());
if (code != HTTP_CODE_OK) {
DEBUG_HTTP_UPDATE("[httpUpdate] - payload: %s\n", http.getString().c_str());
}
switch (code) {
case HTTP_CODE_OK: ///< OK (check for version)
if (http.hasHeader("x-version")) {
available_version = http.header("x-version");
ret = HTTP_UPDATE_OK;
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", current_version.c_str());
DEBUG_HTTP_UPDATE("[httpUpdate] - server version: %s\n", available_version.c_str());
} else {
_setLastError(HTTP_UE_SERVER_NOT_REPORT_VERSION);
ret = HTTP_UPDATE_FAILED;
DEBUG_HTTP_UPDATE("[httpUpdate] Server did not respond with a firmware version\n");
}
if (http.hasHeader("x-MD5")) {
DEBUG_HTTP_UPDATE("[httpUpdate] - current Sketch MD5: %s\n", ESP.getSketchMD5().c_str());
DEBUG_HTTP_UPDATE("[httpUpdate] - server Sketch MD5: %s\n", http.header("x-MD5").c_str());
}
break;
case HTTP_CODE_NOT_FOUND:
_setLastError(HTTP_UE_SERVER_FILE_NOT_FOUND);
ret = HTTP_UPDATE_FAILED;
break;
case HTTP_CODE_FORBIDDEN:
_setLastError(HTTP_UE_SERVER_FORBIDDEN);
ret = HTTP_UPDATE_FAILED;
break;
case HTTP_CODE_UNAUTHORIZED:
_setLastError(HTTP_UE_SERVER_UNAUTHORIZED);
ret = HTTP_UPDATE_FAILED;
break;
default:
_setLastError(HTTP_UE_SERVER_WRONG_HTTP_CODE);
ret = HTTP_UPDATE_FAILED;
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code);
break;
}
http.end();
return ret;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
ESP8266HTTPUpdate ESPhttpUpdate;
#endif

View File

@ -43,16 +43,18 @@
#endif
/// note we use HTTP client errors too so we start at 100
//TODO - in v3.0.0 make this an enum
constexpr int HTTP_UE_TOO_LESS_SPACE = (-100);
constexpr int HTTP_UE_SERVER_NOT_REPORT_SIZE = (-101);
constexpr int HTTP_UE_SERVER_FILE_NOT_FOUND = (-102);
constexpr int HTTP_UE_SERVER_FORBIDDEN = (-103);
constexpr int HTTP_UE_SERVER_WRONG_HTTP_CODE = (-104);
constexpr int HTTP_UE_SERVER_FAULTY_MD5 = (-105);
constexpr int HTTP_UE_BIN_VERIFY_HEADER_FAILED = (-106);
constexpr int HTTP_UE_BIN_FOR_WRONG_FLASH = (-107);
constexpr int HTTP_UE_SERVER_UNAUTHORIZED = (-108);
enum HTTPUpdateError {
HTTP_UE_SERVER_NOT_REPORT_VERSION = -109, // server did not respond with a firmware version
HTTP_UE_SERVER_UNAUTHORIZED, // -108
HTTP_UE_BIN_FOR_WRONG_FLASH, // -107
HTTP_UE_BIN_VERIFY_HEADER_FAILED, // -106
HTTP_UE_SERVER_FAULTY_MD5, // -105
HTTP_UE_SERVER_WRONG_HTTP_CODE, // -104
HTTP_UE_SERVER_FORBIDDEN, // -103
HTTP_UE_SERVER_FILE_NOT_FOUND, // -102
HTTP_UE_SERVER_NOT_REPORT_SIZE, // -101
HTTP_UE_TOO_LESS_SPACE // -100
};
enum HTTPUpdateResult {
HTTP_UPDATE_FAILED,
@ -123,6 +125,8 @@ public:
t_httpUpdate_return update(HTTPClient& httpClient, const String& currentVersion = "");
t_httpUpdate_return updateFS(HTTPClient& httpClient, const String& currentVersion = "");
t_httpUpdate_return getAvailableVersion(WiFiClient& client, const String& host, uint16_t port, const String& uri, const String& current_version, String& available_version);
// Notification callbacks
void onStart(HTTPUpdateStartCB cbOnStart) { _cbStart = cbOnStart; }
void onEnd(HTTPUpdateEndCB cbOnEnd) { _cbEnd = cbOnEnd; }
@ -153,10 +157,9 @@ protected:
String _password;
String _auth;
String _md5Sum;
private:
int _httpClientTimeout;
followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
private:
// Callbacks
HTTPUpdateStartCB _cbStart;
HTTPUpdateEndCB _cbEnd;