Skip to content
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

[HELP] How to post an HTTP with headers? #3483

Closed
sarkrui opened this issue Nov 15, 2019 · 22 comments
Closed

[HELP] How to post an HTTP with headers? #3483

sarkrui opened this issue Nov 15, 2019 · 22 comments

Comments

@sarkrui
Copy link

sarkrui commented Nov 15, 2019

Hardware:

Board: Wemos Lolin32 Lite
Core Installation version: 1.0.4
IDE name: Arduino IDE
Flash Frequency: 80Mhz
PSRAM enabled: Unknown
Upload Speed: 115200
Computer OS: Mac OSX

Description:

I was able to POST a header-less HTTP request to Firebase Realtime Database, while I failed to post HTTP requests with headers (http code 403.) to an Entity Dataset powered by TU Eindhoven. The server side seems to work well as I was able to POST, GET, PUT via Insomnia. On my ESP32, the http.getString returns Access with api_token failed., which seems headers of the request were missing (it's confirmed from the server side that there were attempts of HTTP requests without headers, although I did include them in the code).

Sketch: (leave the backquotes for code formatting)

//Change the code below by your sketch
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h> //v6
const char* ssid     = "";
const char* password = "";
int sensor_0 = 1234;
int sensor_1 = 5678;
String postMessage;

void setup() {
void WPAConnect() {

  Serial.begin(115200);
  delay(500);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WPAPersonal Wi-Fi");
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(200);
  }
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();
}

void setup() {
  WPAConnect();
  curlRequest();
}
void curlRequest() {
  if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
    HTTPClient http;
    const int capacity = JSON_OBJECT_SIZE(2);
    StaticJsonDocument<capacity> doc;
    doc["sensor_0"] = sensor_0;
    doc["sensor_1"] = sensor_1;
    serializeJsonPretty(doc, postMessage);
    serializeJsonPretty(doc, Serial);
    http.begin("https://data.id.tue.nl/datasets/entity/145/item/"); //Specify destination for HTTP request
    http.addHeader("Content-Type", "application/json");
    http.addHeader("api_token",  "pMXFOLpinNq7EzrVQ/nXXLWl+96c9Dk+f8K2iVj+QoQqajaRQJYMeWObg2XYmcX1");
    http.addHeader("resource_id", "breathing_0");
    http.addHeader("token", "1234");
    // http.begin("https://tu-eindhoven-shared-projects.firebaseio.com/.json"); //Specify destination for HTTP request
    int httpCode = http.POST(postMessage);
    if (httpCode > 0) {
      Serial.println();
      Serial.println(httpCode);
      if (httpCode == 200) {
        Serial.println("Hooray!");
      }
    }
  }
}
void loop() {
}

Debug Messages:

{
  "sensor_0": 1234,
  "sensor_1": 5678
}Access with api_token failed.
403
@Jeroen88
Copy link
Contributor

Jeroen88 commented Nov 15, 2019

Your POST request is correct, including the way you add request headers, and your server sends a reasonable reply.

The problem is that you do not send what your server needs to fulfill the request.

There is nothing wrong with the ESP32 libraries, this is not an issue for here.

@sarkrui
Copy link
Author

sarkrui commented Nov 15, 2019

Hi @Jeroen88,

Thanks for the prompt response!
I thought I have fulfilled the server's requirement as I was able to POST via cURL and Insomnia and they both returned successful responses.

Any idea what might went wrong with my Arduino code? Thanks!

@Jeroen88
Copy link
Contributor

Well you should debug your own code :)

One thing I can think of is that the capacity of the json object is too small. You forget space for the string duplications (like "sensor_0"), see here

@Bmooij
Copy link
Contributor

Bmooij commented Nov 16, 2019

Could it be the problem that you are sending a https request without adding a certificate?

@sarkrui
Copy link
Author

sarkrui commented Nov 16, 2019

One thing I can think of is that the capacity of the json object is too small.

Hi @Jeroen88 , thanks for correcting me. Even though I have enlarged the capacity to JSON_OBJECT_SIZE(2) + 20 . It did not work still unfortunately. FYI, the serializeJsonPretty(doc, Serial); did work well, so this should not be problematic.

Hi @Bmooij , I tried including the rootCACertificate based on the BasicHTTPSClient example, no luck. I do really know if it's necessary to generate my own root Certificate as the one in the code below is from the example.

#include <ArduinoJson.h> //v6
const char* ssid     = "";
const char* password = "";
int sensor_0 = 1234;
int sensor_1 = 5678;
String postMessage;

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>

// This is GandiStandardSSLCA2.pem, the root Certificate Authority that signed
// the server certifcate for the demo server https://jigsaw.w3.org in this
// example. This certificate is valid until Sep 11 23:59:59 2024 GMT
const char* rootCACertificate = \
                                "-----BEGIN CERTIFICATE-----\n" \
                                "MIIF6TCCA9GgAwIBAgIQBeTcO5Q4qzuFl8umoZhQ4zANBgkqhkiG9w0BAQwFADCB\n" \
                                "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" \
                                "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" \
                                "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQw\n" \
                                "OTEyMDAwMDAwWhcNMjQwOTExMjM1OTU5WjBfMQswCQYDVQQGEwJGUjEOMAwGA1UE\n" \
                                "CBMFUGFyaXMxDjAMBgNVBAcTBVBhcmlzMQ4wDAYDVQQKEwVHYW5kaTEgMB4GA1UE\n" \
                                "AxMXR2FuZGkgU3RhbmRhcmQgU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" \
                                "DwAwggEKAoIBAQCUBC2meZV0/9UAPPWu2JSxKXzAjwsLibmCg5duNyj1ohrP0pIL\n" \
                                "m6jTh5RzhBCf3DXLwi2SrCG5yzv8QMHBgyHwv/j2nPqcghDA0I5O5Q1MsJFckLSk\n" \
                                "QFEW2uSEEi0FXKEfFxkkUap66uEHG4aNAXLy59SDIzme4OFMH2sio7QQZrDtgpbX\n" \
                                "bmq08j+1QvzdirWrui0dOnWbMdw+naxb00ENbLAb9Tr1eeohovj0M1JLJC0epJmx\n" \
                                "bUi8uBL+cnB89/sCdfSN3tbawKAyGlLfOGsuRTg/PwSWAP2h9KK71RfWJ3wbWFmV\n" \
                                "XooS/ZyrgT5SKEhRhWvzkbKGPym1bgNi7tYFAgMBAAGjggF1MIIBcTAfBgNVHSME\n" \
                                "GDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUs5Cn2MmvTs1hPJ98\n" \
                                "rV1/Qf1pMOowDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD\n" \
                                "VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGy\n" \
                                "MQECAhowCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl\n" \
                                "cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy\n" \
                                "bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy\n" \
                                "dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ\n" \
                                "aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAWGf9\n" \
                                "crJq13xhlhl+2UNG0SZ9yFP6ZrBrLafTqlb3OojQO3LJUP33WbKqaPWMcwO7lWUX\n" \
                                "zi8c3ZgTopHJ7qFAbjyY1lzzsiI8Le4bpOHeICQW8owRc5E69vrOJAKHypPstLbI\n" \
                                "FhfFcvwnQPYT/pOmnVHvPCvYd1ebjGU6NSU2t7WKY28HJ5OxYI2A25bUeo8tqxyI\n" \
                                "yW5+1mUfr13KFj8oRtygNeX56eXVlogMT8a3d2dIhCe2H7Bo26y/d7CQuKLJHDJd\n" \
                                "ArolQ4FCR7vY4Y8MDEZf7kYzawMUgtN+zY+vkNaOJH1AQrRqahfGlZfh8jjNp+20\n" \
                                "J0CT33KpuMZmYzc4ZCIwojvxuch7yPspOqsactIGEk72gtQjbz7Dk+XYtsDe3CMW\n" \
                                "1hMwt6CaDixVBgBwAc/qOR2A24j3pSC4W/0xJmmPLQphgzpHphNULB7j7UTKvGof\n" \
                                "KA5R2d4On3XNDgOVyvnFqSot/kGkoUeuDcL5OWYzSlvhhChZbH2UF3bkRYKtcCD9\n" \
                                "0m9jqNf6oDP6N8v3smWe2lBvP+Sn845dWDKXcCMu5/3EFZucJ48y7RetWIExKREa\n" \
                                "m9T8bJUox04FB6b9HbwZ4ui3uRGKLXASUoWNjDNKD/yZkuBjcNqllEdjB+dYxzFf\n" \
                                "BT02Vf6Dsuimrdfp5gJ0iHRc2jTbkNJtUQoj1iM=\n" \
                                "-----END CERTIFICATE-----\n";
void loop() {
  WiFiClientSecure *client = new WiFiClientSecure;
  if (client) {
    client -> setCACert(rootCACertificate);
    {
      // Add a scoping block for HTTPClient https to make sure it is destroyed before WiFiClientSecure *client is
      HTTPClient http;
      Serial.print("[HTTPS] begin...\n");
      curlRequest();
    }
    delete client;
  } else {
    Serial.println("Unable to create client");
  }
  Serial.println();
  Serial.println("Waiting 10s before the next round...");
  delay(5000);
}

@Bmooij
Copy link
Contributor

Bmooij commented Nov 16, 2019

You can't use the certificate from the example, because it referrers to https://jigsaw.w3.org.
You need to use the certificate from data.id.tue.nl.

Tutorial: https://techtutorialsx.com/2017/11/18/esp32-arduino-https-get-request/

You can try the following certificate:

const char* rootCACertificate = \
"-----BEGIN CERTIFICATE-----\n"
"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" \
"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" \
"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" \
"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" \
"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" \
"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" \
"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" \
"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" \
"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" \
"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" \
"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" \
"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" \
"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" \
"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" \
"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" \
"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" \
"-----END CERTIFICATE-----\n";

@Jeroen88
Copy link
Contributor

You can try https but I don't think it will solve the problem since the server did send a reply over http. The server would have dropped the connection earlier if it didn't accept http

@Jeroen88
Copy link
Contributor

Could you try

int httpCode = http.POST("");

Instead of your current POST?

@sarkrui
Copy link
Author

sarkrui commented Nov 16, 2019

You can't use the certificate from the example, because it referrers to https://jigsaw.w3.org.
You need to use the certificate from data.id.tue.nl.

Tutorial: https://techtutorialsx.com/2017/11/18/esp32-arduino-https-get-request/

You can try the following certificate:

@Bmooij Thanks for your suggestion. No luck so far. It still returns a 403 Access with api_token failed error.

int httpCode = http.POST("");

@Jeroen88 It still returned the same error.

@Bmooij
Copy link
Contributor

Bmooij commented Nov 16, 2019

The issue is in the library. The header token overrides the header api_token.
api_token is never send.

Try to reverse the order. First add the token and then the api_token:

http.addHeader("token", "1234");
http.addHeader("api_token", "pMXFOLpinNq7EzrVQ/nXXLWl+96c9Dk+f8K2iVj+QoQqajaRQJYMeWObg2XYmcX1");

@sarkrui
Copy link
Author

sarkrui commented Nov 16, 2019

@Bmooij You're definitely a genius! It works like a charm now. So, the api_token should be placed at the last line the addHeader section then? That's odd but glad that we now know what went wrong.

@Jeroen88
Copy link
Contributor

@Bmooij why do you think the header is never sent?

@Bmooij
Copy link
Contributor

Bmooij commented Nov 16, 2019

@Jeroen88 I know it because I added debug lines to the HTTPClient and printed the values that are send with the client.

I didn't go full into it (because it is weekend), but I expected the error around here:

int headerStart = _headers.indexOf(headerLine);

@Bmooij
Copy link
Contributor

Bmooij commented Nov 16, 2019

There are 2 possible options to workaround the issue:

Option 1: Change the order

http.addHeader("token", "1234");
http.addHeader("api_token", "pMXFOLpinNq7EzrVQ/nXXLWl+96c9Dk+f8K2iVj+QoQqajaRQJYMeWObg2XYmcX1");

Option 2: Set replace to false

http.addHeader("api_token", "pMXFOLpinNq7EzrVQ/nXXLWl+96c9Dk+f8K2iVj+QoQqajaRQJYMeWObg2XYmcX1");
http.addHeader("token", "1234", false, false); // set replace to false

@Bmooij
Copy link
Contributor

Bmooij commented Nov 16, 2019

@Jeroen88 It is definitely the indexOf.

String _headers = "api_token : pMXFOLpin...";
// add token header:
_headers.indexOf("token :") != -1

@Jeroen88
Copy link
Contributor

@Bmooij thnx, I may check it tomorrow and make a PR for it :)

@Jeroen88
Copy link
Contributor

@sarkrui by the way, you do not need arduino json for such simple usage. You may POST "{'sensor_0':1234', 'sensor_1':45678}" directly to the http client.

If the response from the server is also a json, it is more useful to parse the reply with arduino json.

@sarkrui
Copy link
Author

sarkrui commented Nov 17, 2019

@Jeroen88 Thanks for the information although that seems not working for me. Also, the sensor_x values are going to be read from analog pins. In that case, ArduinoJson should be necessary.

@Jeroen88
Copy link
Contributor

Jeroen88 commented Nov 17, 2019

@sarkrui I made a typo, maybe that is because it did not work. Even if you read from the pins, you can just construct the JSON yourself:

char buffer[20];
sprintf(buffer, "{\"sensor_0\": %d, \"sensor_1\": %d}", 1234, 5678);
http.POST(buffer);

Jeroen88 pushed a commit to Jeroen88/arduino-esp32 that referenced this issue Nov 17, 2019
@Jeroen88
Copy link
Contributor

I just made PR #3487 to fix the original problem

@sarkrui
Copy link
Author

sarkrui commented Nov 17, 2019

@Jeroen88 Thanks again! Although you made another tiny typo haha. A backslash is necessary before a double-quotation mark.

char buffer[20];
sprintf(buffer, "{\"sensor_0\": %d, \"sensor_1\": %d}", 1234, 5678);
http.POST(buffer);

@sarkrui sarkrui closed this as completed Nov 17, 2019
me-no-dev pushed a commit that referenced this issue Jan 20, 2020
…3487)

If two headers with overlapping names are added while replace == true, like in:
```cpp
http.addHeader("api_token",  "pMXFOLpinQqajaRQJYMeWObg2XYmcX1");
http.addHeader("token", "1234");
```
then replacing went wrong. This is fixed with this PR.
@sohaibqamar
Copy link

Hi,
I may be cluttering someone else post, but I found it relevant to my problem.
I am trying to POST with Bearer token and I am unable to get the server response.
I have checked with Postman and I am getting the right response there.
I have written all the details here.
Any help would be great. Thank you for your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants