Generating Dynamic HTML Pages
How to "print" dynamic HTML data
In most cases the BASIC code included into the HTML page is used to generate dynamic HTML content, i.e. to send some dynamically generated data to the browser. This is done in a way, similar to sending out data in a regular data mode: you first set the data you want to send with the sock.setdata method, then commit this data for sending using sock.send method.
Here is an example HTML page that checks the state of one of the inputs of the I/O object and reports this state on the HTML page:
** Tibbo Basic **
<!DOCTYPE HTML public "-//W3C//DTD W3 HTML//EN"> <HTML> <BODY> The state of line 0 is:!<br> <? 'This is a BASIC code fragment. Get the state of the line. io.num=0 if io.state= LOW then sock.setdata("LOW") else sock.setdata("HIGH") end if sock.send ?> </BODY> </HTML>
Notice how we did not have to use sock.num- it is set automatically when control is passed to BASIC!
Be careful not to get your data truncated!
The above example is seemingly correct and in this particular case will work fine- because there is not much static data preceding the point where we generate dynamic content and not much dynamic content is generated as well. Generally speaking, you cannot expect that the TX buffer will have enough space when you need to put some data into it! If you are not careful the dynamic data you want to generate may get truncated!
To avoid this situation always check if the necessary amount of free space is available before attempting to put it into the TX buffer. This statement is true for the normal data mode as well, not just for the HTTP processing- we have already touched on this subject in Sending Data. What is different for HTTP is that you cannot use the on_sock_data_sent event to "call you back" when the TX buffer frees up!
The only solution in case of HTTP is to wait, in a loop, for the desired amount of space to become available. Naturally, we don't want to be blocking the whole device, so "polite" waiting shall include a doevents statement:
** Tibbo Basic **
<? dim s as string(4) ?> <!DOCTYPE HTML public "-//W3C//DTD W3 HTML//EN"> <HTML> <BODY> The state of line 0 is:!<br> <? 'This is a BASIC code snippet. Get the state of the line. io.num=0 if io.state= LOW then s="LOW" else s=HIGH end if 'and now we wait till the TX buffer has enough free space while sock.txfree<len(s) doevents wend 'OK, so necessary space is now available! sock.setdata(s) sock.send ?> </BODY> </HTML>
Now we have a bullet-proof dynamic content generation and non-blocking operation! As you get more experience with HTML, you will see that the doevents statement has to be used quite often.
Special case: doevents and concurrent request of the same file
With HTTP it is entirely possible that two computers (browsers) will request the same HTML file. If you have allocated more than one socket for HTTP it is also possible that both of those requests will be processed at the same time. Of course, the BASIC VM is a single-process system, so when it comes to processing dynamic part of the files, one of the requests will be first.
It is also entirely possible, that when executing the BASIC procedure from the first "instance" of the file, execution arrives at doevents and the second instance of the same file will start to process. After all, doevents allows other events to execute, so this can include activity in other sockets.
Now, if the same BASIC procedure was allowed to execute again this would cause recursion: an attempt to execute a portion of code while it is already executing! Recursion is not allowed, so the VM will not re-enter the code immediately. Instead, the second instance of HTML page will be "on hold" until the first instance finishes running the procedure in question. After that, the same procedure will be executed for the second instance. This behavior has been introduced in V1.2 of TiOS. In the previous release, procedure execution for the second instance of the HTML page was simply skipped and not executed at all, which is wrong!
Once again, for this to occur the following conditions must be met: the HTML procedure in question must use doevents statement, and the same file (HTML page) must be requested simultaneously from several browsers.
Avoiding illegal characters
HTTP restricts the use of some characters- you cannot freely send any code from the ASCII table. When you use the sock.setdata and sock.send, you are "printing" data directly to the browser. It is your program's responsibility to avoid illegal characters and use "% xx" instead.