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.