HTTPUpdateServer.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /**
  2. * Ported the ESP8266HTTPUpdateServer published by Arduino-core to
  3. * provide the web browser based OTA update on the ESP32 platform.
  4. * @file HTTPUpdateServer.cpp
  5. * @author hieromon@gmail.com
  6. * @version 0.9.10
  7. * @date 2019-06-06
  8. * @copyright MIT license.
  9. */
  10. #ifdef ARDUINO_ARCH_ESP32
  11. // This class will available only EPS32 actually.
  12. #include <Arduino.h>
  13. #include <WiFiClient.h>
  14. #include <WiFiServer.h>
  15. #include <WebServer.h>
  16. #include <WiFiUdp.h>
  17. #include <Update.h>
  18. #include "StreamString.h"
  19. #include "HTTPUpdateServer.h"
  20. static const char serverIndex[] PROGMEM = R"(
  21. <html><body>
  22. <form method='POST' action='' enctype='multipart/form-data'>
  23. <input type='file' name='update'>
  24. <input type='submit' value='Update'>
  25. </form>
  26. </body></html>
  27. )";
  28. static const char successResponse[] PROGMEM =
  29. "<meta http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...\n";
  30. /**
  31. * Setup for the web update. Register the authentication procedure and
  32. * binary file upload handler required to update the actual sketch binary by OTA.
  33. * @param server A pointer to the WebServer instance
  34. * @param path URI of the update handler
  35. * @param username Username for authentication
  36. * @arama password Password for authentication
  37. */
  38. void HTTPUpdateServer::setup(WebServer* server, const String& path, const String& username, const String& password) {
  39. _server = server;
  40. _username = username;
  41. _password = password;
  42. // handler for the /update form page
  43. _server->on(path.c_str(), HTTP_GET, [&] () {
  44. if (_username != _emptyString && _password != _emptyString && !_server->authenticate(_username.c_str(), _password.c_str()))
  45. return _server->requestAuthentication();
  46. _server->send_P(200, PSTR("text/html"), serverIndex);
  47. });
  48. // handler for the /update form POST (once file upload finishes)
  49. _server->on(path.c_str(), HTTP_POST, [&] () {
  50. if(!_authenticated)
  51. return _server->requestAuthentication();
  52. if (Update.hasError()) {
  53. _server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
  54. }
  55. else {
  56. _server->client().setNoDelay(true);
  57. _server->send_P(200, PSTR("text/html"), successResponse);
  58. delay(100);
  59. _server->client().stop();
  60. ESP.restart();
  61. }
  62. }, [&] () {
  63. // handler for the file upload, get's the sketch bytes, and writes
  64. // them through the Update object
  65. HTTPUpload& upload = _server->upload();
  66. if (upload.status == UPLOAD_FILE_START) {
  67. _updaterError = String();
  68. if (_serial_output)
  69. Serial.setDebugOutput(true);
  70. _authenticated = (_username == _emptyString || _password == _emptyString || _server->authenticate(_username.c_str(), _password.c_str()));
  71. if (!_authenticated) {
  72. if (_serial_output)
  73. Serial.println("Unauthenticated Update");
  74. return;
  75. }
  76. if (_serial_output)
  77. Serial.printf("Update: %s\n", upload.filename.c_str());
  78. uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
  79. if (!Update.begin(maxSketchSpace)) { //start with max available size
  80. _setUpdaterError();
  81. }
  82. }
  83. else if (_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()) {
  84. if (_serial_output)
  85. Serial.print('.');
  86. if (Update.write(upload.buf, upload.currentSize) != upload.currentSize)
  87. _setUpdaterError();
  88. }
  89. else if (_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()) {
  90. if (Update.end(true)) { //true to set the size to the current progress
  91. if (_serial_output)
  92. Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
  93. }
  94. else {
  95. _setUpdaterError();
  96. }
  97. if (_serial_output)
  98. Serial.setDebugOutput(false);
  99. }
  100. else if (_authenticated && upload.status == UPLOAD_FILE_ABORTED) {
  101. Update.end();
  102. if (_serial_output)
  103. Serial.println("Update was aborted");
  104. }
  105. delay(0);
  106. });
  107. }
  108. /**
  109. * Convert the update error code to string for notation.
  110. */
  111. void HTTPUpdateServer::_setUpdaterError() {
  112. if (_serial_output)
  113. Update.printError(Serial);
  114. StreamString str;
  115. Update.printError(str);
  116. _updaterError = str.c_str();
  117. }
  118. /**
  119. * Shared empty String instance
  120. */
  121. const String HTTPUpdateServer::_emptyString;
  122. #endif // !ARDUINO_ARCH_ESP32