In this tutorial, we will look into the basics of LSP and how you can use HTML forms for sending data from the browser to the server. When we convert simple HTML pages into interactive applications we need to get user input to be processed at the server side. The server side processing is done by Lua Server Pages (LSP) in the Mako Server.
Let's take a quick look at the inner working of LSP before moving onto designing HTML web forms. Having a basic understanding of the LSP engine will make it easier for you to design server side web applications. LSP can dynamically create any type of text so let's make it simple by creating an LSP page that returns "Hello World".
An LSP page containing the two words "Hello World" will be converted by the LSP processor into Lua code similar to the following:
function action() response:write("Hello World") end
The Lua function action() is called by the Mako Server runtime engine when a browser visits our hello world LSP page. The action() function's environment (aka scope) includes a number of pre-defined variables such as the request object and the response object. The request object makes it easy to retrieve information provided by the client and the response object is used when sending response data back to the client.
The above example is not very exciting since the produced result is no different from a static HTML page. We have to use LSP tags in order to create dynamic content.
LSP provides a simple and fast way of creating dynamic web pages. Lua script can be freely intermixed with text such as HTML and XML. LSP tags are XML compliant <?lsp ?>. Code between these tags is executed as Lua code. Expressions are provided by the <?lsp= ?> tag. The result of an expression is emitted as HTML/XML.
We can insert Lua code into an LSP page by using LSP code tags and LSP expression tags. The following example dynamically creates a response message from the HTTP method used by the client:
<?lsp if request:method() == "GET" then ?> You sent a GET request <?lsp else ?> You sent a <?lsp=request:method()?> request <?lsp end ?>
Processed LSP page:
function action() if request:method() == "GET" then response:write("You sent a GET request") else response:write("You sent a ",request:method()," request") end end
The LSP processing is automatic and you will not see the processed LSP page as shown above. The complete processing and compilation sequence is shown in figure 1, where the LSP processor converts LSP to Lua, and the Lua compiler compiles Lua into byte code that in turn is executed by the Lua runtime engine.
HTML forms send data as key/value pairs to the server, where the key/value pairs can be sent as data content just after the initial HTTP header or as part of the URL.
A number of characters are reserved and must be escaped. For example, the ampersand character must be escaped since this character is used to separate the key/value pairs. Escaping the characters are known as URL encoding. The encoding/decoding is normally automatic and transparent to you as a developer. The browser automatically encodes the data and the server automatically decodes the data.
The key/value pairs are embedded in the query string when they are sent as part of the URL. The client typically sends a GET request to the server when sending a query string. As an example, clicking the following link sends a GET request with the key 'q' and the value 'URL encoding' as part of the query string to the "let me Google that for you" service.
Although one can send form data as a GET request, it is more common to send form data as a POST request and append the URL encoded data just after the HTTP header. A browser sends POST data as "application/x-www-form-urlencoded" to the server.
In Lua, key value pairs are best represented as a table. The method request:data() returns a Lua table with all key/value pairs sent to the server. The following example shows how to iterate and print all URL encoded data sent from the client to the server. The following example shows how to iterate and print all URL encoded data sent from the client to the server. The data printed is sent as a response back to the HTTP client that performed the request.
<?lsp for key,value in pairs(request:data()) do response:write("key=", key, ", value=", value, "<br>") end ?>
You can save the above example in an LSP page, run the Mako Server, and enter the key/value pairs in the browser as follows:
The returned page should look like the following:
key=key1, value=value1 key=key2, value=value2 key=key3, value=value3
A form may contain many different types of input elements that allow the user to enter and send information to the server. The input element types you can use in a form are: text fields, text area, drop-downs, radio buttons, check boxes, etc.. They are combined together inside <form> and </form> tags. The values of all the input elements are submitted to the server-side when the user clicks a submit button. As an example, the following HTML illustrates how one could design a basic login form.
<form method="post"> <input type = "text" name="username"> <input type = "submit" value="Login"> </form>
You can save the above example in an LSP page and run the example in the Mako Server. Although the example is not a complete HTML page with all required HTML tags such as the body tag, etc., the example will still run in your browser. You can also press the submit button and the browser will send this as a POST request to the server.
LSP makes it easy to include HTML and process data sent from the browser inside the same LSP page. The first browser request is typically sent as a HTTP GET request and the HTML form data is typically sent as a HTTP POST request when the user clicks the submit button.
The image to the right shows a typical GET – POST sequence.
If you try the above example in the Mako Server, you’ll notice that nothing happens when you press the submit button. The form is sent as POST data from the browser to the server, but the above LSP page includes no server side logic that manages the submitted data. Let’s go ahead and add some basic Lua code that manages the submitted data.
01: <?lsp 02: local username 03: local session = request:session() 04: local data=request:data() 05: if request:method() == "POST" then 06: if data.username then 07: username=data.username 08: request:session(true).username=username 09: elseif session then 10: session:terminate() 11: end 12: else 13: username = session and session.username 14: end 15: ?> 16: 17: <form method="post"> 18: <?lsp if username then ?> 19: <h1>Hello <?lsp=username?></h1> 20: <input type = "submit" value="Logout"> 21: <?lsp else ?> 22: <input type = "text" name="username"> 23: <input type = "submit" value="Login"> 24: <?lsp end ?> 25: </form>
If you look at the above example, you will notice that in addition to the new server side logic at the top, we have also changed how the server dynamically creates the form. Line 17 to 25 dynamically creates a HTML login form or a HTML logout form. The login form is dynamically created if the variable username is nil. The logout form is dynamically created if the variable username is not nil.
We fetch the session object on line 3. Method request:session() returns nil if we do not have a session, which is the case when we are not logged in.
We fetch the submitted data on line 4. Method request:data() returns a Lua table with all the submitted key/value pairs sent from the browser when the submit button was pressed. The table will be empty if no data was submitted.
We check if this is a HTML form submit on line 5 -- i.e. if this is a HTTP POST. The browser will not send a POST request unless you press the submit button. The first time you load the page or if you press the refresh button you will end up on line 13. The code on line 13 retrieves the username if we have a session -- i.e., if the user is logged in.
We check if the submitted data contains "username" on line 6. This is only true if the user submits the data in the login form since only the login form includes an "input" (line 22) whose name is "username". If the login button is pressed, the username is permanently stored in the session object created on line 8.
If the logout button is pressed, line 6 evaluates to false and we end up on line 10.
The following two images show our basic login page in action.
Whether you are a maker, a startup, or a large business, we've got you covered. Please send us an email if you have any questions or if you are unsure on what product to select. We are here to help you find the best solution, and we'd really like to help you with your hardware/software project challenges.
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.