HTML Forms and LSP for Beginners

This tutorial introduces the concept of server side generated content aka server side scripting.

Ref Wikipedia: Server-side scripting
A program running on a web server (server-side scripting) is used to change the web content on various web pages or to adjust the sequence of or reload of the web pages. Server responses may be determined by such conditions as data in a posted HTML form, parameters in the URL, the type of browser being used, the passage of time, or a database or server state.

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.

How LSP Works

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")
Compile LSP

Figure 1. Recompiling LSP is as simple as refreshing the browser window.

Figure 1 illustrates how an LSP "Hello World" page is converted to Lua. Note, this example is for illustration purposes only and should not be used.

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 page:

<?lsp if request:method() == "GET" then ?>
   You sent a GET request
<?lsp else ?>
   You sent a <?lsp=request:method()?> request
<?lsp end ?>

Figure 2 shows how to dynamically produce HTML responses from the HTTP method type.

Processed LSP page:

function action()
   if request:method() == "GET" then
      response:write("You sent a GET request")
      response:write("You sent a ",request:method()," request")

Figure 3 illustrates how the LSP in Figure 2 is converted to Lua. Note, this example is for illustration purposes only and should not be used.

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 form data and query string (URL-encoding)

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.


Figure 4 shows how key/value pairs are sent to the server.

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.

Having an understanding of the HTTP protocol is not required when using the Mako Server, but if you are curious, you may want to read the online tutorial HTTP Made Really Easy.

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.

for key,value in pairs(request:data()) do
   response:write("key=", key, ", value=", value, "<br>")

Figure 5 shows how to iterate and print out all key/value pairs received from the client.

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

HTML Forms

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">

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: ?>
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.

image image

Download the Example Code

Download the Example Code From GitHub.

Seeking an Engineering Boost?

Our seasoned experts are ready to tackle your most pressing networking, security, and device management challenges. And if you're fueled by the DIY spirit, our rich collection of tutorials awaits to guide you. With us, you get the best of both worlds. Your project, our dedication.


OPC-UA Client & Server

An easy to use OPC UA stack that enables bridging of OPC-UA enabled industrial products with cloud services, IT, and HTML5 user interfaces.

Edge Controller

Edge Controller

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.

On-Premises IoT

On-Premises IoT Platform

Learn how to use the Barracuda App Server as your On-Premises IoT Foundation.

Embedded Web Server

Barracuda Embedded Web Server

The compact Web Server C library is included in the Barracuda App Server protocol suite but can also be used standalone.

WebSocket Server

Microcontroller Friendly

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.

WebDAV Server

Network File System

Why use FTP when you can use your device as a secure network drive.

HTTP Client

Secure HTTP Client Library

PikeHTTP is a compact and secure HTTP client C library that greatly simplifies the design of HTTP/REST style apps in C or C++.

WebSocket Client

Microcontroller Friendly

The embedded WebSocket C library lets developers design tiny and secure IoT applications based on the WebSocket protocol.

SMTP Client

Secure Embedded SMTP Library

Send alarms and other notifications from any microcontroller powered product.

Crypto Library

RayCrypto C Library

The RayCrypto engine is an extremely small and fast embedded crypto library designed specifically for embedded resource-constrained devices.

Embedded PKI Service

Automatic SSL Certificate Management for Devices

Real Time Logic's SharkTrust™ service is an automatic Public Key Infrastructure (PKI) solution for products containing an Embedded Web Server.


Modbus TCP client

The Modbus client enables bridging of Modbus enabled industrial products with modern IoT devices and HTML5 powered HMIs.

Posted in Tutorials