www.mycpu.eu (C) 2023 by Dennis Kuschel 

CGI for MyCPU

MyCPU is able of providing dynamically generated web content!

Abstract

The abbreviation "CGI" stands for Common Gateway Interface. It describes a mechanism how web servers can delegate the generation of web pages to a stand-alone application (an executable file). Such applications are commonly known as CGI scripts, but they are not required to be scripts, they can be written in any programming language.

With CGI the web site designer can provide dynamic content to the user. Websites are generated on-the-fly, so the user can interact with the server and the underlying software, for example data bases.

Sayed with other words: A CGI program can generate any kind of data that is downloaded to and displayed by the web browser. Usually the dynamically generated data will be a html file, but it can also be any other type of data, like a picture or a pdf file.


The Website Hit Counter

I wanted to track how many users are visiting my website and I wanted to collect some statistics about the load of my MyCPU webserver. In the past I had to use the services of other ISPs: I included a link to an image on an other website, and when the image was loaded the other webserver tracked the access so I got some statistics. But I wanted my little MyCPU server to work stand-alone, so I had to get rid of the external services. My idea was to extend the MyCPU server by some CGI like features, allowing me to generate my own small counter-images on-the-fly when the website is loaded. And so I implemented the CGI interface into my webserver code and wrote the program "counter.cgi" that provides the counting service.

The counter plugin "counter.cgi" is written in "C" and is stored in the new directory 8:/bin/cgi. It is referenced from within the configuration file 8:/etc/httpservcfg. If you whish to add the counting service to your MyCPU webserver, simply download and install the latest MyCPU software distribution, edit the httpservcfg - file and add the line "+ 8:/bin/cgi/counter.cgi" to it.

The counter image that is displayed is configurable and can have one of these styles:

           

The first style, style number 0, is the "analog" style. It is similar to the old mechanical counters. The second style (it has the number 1) is the "digital" style where you can configure the colors. Same with the third style (ID number 2) which is the "mini"-counter. Examples:

           

If you want to add such a counter to your website, you have to place a "<img>"-tag somewhere in you website. The ID-number of the counter, the style of the counter and the color is configured by optional parameters that are added to the URL.

For a simple "analog" counter add the tag <img src="counter.cgi?style=0"> to your html source code. If you want to have the very little blue/white counter on your web site, you have to insert the code <img src="counter.cgi?style=2&fgcol=ffff00&bgcol=0000ff"> into your html side.

The table lists the options that are supported:

style Selects the counter image style. Style numbers 0, 1 and 2 are supported. If this option is not set, the counter has style 0 by default.
ctr MyCPU can manage 10 different counters. If you want to use more than one counter on your website, add this option to define the ID-number of the counter (the values 0 to 9 are valid for this option). If this option is not set, the counter 0 is used by default. Note: All counters do access-filtering, that means, a counter is not triggered twice when it is loaded from the same source IP address within 30 minutes. The counter number 9 does not do this filtering, it is incremented on every access. Example: ctr=9 (selects counter number 9)
fgcol
bgcol
bgcol2
These options set the color scheme of the counters with style 1 and 2. The color is coded as a three-byte hexadecimal RGB value. fgcol = foreground color, bgcol = background color, bgcol2 = background color of the inactive segments of counter style 1. Example: fgcol=FF9900 (=orange)
len Defines the width (number of digits) of the counter. Example: len=10 defines a very long counter.
nocount The counter is not counted up when this option is set. This option does not take a parameter value.
ref This option can be used to forward the http referrer to the counter cgi. To do this you will need a little bit of java script. This option should be last and it should be started with to & signs. Example: counter.cgi?ctr=4&&ref=www.google.com
print When this option is set the counter.cgi creates no bitmap file but a html file that shows detailed counter statistics. Example: counter.cgi?print loads a common statistics page that contains links to detailed statistics for each counter.

Counter statistics are saved to the file 8:/etc/webcounters.txt. The file contains an editable and a fixed section. Please do not change any data in the fixed section, because this will result in losing all counter history. The counter statistics are saved at least one time per day to the file, so not too much data is lost in the case the webserver crashes (which happens really seldom :-))

Click here to see the counter statistics of this website


Use Any Program to Generate Dynamic Content

With "exec.cgi" you can use any program to generate dynamic web content. When a request for exec.cgi is made by the webbrowser, exec.cgi calls in turn a user-defined program whose stdout-stream is captured and forwarded to the browser. If you are a lazy guy how don't like to learn a new programming language like "C", you can also use the good old Basic to provide dynamic content. The syntax of exec.cgi is simple. For example "http://192.168.1.1/exec.cgi?x=ver" executes the shell command "ver" and displays the installed OS version in the webbrowser.

But what is with user input? In most cases users are entering some data into a web form that is then processed by a server side application. MyCPU's exec.cgi knows three ways to provide input data to your application. The first way is sending it to the std-input stream. The second is to provide "command line parameters" that are appended to the application call. For example, if you want to call the "mem" command with the parameters "-t -s" (="mem -t -s" on the shell prompt), you could send the CGI-request "http://192.168.1.1/exec.cgi?x=mem&p=-t -s" to the server. And the third way is to use dedicated environment variables to pass up to 9 values to the application. From within a basic program you can access this variables through the " env$()" function.

The table shows all parameters supported by exec.cgi:

x Mandatory. Sets the program that shall be executed on the server. For example "x=myprogram.bas" will execute your basic-program "myprogram.bas" on the server.
n This parameter can be used to insert some null-bytes at the beginning of the stdin-stream. Some programs that clear the input buffer at start up may require this parameter to work properly. For example add "n=2" to insert two null-bytes into the stream.
t Forward plain text from the URI to the stdin stream of the executed program. For example "t=hello world" will put the words "hello" and "world" into the input stream, so that you could use a "INPUT A$" from within a Basic program to read the string "hello world" into the variable A$. But note: The Basic interpreter echoes back the input data to the stdout stream. So you have to do some tricks to avoid that your input data is looped back to the generated website. (A trick is to place the echoed data in a hidden section in the generated html file, eg. by using the html comment function.)
c Same like the parameter "t", but replaces all commas (",") through a carriage return (CR) character.
h Use this parameter to forward binary data to your application program. Binary data is appended in hexadecimal notation to this parameter, so that for example "h=327E5A00C3" will put the bytes 32 7E 5A 00 and C3 in the program's input stream.
1 to 9 The numbers 1 to 9 are placeholders for environment variables with the same name. The environment variables can then be read from within the application program. For example the URI "http://192.168.1.1/exec.cgi?x=myprog.bas&1=MyCPU&2=rules" will set the environment variables 1 and 2 before calling the program myprog.bas. When the Basic program contains the line "print env$("1");env$("2")" you will see the text "MyCPUrules" in the generated website.

If you want to use exec.cgi to generate dynamic web content, you must enable exec.cgi in the webserver configuration file 8:/etc/httpserv.cfg. Please add the line "+ 8:/bin/cgi/exec.cgi" to the file, so that exec.cgi gets loaded when the webserver is started. The file must be extended by the names of the programs you want be able to execute from the web interface. For example, if you want to allow exec.cgi to execute the programs "mem" and "ver", you must add the following line to the configuration file:
"+ 8:/bin/cgi/exec.cgi 8:/bin/mem ver"   (of course without the quotation marks)

exec.cgi supports different MIME format types for the generated output stream. The MIME type is set with a control string at the beginning of the generated stream. These control-strings (MIME types) are currently supported by the MyCPU webserver: :html:, :bmp:, :gif:, :jpeg:, :png:, :pdf:, :zip:, :rar:, :tgz:, :tar:, :gz:. If no MIME type is set by your program, the webserver tries to set the type automatically. For example you don't need to set the MIME type if you are providing plain text or html data.

Here is an example of a small basic program that collects system information and generates a html page. Click the link exec.cgi?x=sysinfo.bas to see the generated page:

 100 print":html:";
 120 print"<html><head><title>MyCPU System Info</title></head><body>"
 130 print"<h2>System Uptime</h2><pre>"
 140 shell"uptime"
 150 print"</pre><br><hr><h2>Last System Errors</h2><pre>"
 160 shell"errors"
 170 print"</pre><br><hr><h2>Loaded Modules</h2><pre>"
 180 shell"mem -a"
 190 print"</pre><br><hr><h2>Network Statistics</h2><pre>"
 200 shell"netstat -t"
 210 print"</pre><br><hr><h2>Network Configuration</h2><pre>"
 220 shell"ifconfig"
 230 print"</pre><br><br></body></html>"


The C-Program API

If the provided CGI handlers counter.cgi and exec.cgi do not satisfy your needs, you can write your own CGI handler program in 'C'. The table below shows the relevant functions that are defined in mycpu.h:

void cgi_start(
    const char* httpfile,
    __cgiHandler cgihandler);
This function is called from the main()-entry of your C-program. It registers the CGI callback handler function and starts the CGI service. "httpfile" is the name of the export (eg. "counter.cgi") and "cgihandler" is a pointer to the handler function. The handler function gets called every time a webbrowser requests your CGI file. All further work is performed in the callback handler function: You can write up to 16kb output data to the stdout stream by using fwrite() or printf() and friends.
void cgi_stop(void); Stops the CGI service. You should call this function from an exit-handler that is registered through a call to atexit(). See countercgi.c and execcgi.c for details.
void cgi_ifidle(
    __cgiIdle idlecallback);
Optional: Registers a callback function that is called one time per second when the http-server is idle. This can be used to do some background operation.
char* cgi_getStringParam(
    const char *paramname);
Get a string-parameter from GET-request-line (URI). Parameters are separated by '&'-signs and values are assigned by a '='-signs. For example, if your CGI handler is called with the URI " myprog.cgi?day=monday&week=25", a call of cgi_getStringParam("week") will return a pointer to the value "25".
void cgi_setMimeType(
    char mimetype);
Set the MIME type of the generated data. These types are defined: MIME_PLAINTEXT, MIME_HTML, MIME_BMP, MIME_GIF, MIME_JPEG, MIME_PNG, MIME_PDF, MIME_ZIP, MIME_RAR, MIME_TGZ, MIME_TAR, MIME_GZ
void cgi_bufPoke(
    int addr, char value);
Writes a byte into the CGI output buffer. Note that the output buffer has a size of approx. 16kb.
char cgi_bufPeek(int addr); Reads back a byte from the CGI output buffer.

Please see the example programs countercgi.c and execcgi.c for more details. These files are included in the latest MyCPU software package.