So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By netphantm
#81806 Hi there.

I try to save my settings into a JSON file on my nginx-based webserver, but it doesn't work, I see an empty post-data reply and the file ends up empty. I couldn't find any better/working code around, so this is/are the function(s) I use that got me at least connected alright:

Code: Select allvoid writeSettingsWeb() {
  Serial.println("= writeSettingsWeb: ");

  String outputJson;
  StaticJsonBuffer<256> jsonBuffer;
  JsonObject &root = jsonBuffer.createObject();
  root["SHA1"] = SHA1;
  root["loghost"] = loghost;
  root["httpsPort"] = httpsPort;
  root["interval"] = interval;
  root["temp_min"] = temp_min;
  root["temp_max"] = temp_max;
  root["temp_dev"] = temp_dev;
  root["heater"] = heater;
  root["manual"] = manual;
  root["debug"] = debug;
  root.printTo(outputJson);
  //outputJson = serializeJson();
  //String uploadJson = urlEncode(outputJson);
  if (debug) {
    Serial.print(F("Connecting to https://"));
    Serial.println(loghost + ":" + httpsPort);
    //Serial.println("outputJson=|" + outputJson + "|");
  }

  HTTPClient http;
  //WiFiClientSecure client;
  BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure ;

  bool mfln = client->probeMaxFragmentLength(loghost, 443, 1024);
  Serial.printf("Maximum fragment Length negotiation supported: %s\n", mfln ? "yes" : "no");
  if (mfln) {
    client->setBufferSizes(1024, 1024);
  }

  from_str();
  client->setFingerprint(sha1);
  String msg = String("'device=" + hostname + "&uploadJson=" + outputJson + "'");
  Serial.print(F("Posting data: "));
  Serial.println(msg);

  if (http.begin(*client, loghost, httpsPort, "/upload.php", true)) {
    http.addHeader("Content-Type", "application/json");
    http.addHeader("User-Agent", "BuildFailureDetectorESP8266");
    http.addHeader("Host", String(loghost + ":" + httpsPort));
    http.addHeader("Content-Length", String(msg.length()));

    int  httpCode = http.POST(msg);
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      Serial.printf("[HTTPS] code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();
        Serial.println(payload);
      }
    } else {
      Serial.println("[HTTPS] failed, error: " + String(httpCode) + " = " +  http.errorToString(httpCode).c_str());
    }
    http.end();
  } else {
    Serial.printf("[HTTPS] Unable to connect\n");
  }
}

void from_str() {
  int j = 0;
  for (int i = 0; i < 60; i = i + 3) {
    String x = ("0x" + SHA1.substring(i, i+2));
    sha1[j] = strtoul(x.c_str(), NULL, 16);
    j++;
  }
}


this is the php part on the webserver:

Code: Select all<?php
  $filename = "settings-Donbot-test.json";

  if (isset($_POST)) {
    file_put_contents($filename, $_POST['uploadJson']);
    print '<pre>';
    print_r($_POST);
    print '</pre>';
  } else {
    error_log("No POST data");
  }
?>


and this is the result I see on the serial console:

Code: Select all= writeSettingsWeb:
Connecting to https://temperature.foo.com:443
Maximum fragment Length negotiation supported: yes
                                                  Posting data: 'device=Donbot&uploadJson={"SHA1":"B5:1F:7A:61:AE:D3:82:4A:D3:94:ED:D7:44:98:F0:E2:60:39:52:A5","loghost":"temperature.foo.com","httpsPort":443,"in
terval":300000,"temp_min":24,"temp_max":26,"temp_dev":-1.5,"heater":true,"manual":false,"debug":true}'
[HTTPS] code: 200
                 <pre>Array
                           (
                            )
                             </pre>
 39% [||||||||||||||||||||||||||||||                                                 ]


if I try with curl, it works as expected:
Code: Select all$ curl --data 'device=Donbot&uploadJson={"SHA1":"B5:1F:7A:61:AE:D3:82:4A:D3:94:ED:D7:44:98:F0:E2:60:39:52:A5","loghost":"temperature.foo.com","httpsPort":443,"interval":300000,"temp_min":24,"temp_max":26,"temp_dev":-1.5,"heater":true,"manual":false,"debug":true}' https://temperature.foo.com/upload.php
<pre>Array
(
    [device] => Donbot
    [uploadJson] => {"SHA1":"B5:1F:7A:61:AE:D3:82:4A:D3:94:ED:D7:44:98:F0:E2:60:39:52:A5","loghost":"temperature.foo.com","httpsPort":443,"interval":300000,"temp_min":24,"temp_max":26,"temp_dev":-1.5,"heater":true,"manual":false,"debug":true}
)
</pre>

$ cat settings-Donbot-test.json
{"SHA1":"B5:1F:7A:61:AE:D3:82:4A:D3:94:ED:D7:44:98:F0:E2:60:39:52:A5","loghost":"temperature.foo.com","httpsPort":443,"interval":300000,"temp_min":24,"temp_max":26,"temp_dev":-1.5,"heater":true,"manual":false,"debug":true}


the error log show nothing and in the access log I see just this:

[15/Apr/2019:00:24:12 +0200] "POST /upload.php HTTP/1.1" 200 32 "-" "ESP8266HTTPClient"

Do you need some more info, or can you see an error already? I am pretty new at the programming part.

thanks.
User avatar
By netphantm
#81813 I just noodled a bit around and found the problem myself. I changed the Content-Type to application/x-www-form-urlencoded and url-encoded the JSON, and now it works like a charm. If somebody thinks this can be useful to others, you can leave these postings here.
Here's the changed code and the urlEncode() I used:

Code: Select allvoid writeSettingsWeb() {
  Serial.println("= writeSettingsWeb: ");

  String outputJson;
  StaticJsonBuffer<256> jsonBuffer;
  JsonObject &root = jsonBuffer.createObject();
  root["SHA1"] = SHA1;
  root["loghost"] = loghost;
  root["httpsPort"] = httpsPort;
  root["interval"] = interval;
  root["temp_min"] = temp_min;
  root["temp_max"] = temp_max;
  root["temp_dev"] = temp_dev;
  root["heater"] = heater;
  root["manual"] = manual;
  root["debug"] = debug;
  root.printTo(outputJson);
  //outputJson = serializeJson();
  //String uploadJson = urlEncode(outputJson);
  if (debug) {
    Serial.print(F("Connecting to https://"));
    Serial.println(loghost + ":" + httpsPort);
    //Serial.println("outputJson=|" + outputJson + "|");
  }

  HTTPClient http;
  //WiFiClientSecure client;
  BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure ;

  bool mfln = client->probeMaxFragmentLength(loghost, 443, 1024);
  Serial.printf("Maximum fragment Length negotiation supported: %s\n", mfln ? "yes" : "no");
  if (mfln) {
    client->setBufferSizes(1024, 1024);
  }

  from_str();
  client->setFingerprint(sha1);
  String msg = String("device=" + hostname + "&uploadJson=" + urlEncode(outputJson));
  Serial.print(F("Posting data: "));
  Serial.println(msg);

  if (http.begin(*client, loghost, httpsPort, "/upload.php", true)) {
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    http.addHeader("User-Agent", "BuildFailureDetectorESP8266");
    http.addHeader("Host", String(loghost + ":" + httpsPort));
    http.addHeader("Content-Length", String(msg.length()));

    int  httpCode = http.POST(msg);
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      Serial.printf("[HTTPS] code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();
        Serial.println(payload);
      }
    } else {
      Serial.println("[HTTPS] failed, error: " + String(httpCode) + " = " +  http.errorToString(httpCode).c_str());
    }
    http.end();
  } else {
    Serial.printf("[HTTPS] Unable to connect\n");
  }
}

String urlEncode(String str)
{
  String encodedString="";
  char c;
  char code0;
  char code1;
  char code2;
  for (int i =0; i < str.length(); i++){
    c=str.charAt(i);
    if (c == ' '){
      encodedString+= '+';
    } else if (isalnum(c)){
      encodedString+=c;
    } else{
      code1=(c & 0xf)+'0';
      if ((c & 0xf) >9){
          code1=(c & 0xf) - 10 + 'A';
      }
      c=(c>>4)&0xf;
      code0=c+'0';
      if (c > 9){
          code0=c - 10 + 'A';
      }
      code2='\0';
      encodedString+='%';
      encodedString+=code0;
      encodedString+=code1;
      //encodedString+=code2;
    }
    yield();
  }
  return encodedString;
}


It came to me after I enabled debug log in nginx and realized that curl url-encodes the data it sends first:

Code: Select all2019/04/15 17:09:01 [debug] 1265#1265: *1892 fastcgi param: "HTTP_USER_AGENT: curl/7.61.0"
2019/04/15 17:09:01 [debug] 1265#1265: *1892 fastcgi param: "HTTP_ACCEPT: */*"
2019/04/15 17:09:01 [debug] 1265#1265: *1892 fastcgi param: "HTTP_CONTENT_LENGTH: 247"
2019/04/15 17:09:01 [debug] 1265#1265: *1892 fastcgi param: "HTTP_CONTENT_TYPE: application/x-www-form-urlencoded"


and I didn't with my POST from the ESP8266:

Code: Select all2019/04/15 16:05:40 [debug] 1266#1266: *7 fastcgi param: "HTTP_USER_AGENT: ESP8266HTTPClient"
2019/04/15 16:05:40 [debug] 1266#1266: *7 fastcgi param: "HTTP_CONNECTION: close"
2019/04/15 16:05:40 [debug] 1266#1266: *7 fastcgi param: "HTTP_ACCEPT_ENCODING: identity;q=1,chunked;q=0.1,*;q=0"
2019/04/15 16:05:40 [debug] 1266#1266: *7 fastcgi param: "HTTP_CONTENT_TYPE: application/json"
2019/04/15 16:05:40 [debug] 1266#1266: *7 fastcgi param: "HTTP_CONTENT_LENGTH: 249"


greetings,
netphantm.-