Generating Dynamic HTML Pages
"Printing" Dynamic HTML Data
In most cases, the Tibbo BASIC/C code included into an 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 io. object and reports this state on the HTML page:
<!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 Tibbo BASIC/C!
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 TCP and UDP 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 the 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:
<?
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 bulletproof 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 a 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 TiOS VM is a single-process system, so when it comes to processing the dynamic part of the files, one of the requests will be first.
It is also entirely possible that when executing the Tibbo BASIC/C 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 Tibbo BASIC/C 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 the 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 was introduced in TiOS V1.2. In earlier releases, 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 the 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 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.