In this tutorial we will show you how to create a traditional upload form and then move on to creating a drag & drop uploader. All new browsers such as IE10, Firefox, Chrome, Safari, and Opera support the new HTML5 drag and drop upload standard. Drag and drop upload makes it much easier for the user to upload data. It’s also very easy to implement a progress bar for drag and drop upload.
You must first build an HTML form that lets users select a file to upload before you can use server side LSP to manage your uploads. See our HTML Forms for Beginners tutorial if you are new to HTML forms. The following HTML form contains all HTML elements required for a file upload form.
<form enctype="multipart/form-data" method="post"> Choose a file to upload: <input name="thefile" type="file" /> <br/> <input type="submit" value="Upload File" /> </form>
After the user clicks submit, the data will be posted (sent back) to the same LSP page that presented the upload form. The following LSP code is all that is required on the server for receiving and saving the received data to a file.
<?lsp local err if request:method() == "POST" then -- Open a file pointer for the data we will receive. local fp fp,err=io:open("the-file-name","w") if not fp then err = "Cannot open file: "..err else -- filedata: save data chunks received from the client local function filedata(data) fp:write(data) end request:multipart{ beginfile=function() end, -- Required, but not used. filedata=filedata, error=function(e) err=e end } fp:close() -- Upload complete if err then err = "Upload failed: "..err end end end if err then response:write('<p>',err,'</p>') end ?>
The above code executes if the HTTP method is POST. The method request:multipart decodes the multi-part stream received from the browser and calls the callback function ‘filedata’ for each file data chunk that has been decoded. The request:multipart method also requires a "beginfile" function, but we are not using this function in the above example so we have created a dummy function that does nothing. The above code uses the IO interface defined in the web application and the application can for this reason not be deployed, i.e. not be a ZIP file. You can change this code and use any of the Mako Server IO Interfaces. You can also use the standard Lua input/output functions.
All modern browsers support the new XMLHttpRequest Level 2 specification which makes it possible to design drag and drop logic in JavaScript.
To visualize that we support drag and drop, we’ll install a “dragover” JavaScript callback. The easiest way to do this is to use JQuery.
var dragover=false $('body').bind('dragover',function(e) { e.preventDefault(); if(dragover) return; dragover=true; $('#dropbox').fadeTo(300,.3,function(){ $('#dropbox').fadeTo(300,1, function() {dragover=false;});}); });
The ‘dragover’ callback function, which we bind to the ‘body’ element, triggers when the user drags a file over the browser window. The ‘dropbox’ element, which we reference on the two last lines in the above code, is for a div element with the drop image to the right. The chained fadeTo functions make the drop box oscillate. You can test this by dragging a file over the image to the right. The image to the right should then start to oscillate by fading in and out. Note, do not drop the file since this page is not designed for accepting ‘drop’ events. |
The ‘dragover’ callback is not required, but it provides a visual clue to the user that we support drag and drop. You can make the ‘dragover’ callback perform any type of visual clue, and you do no have to use the code we provided above.
The browser fires a ‘drop’ event when a user drops a file into a browser window. We must install a callback that catches this event and prevents the default browser action.
// The drop event callback i.e. drag and drop function drop(e) { e.preventDefault(); //Prevent the default browser action // We accept one file. Additional files are ignored. var file=e.originalEvent.dataTransfer.files[0]; var xhr = new XMLHttpRequest(); //Create the upload object //Bind a "progress" callback xhr.upload.addEventListener("progress", my_progress); //Open connection to origin i.e. to LSP page xhr.open("PUT", window.location.href); xhr.send(file); // Start the upload }; $('body').bind('drop',drop); // Bind the drop function to the drop event
The above code is designed such that it accepts one dropped file. You can redesign the code and make it accept all files dropped into the browser window. As an example, the Web File Manager used in the How to Create a Cloud Server tutorial accepts all files dropped into the browser window.
The above code creates a XMLHttpRequest object and binds a “progress” event to the object. The code for this callback is not shown in the above code snippet. The complete JavaScript code for the above is provided in the example code presented at the end of this tutorial.
Notice that we use the HTTP PUT method in the above example and not HTTP POST when sending data to the server. The HTTP PUT method was designed specifically for uploading files and the Mako server provides an object that manages HTTP PUT uploads.
<?lsp local err if request:method() == "PUT" then -- Open a file pointer for the data we will receive. local fp fp,err=io:open("the-file-name","w") if not fp then err = "Cannot open file:"..err else -- filedata: save data chunks received from the client local function filedata(data) fp:write(data) end for data in request:rawrdr() do filedata(data) end fp:close() -- Upload complete end end ?>
The code in example 5 is similar to the code in example 2. The request:rawrdr() method returns a Lua iterator that makes it possible to iterate over the received HTTP PUT data. The data received is not buffered inside the request:rawrdr() method, but is instead returned as chunks as long as data trickles in.
You can easily combine the code in example 2 and 5. The example code, which you can download below, combines the code in example 2 and 5. This code automatically detects if the data received should be parsed by request:multipart (example 2) or managed by the iterator returned by method request:rawrdr (example 5).
The above example code uses the server’s blocking API functions. This means that each active upload requires an executing thread. The Mako Server can be configured to use a large number of threads, but you will eventually run into limitations if you plan on supporting many concurrent uploads.
The Mako Server also provides a more advanced upload API that uses non blocking sockets. This API should be used if you have requirements where you need to support many concurrent uploads. The Web File Manager, which is introduced in the How to Create a Cloud Server tutorial, uses this API. We also provide a non blocking firmware upload example, which is identical to the code above, except for that the code uses the non blocking API.
Dive deep into our treasure trove of embedded web server and IoT tutorials designed for enthusiasts like you. Yet, if deadlines loom or challenges arise, remember our experts are on standby. With Real Time Logic, you have the freedom to learn and the assurance of expert support when you need it. Let's bring your project to fruition your way.
Expedite your IoT and edge computing development with the "Barracuda App Server Network Library", a compact client/server multi-protocol stack and toolkit with an efficient integrated scripting engine. Includes Industrial Protocols, MQTT client, SMQ broker, WebSocket client & server, REST, AJAX, XML, and more. The Barracuda App Server is a programmable, secure, and intelligent IoT toolkit that fits a wide range of hardware options.
SharkSSL is the smallest, fastest, and best performing embedded TLS stack with optimized ciphers made by Real Time Logic. SharkSSL includes many secure IoT protocols.
SMQ lets developers quickly and inexpensively deliver world-class management functionality for their products. SMQ is an enterprise ready IoT protocol that enables easier control and management of products on a massive scale.
SharkMQTT is a super small secure MQTT client with integrated TLS stack. SharkMQTT easily fits in tiny microcontrollers.
An easy to use OPC UA stack that enables bridging of OPC-UA enabled industrial products with cloud services, IT, and HTML5 user interfaces.
Use our user programmable Edge-Controller as a tool to accelerate development of the next generation industrial edge products and to facilitate rapid IoT and IIoT development.
Learn how to use the Barracuda App Server as your On-Premises IoT Foundation.
The compact Web Server C library is included in the Barracuda App Server protocol suite but can also be used standalone.
The tiny Minnow Server enables modern web server user interfaces to be used as the graphical front end for tiny microcontrollers. Make sure to check out the reference design and the Minnow Server design guide.
Why use FTP when you can use your device as a secure network drive.
PikeHTTP is a compact and secure HTTP client C library that greatly simplifies the design of HTTP/REST style apps in C or C++.
The embedded WebSocket C library lets developers design tiny and secure IoT applications based on the WebSocket protocol.
Send alarms and other notifications from any microcontroller powered product.
The RayCrypto engine is an extremely small and fast embedded crypto library designed specifically for embedded resource-constrained devices.
Real Time Logic's SharkTrust™ service is an automatic Public Key Infrastructure (PKI) solution for products containing an Embedded Web Server.
The Modbus client enables bridging of Modbus enabled industrial products with modern IoT devices and HTML5 powered HMIs.