[SOLVED] ESP8266 crash at if (HTTPCode > 0) {}

Hello fellow programmers!

I am having trouble with my ESP, it seems to be crashing at an odd place.

I am using this function (I cut out some of the code, a lot of it is not relevant):

#include <ESP8266HTTPClient.h> // At the top of the project

String CollectExternalResponse(String URL) {
  WiFiClient client;
    
  HTTPClient HTTP;

  HTTP.begin(URL);
  int HTTPCode = HTTP.GET();

  Serial.println("A");
  String Response = "";
  Serial.println("B");

  if (HTTPCode > 0) {
    Serial.println("1");
    Response = HTTP.getString();
    Serial.println("2");
  }

  HTTP.end();
  return Response;
}

When I run it, the "A" and "B" print to the Serial monitor but "1" and "2" do not. The full output is this:

A
B

Exception (3):
epc1=0x40100621 epc2=0x00000000 epc3=0x00000000 excvaddr=0x40068648 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffd80 end: 3fffffc0 offset: 01a0
3fffff20:  4010000a 002a8400 3ffee75c 3ffee700  
3fffff30:  3fffdad0 00000000 00000020 401008cb  
3fffff40:  00001388 3ffee75c 00000000 00000000  
3fffff50:  3ffef800 0035003f 3fffff80 4020424a  
3fffff60:  3fffff8c 3fffff8c 3ffee6c0 40204260  
3fffff70:  3fffdad0 00000000 3ffee6c0 402012ad  
3fffff80:  3ffe8648 8000001c 00000000 3ffef76c  
3fffff90:  0035003f 00000000 3ffee6c0 402010f6  
3fffffa0:  feefeffe feefeffe feefeffe 402051a8  
3fffffb0:  feefeffe feefeffe 3ffe84e8 40100b8d  
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,0)

load 0x4010f000, len 1392, room 16 
tail 0
chksum 0xd0
csum 0xd0
v3d128e5c
~ld

Anyone know what is going on here? It seems odd that it would crash at this if statement, especially given the same function works when I do not pass the URL as a variable. Just to be clear, in another test, I printed the URL at the beginning of the function and it worked.

Here is the URL: https://blockchain.info/tobtc?currency=USD&value=1000

I would really appreciate some help!

"Anyone know what is going on here? It seems odd that it would crash at this if statement, especially given the same function works when I do not pass the URL as a variable. Just to be clear, in another test, I printed the URL at the beginning of the function and it worked. "

If you hard code the URL in in place of the URL variable, does it work? What format/type is the URL variable?

Exception 3 is a stack overflow. Most likely the call to HTTP.getString() is returning a gigantic string, which causing the error.

Your print statements do NOT necessarily indicate WHERE the problem is, because it takes a long time for the characters to actually be sent out the serial port. If you follow each Serial.print with a Serial.flush(), the characters will all be sent before the next line of code is executed. If you do that, I expect you will see the "1" come out, but not the "2", which will confirm what I wrote above.

Regards,
Ray L.

Response = HTTP.getString();As Ray says, if the code isn't '0' then you should not attempt to do that.

RayLivingston:
Exception 3 is a stack overflow. Most likely the call to HTTP.getString() is returning a gigantic string, which causing the error.

Your print statements do NOT necessarily indicate WHERE the problem is, because it takes a long time for the characters to actually be sent out the serial port. If you follow each Serial.print with a Serial.flush(), the characters will all be sent before the next line of code is executed. If you do that, I expect you will see the "1" come out, but not the "2", which will confirm what I wrote above.

Regards,
Ray L.

Good suggestion, but that your prediction did not quite match the results. When I added Serial.flush() after each print, a bunch of gibberish was printed as well. The first character is discernible, but anything else is hidden in the spam.

If you follow the link I posted in the original thread, it leads to the conversion rate for Bitcoin in USD. It should be returning something like 0.14789, not a gigantic string (unless it is sending things in a different format... perhaps json?).

zoomkat:
"Anyone know what is going on here? It seems odd that it would crash at this if statement, especially given the same function works when I do not pass the URL as a variable. Just to be clear, in another test, I printed the URL at the beginning of the function and it worked. "

If you hard code the URL in in place of the URL variable, does it work? What format/type is the URL variable?

It does not. I am sending the variable to the function as a String type. When I define it as const char*, as shown in the ESP examples and is functional on a server I made myself to return predictable strings, I receive the same error.

UPDATE:

I changed the URL to "http://worldtimeapi.org/api/ip/75.110.25.187.txt" and had a successful response from the server.

There are two observations I have about this:

  1. It uses http instead of https. I don't know if this makes a difference, but I will test it to see.

  2. The URL ends in .txt. Though the original claims to be in plain text, this may be significant.

UPDATE:

Since the api uses HTTPS, I needed to specify a fingerprint in the code:

HTTP.begin(URL, Fingerprint);

This did not solve the stack overflow problem, though.

Have you tried to download the URL with a browser and store it to a file and see how big that file is?

Deva_Rishi:

Response = HTTP.getString();

As Ray says, if the code isn't '0' then you should not attempt to do that.

All of the examples I've seen specify the code should be greater than 0. A positive response from http is 200...

Danois90:
Have you tried to download the URL with a browser and store it to a file and see how big that file is?

I just tried something similar. I made the same request with python and used a function to see that the response was 48 bytes.

Is this similar enough to what you suggested?

"1) It uses http instead of https. I don't know if this makes a difference, but I will test it to see."

As best as I know, there is a lot of extra stuff you have to do with https.

The HTTPClient has no valid WiFi client applied - look at this example.

SOLVED

Ok! The issue was with this particular API and its need for https. The solution should apply to any plaintext API using https:

You need to specify the SHA-1 fingerprint in the code:

http.begin(URL, SHA1Fingerprint);

It is important to use the SHA-1 fingerprint! When I first tried this, I used SHA-256 which did not solve the problem.

How do you get the SHA-1 fingerprint, you may wonder! Here is what to do on a Mac (specifically Safari):

  1. In Safari, click on the green lock next to the url.

  2. Click "Show Certificate"

  3. Click "Details"

  4. At the very bottom you will find your SHA-1 fingerprint

My only question at this point is whether the fingerprint will eventually need to be updated. Will it ever expire? Will this happen in a predictable time frame?

My code is dynamic, so I can specify the fingerprint from the outside, but will I need to check in every so often to update that data?

The fingerprint will expire with the certificate, expiration date is shown in the certificate. If you properly implement SSL/TLS in you application, you do not need to worry about this.