httpSaveFilesFromUpload()

The function returns the HTTP content of a Blob variable that was received from an HTTP client via an HTML form. The function copies the content of this blob variable (a file) into a directory.

Synopsis

int httpSaveFilesFromUpload( blob content, string boundary, string targetdirectory, mapping formdata);

Parameter

Parameter Meaning
content The content that was selected via an HTML form.
boundary The boundary parameter is the separator defined by the HTTP header. It defines a string for the HTTP content to separate multiple content parts of the upload. See example further below.
targetdirectory

The parameter targetdirectory defines an HTTP server local directory, where the uploaded files are saved when the function is called.

e.g.

"D:\\Data\\"

formdata

The mapping contains the form data:

  • The field names as key values and a second mapping as a value container.

The second mapping contains

  • The entry “content” which contains either the filename (without path) or the content of the form field (the field name that corresponds to a file name or other data),

  • a second entry “success” which tells whether the file save operation was successful.

The rest of the mapping keys represent the header information of a form field.

Example:

"fileupload" : mapping 4 items

WCCOActrl3: "success" : 1

WCCOActrl3: "content" : "hosts.txt"

WCCOActrl3: "Content-Type" : "text/plain"

WCCOActrl3: "Content-Disposition" : "form-data; name=\"fileupload\"; filename=\"D:\\hosts.txt\""

Return value

The function httpSaveFilesFromUpload returns 0 on success, otherwise -1.

Error

Wrong or missing arguments.

Description

The function returns the HTTP content of a Blob variable that was received from an HTTP client via an HTML form. The function copies the content of this blob variable (a file) into a directory.

WinCC OA does not support the upload type multipart/mixed. The upload of several files via one POST request is, however, possible. For POST request, see variable "formDoc" in the example below.

The current HTTP server implementation does not support streaming of data. Thus, the whole response is read into memory for being processed. Since processing demands a copy of the original data, this means allocating twice the memory and therefore running out of memory if the uploaded file is too large. We recommend to limit the upload to a meaningful value like 50 megabytes. This is the most common size on many public file upload sites.
Note:

To improve the security on the client:

  • Limit the selection of the possible directory.
  • Limit the possible HTML file type.

    To improve the security on the server:

  • Limit the selection of the possible target directory.
  • By using the function blobGetValue() you can query the content and can check the file name, the extension or the content type before saving a file. After saving: You can scan the target directory by using an antivirus software, check the file by name or extension and depending on the result, delete or copy the file to the final target directory.

Example

The following example starts an HTTP server at the port 12000 without authentication, creates a form with input fields for the selection of the data that should be copied. The example executes the function httpSaveFilesFromUpload in order to copy data.

#uses "CtrlHTTP"
int MAXLENGTH = 100 * 1024 * 1024;
// 100 MB

main()
{

// starts the HTTP Server at Port 12000 without authentication,
  httpServer(FALSE,12000);
  httpSetMaxContentLength(MAXLENGTH);


// Register Upload handler
// Use http://localhost:12000/filetest URL, in order to upload data
// httpConnect registers the functions "filetest1" and "fileupload" as Web resource
//  under the names "/filetest" and "/" as well as "/fileupload" and "/query_2"

 int k = httpConnect("filetest1","/filetest");
 DebugN("httpConnect:", k);

 int l = httpConnect("fileupload","/query_2");
 DebugN("httpConnect:", l);
}


// See rfc1867 for detailed information on form-based file uploads in HTML
string filetest1()
{

// Form example with two fields of types "file" and "submit".
//This means for selecting files and copying the selected data.
  string formDoc = "<html><head><title>File Upload</title>"
                   "<body><h1>"
                   "<form action=\"/query_2\" method=\"post\" enctype=\"multipart/form-data\">"
                   "<input type=\"file\" name=\"dateiupload\"> "
                   "<input type=\"submit\" name=\"btn[upload]\"> "
                   "<td><font face=\"Arial\"><input type=\"text\" size=\"40\"  name=\"folder\" value=\"Dokumente/neu\"></font></td></form>"
                   "</body></html>";
  return formDoc;
  DebugN("Formdoc:", formDoc);
// Returns the form
}

void fileupload(blob content, string user, string ip, dyn_string headernames, dyn_string headervalues, int connIdx)
{
  int pos =0;
  int len = bloblen(content);
  string val;
  blobGetValue(content,pos,val,len);
  DebugN(val);
  DebugN("blobGetValue - content:", content);

  string contentType = httpGetHeader(connIdx, "Content-Type");
  int pos = strpos(contentType, "boundary=");
// Returns the string boundary= from the string "contentType

  if (pos >= 0)
  {
    string boundary = substr(contentType, pos + 9);

// The "boundary" parameter is a separator defined by the HTTP header, substr cuts the string "contentType" off as of "pos" + 9 characters
    DebugN("Boundary:", boundary, contentType);
// Outputs the content of the "boundary" parameter as well as contentType

    mapping result;
    int retval = httpSaveFilesFromUpload(content, boundary, "D:\\Test\\", result);
    DebugN("result", result);
    for(int i = 1; i <= mappinglen(result); i++) DebugN("mappingGetValue", i, "is =" + mappingGetValue(result,i));

//Copies the content of the Content variable into the directory "D:/Test"
    dyn_string fNames = getFileNames("D:\\Test\\");
    DebugN("File names:",fNames);
    copyAllFiles("D:\\Test\\", "D:\\Test\\Target\\");
    DebugN("return", retval);

  }

  // parse content & extract file(s)
  // use info from header Content-Type: multipart/form-data; boundary=BOUNDARY
  // now search for BOUNDARY\r\n
  // next line holds
  //    Content-Disposition: form-data; name="myfile"; filename="FILENAME"\r\n
  //    Content-Type: MIMETYPE\r\n
  //    \r\n
  // here comes the content up to the next boundary (with trailing \r\n)
  //    BOUNDARY

}

Assignment

CTRL PlugIn

Availability

CTRL, UI