Update OTA - Get request doesn't parse content-length

Hi folks.

I'm trying to do an update OTA using the ArduinoOTA library with this example but it always give me the error "Server didn't provide Content-length header. Can't continue with update.".

However If I make the request via postman, to my webserver, I can see that the content length is there. I also printed the get response to the serial console I also can see it there.

Response:

cache-control: max-age=0, private, must-revalidate
connection: close
content-length: 19332
cross-origin-window-policy: deny
date: Mon, 17 May 2021 21:49:13 GMT
server: Cowboy
x-content-type-options: nosniff
x-download-options: noopen
x-frame-options: SAMEORIGIN
x-permitted-cross-domain-policies: none
x-request-id: Fn_4_EDKq7h4hbQAAAEj
x-xss-protection: 1; mode=block

⸮ ⸮⸮⸮⸮Aa⸮L#x+a⸮K+⸮H⸮⸮##p⸮\ ⸮⸮K+⸮aHI⸮⸮aHh+⸮K+ИG⸮⸮F⸮` X JKx)	⸮Ix	xAɲp⸮ I⸮⸮ax1ɲpx⸮)⸮x	)	⸮Ix@B⸮⸮px	xAɲpxex⸮Bр"K⸮⸮apGx   DA⸮⸮i⸮a⸮⸮h$⸮C`⸮i#B⸮⸮h#C`h⸮a⸮⸮⸮i#B⸮⸮⸮i⸮@B⸮⸮KC`⸮iZa⸮⸮⸮#⸮C`⸮⸮⸮i⸮a⸮⸮h"C`⸮@~⸮a⸮⸮⸮pG~#Qa⸮⸮B⸮Ba⸮B⸮⸮@B⸮B⸮⸮B⸮K"p⸮⸮⸮pG⸮Fy p⸮h⸮⸮!⸮2B&Ѐ ⸮⸮⸮r#Sp@!K⸮qPq^hM⸮ .@⸮C^`^i5@(CXaH`Ha]hH(@⸮%⸮(CX`Xh⸮⸮X`#Qq#q⸮z⸮⸮ ⸮⸮⸮ yp⸮⸮ ⸮⸮⸮⸮⸮  ⸮?⸮#qCqK`⸮`x"CppG⸮F⸮8⸮6K !⸮i 
// it continues 

This is the sketch I'm using:

#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoHttpClient.h>
#include <ArduinoOTA.h>


///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;     // the Wifi radio's status

const short VERSION = 1;

WiFiClient wifi;

void setup() {

  //Initialize serial and wait for port to open:

  Serial.begin(9600);

  while (!Serial) {

    ; // wait for serial port to connect. Needed for native USB port only

  }

  // check for the WiFi module:

  if (WiFi.status() == WL_NO_MODULE) {

    Serial.println("Communication with WiFi module failed!");

    // don't continue

    while (true);

  }

  String fv = WiFi.firmwareVersion();

  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {

    Serial.println("Please upgrade the firmware");

  }

  // attempt to connect to Wifi network:

  while (status != WL_CONNECTED) {

    Serial.print("Attempting to connect to WPA SSID: ");

    Serial.println(ssid);

    // Connect to WPA/WPA2 network:

    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:

    delay(10000);

  }

  // you're connected now, so print out the data:

  Serial.print("You're connected to the network");

  printCurrentNet();

  printWifiData();

}

void loop() {

  // check the network connection once every 10 seconds:
  
  Serial.println("strating upload OTA!");
  handleSketchDownload();

  delay(5000);

  printCurrentNet();
}

void printWifiData() {

  // print your board's IP address:

  IPAddress ip = WiFi.localIP();

  Serial.print("IP Address: ");

  Serial.println(ip);

  Serial.println(ip);

  // print your MAC address:

  byte mac[6];

  WiFi.macAddress(mac);

  Serial.print("MAC address: ");

  printMacAddress(mac);
}

void printCurrentNet() {

  // print the SSID of the network you're attached to:

  Serial.print("SSID: ");

  Serial.println(WiFi.SSID());

  // print the MAC address of the router you're attached to:

  byte bssid[6];

  WiFi.BSSID(bssid);

  Serial.print("BSSID: ");

  printMacAddress(bssid);

  // print the received signal strength:

  long rssi = WiFi.RSSI();

  Serial.print("signal strength (RSSI):");

  Serial.println(rssi);

  // print the encryption type:

  byte encryption = WiFi.encryptionType();

  Serial.print("Encryption Type:");

  Serial.println(encryption, HEX);

  Serial.println();
}

void printMacAddress(byte mac[]) {

  for (int i = 5; i >= 0; i--) {

    if (mac[i] < 16) {

      Serial.print("0");

    }

    Serial.print(mac[i], HEX);

    if (i > 0) {

      Serial.print(":");

    }

  }

  Serial.println();
}

void handleSketchDownload() {
  const char* SERVER = "192.168.1.84";  // Set your correct hostname
  const unsigned short SERVER_PORT = 4000;     // Commonly 80 (HTTP) | 443 (HTTPS)
  const char* PATH = "/files";       // Set the URI to the .bin firmware
  const unsigned long CHECK_INTERVAL = 6000;  // Time interval between update checks (ms)

  // Time interval check
  static unsigned long previousMillis;
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis < CHECK_INTERVAL)
    return;
  previousMillis = currentMillis;

  // HttpClient client(wifiClient, SERVER, SERVER_PORT);  // HTTP
  HttpClient client(wifi, SERVER, SERVER_PORT);  // HTTPS

  char buff[32];
  snprintf(buff, sizeof(buff), PATH, VERSION + 1);

  Serial.print("Check for update file ");
  Serial.println(buff);

  // Make the GET request
  client.get(buff);

  int statusCode = client.responseStatusCode();
  Serial.print("Update status code: ");
  Serial.println(statusCode);
  
  if (statusCode != 200) {
    client.stop();
    return;
  }

  long length = client.contentLength();
  if (length == HttpClient::kNoContentLengthHeader) {
    client.stop();
    Serial.println("Server didn't provide Content-length header. Can't continue with update.");
    return;
  }
  Serial.print("Server returned update file of size ");
  Serial.print(length);
  Serial.println(" bytes");

  if (!InternalStorage.open(length)) {
    client.stop();
    Serial.println("There is not enough space to store the update. Can't continue with update.");
    return;
  }
  byte b;
  while (length > 0) {
    if (!client.readBytes(&b, 1)) // reading a byte with timeout
      break;
    InternalStorage.write(b);
    length--;
  }
  InternalStorage.close();
  client.stop();
  if (length > 0) {
    Serial.print("Timeout downloading update file at ");
    Serial.print(length);
    Serial.println(" bytes. Can't continue with update.");
    return;
  }

  Serial.println("Sketch update apply and reset.");
  Serial.flush();
  InternalStorage.apply(); // this doesn't return
}

Any pointers on how to solve this?

Note: I tried other endpoints and the result was the same

Thanks

the ArduinoHttpClient library is not a good one. it expects exact case in header name so it searches for "Content-Length"

What library do you recommend?

sorry, If I knew a better simple library for download, I would use it in the example.
(you know that I am the author of the ArduinoOTA library?)

Ohh sorry I didn't notice!

In the meantime I changed the ArduinoHttpClient library to accept the lower case "content-length" and it worked.

I will try to make a pull request to them to fix that issue.

Thank you for the awesome library :slight_smile: