-->
Page 1 of 3

http upload with path?

PostPosted: Sun Aug 21, 2016 11:15 pm
by treii28
I'm trying to figure out how the upload functionality works in the ESP8266WebServer, but - sorry to say it - the documentation SUCKS.
I see there are two callbacks and the second one seems to be evoked more than once I'm assuming since it tests for three different states to decide whether to open a file/output handle, stream content to the handle, or close the handle. The other seems to be what is called when it's all finished.

Most of the examples I see just upload to the root of the SD card and don't check any other parameters. I wrote a function to check for a 'dir' parameter and then check to see if the 'dir' exists and is in fact a directory. I then managed to get the upload.filename concatenated to it. But When I try to put it somewhere in the handleUpload, I get crash after crash no matter how I try to place it.

So how in the hell do you parse a parameter in conjunction with the handleUpload functionality and still report errors and messages properly? i.e. if the directory doesn't exist, I want it to fail out due to that without even doing the upload. Otherwise, if it complete successfully, I want it to send a 200 with a little more user friendly message than a blank screen with a 200 code!

I tried something like this using the SD web server example. I added two String variables 'serverError' and 'serverMessage' globally and clear them out before starting each 'loop' call to handleClient. (I also clear them after running my returnFail or returnMessage calls)

In setup:
Code: Select all  server.on("/edit", HTTP_POST, []() {
    if (serverError != "") {
      returnFail(serverError);
    } else if (serverMessage != "") {
      returnMsg(serverMessage);
    } else {
      returnMsg("upload");
    }
    serverMessage = "";
    serverError = "";
  }, handleFileUpload);


handleFileUpload:
Code: Select allvoid handleFileUpload() {
  if (server.uri() != "/edit") return;
  HTTPUpload& upload = server.upload();

  if (upload.status == UPLOAD_FILE_START) {
    String fn = getDirArg() + upload.filename;
    if (serverError == "") {
      serverMessage = "uploading";
      DBG_OUTPUT_PORT.print("Upload: START, filename: ");
      DBG_OUTPUT_PORT.println(fn);
      if (SD.exists(fn)) {
        serverMessage += " over";
        DBG_OUTPUT_PORT.println("file exists, deleting!");
        // todo check to make sure file isn't a directory
        SD.remove(fn);
      }
      serverMessage += " " + fn;
      uploadFile = SD.open(fn, FILE_WRITE);
      DBG_OUTPUT_PORT.println("opened!");
    }
  } else if ((upload.status == UPLOAD_FILE_WRITE) && (serverError == "")) {
    if (uploadFile) uploadFile.write(upload.buf, upload.currentSize);
    DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: ");
    DBG_OUTPUT_PORT.println(upload.currentSize);
  } else if ((upload.status == UPLOAD_FILE_END) && (serverError == "")) {
    if (uploadFile) uploadFile.close();
    DBG_OUTPUT_PORT.print("Upload: END, Size: ");
    DBG_OUTPUT_PORT.println(upload.totalSize);
  }
}


getDirArg:
Code: Select allString getDirArg() {
  String d = (server.hasArg("dir")) ? server.arg("dir") : "";
  d.trim();

  char dChar[d.length() + 1];
  d.toCharArray(dChar, d.length() + 1);

  if ((d != "/") && (d != ""))  {
    if (SD.exists(dChar)) {

      File df = SD.open(d);
      if (df.isDirectory()) {
        if (!(d.endsWith("/"))) d += "/"; // add trailing slash if needed
      } else {
        serverError = "GETPATH: PATH NOT DIR";
      }
      df.close();
    } else {
      serverError = "GETPATH: PATH NOT EXIST";
    }
  }
  return d;
}


return with status functions:
Code: Select allvoid returnOK() {
  server.send(200, "text/plain", "");
}
void returnMsg(String msg) {
  server.send(200, "text/plain", msg + " successful\r\n");
}
void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

Re: http upload with path?

PostPosted: Sun Aug 21, 2016 11:34 pm
by treii28
OK, I think I found my error.
In the getDirArg() function, I was getting crashes on sd.exists() when using the string value for the filename. There is apparently a known bug that claims to be fixed on this, as it is supposed to handle the string, but it was still crashing for me and I was able to get around it by converting the string to a character array. I forgot the example code also had another SD.exists() call on the file to see if it existed already.
Allegedly the bug also effects the SD.remove() function so I converted the full path to a char and then used the char for both functions. re-compiling as I type. Testing shortly....

Yup, that did it. I guess I can make a wrapper for SD.exists and SD.remove to handle a string value until the bug is fixed.

UPLOAD_FILE_START portion of handleFileUpload:
Code: Select all    String fn = getDirArg() + upload.filename;
    if (serverError == "") {
      serverMessage = "uploading";
      DBG_OUTPUT_PORT.print("Upload: START, filename: ");
      DBG_OUTPUT_PORT.println(fn);
      char fnChar[fn.length()+1];
      fn.toCharArray(fnChar,fn.length()+1);
      if (SD.exists(fnChar)) {
        serverMessage += " over";
        DBG_OUTPUT_PORT.println("file exists, deleting!");
        // todo check to make sure file isn't a directory
        SD.remove(fnChar);
      }
      serverMessage += " " + fn;
      uploadFile = SD.open(fn, FILE_WRITE);
      DBG_OUTPUT_PORT.println("opened!");

Re: http upload with path?

PostPosted: Sun Aug 21, 2016 11:43 pm
by treii28
I was struggling finding the quick method and found it looking over other code. To use the string more directly (cleaner) they can be called as:

Code: Select allSD.exists((char *) pathString.c_str());
SD.remove((char *) pathString.c_str());


Ugh, struggling learning C++ (I haven't used it since college about 20 years ago)

Re: http upload with path?

PostPosted: Mon Aug 22, 2016 7:27 am
by martinayotte
Yes ! there was a issue with exist()/remove()/rmdir()/mkdir() with any "const char *" or String, making a recursion and then a WDT crash.
It been fixed but not merged yet ...
https://github.com/esp8266/Arduino/pull/2398

EDIT : Ok ! It is now merged into github ...