събота, 11 юни 2011 г.

Creating web interface

FriendlyARM comes with installed Boa web server. 
Web interface can be very useful feature for real life applications. 
It might be used for editing and storing settings to a file or to access the real world - ADC, GPIO, SPI, Serial.

The purpose of this tutorial is to show the basics of creating a simple web interface using CGI in C.

All that you need is mini2440 board with or without LCD and PC with GCC cross-compiler  
http://www.friendlyarm.net/dl.php?file=arm-linux-gcc-4.4.3.tgz
On my mini2440 I have SD card installed. If  you do not have any you have to make some changes to the code.

Example 1:
The example consists of the following files:
index.html
template.html
savefile.c
showfile.c

This web interface opens example.txt text file from the flash and shows it on a web page. 
The user can edit it and store it back.

The first file is index.html. When you type the IP address of the FriendlyARM board into a web browser Boa 
searches for index.html in /www 

index.html:

<HTML>
  <HEAD>
    <TITLE>REDIRECTING...</TITLE>
    <meta http-equiv="Refresh" content="3;url=./cgi-bin/showfile.cgi">
  </HEAD>
   
  <BODY>
    redirecting in 3 seconds...
  </BODY>
</HTML>


The only purpose of this web page is to redirect the browser to another URL and in particular this is the showfile.cgi

What is CGI? This is a program. It might be a script file or an executable written in no matter what programming language.
You can write CGI in C,Basic or even Assembler. This executable is called by the web server. 
CGI program captures data reading environment variables and the output data is sent to the console. 
The web server captures this output and sends it back to the client's browser.

Two CGI programs are used in this example - showfile.cgi and savefile.cgi
When the web server calls showfile.cgi it reads file template.html from flash and sends it's contents to the console.
The contents of example.txt are sent between </TEXTAREA> and </TEXTAREA> tags. 

template.html
<HTML>
  <HEAD>
    <TITLE>EDIT TEXT FILE</TITLE>
  </HEAD>
   
  <BODY>
    <FORM name="input" action="./savefile.cgi" method= "get">
        <TEXTAREA NAME=textarea ROWS=10 COLS=60>
<!-- /TEXTAREA -->
    <BR><BR>
    <INPUT type="submit" value="Submit" />       <INPUT type="reset" value="Undo changes" />
    </FORM>
  </BODY>
</HTML>

showfile.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main()
{
//Open template.html file. If unable to open show error web page and return
    FILE * htmlTemplate;
        htmlTemplate =  fopen("/sdcard/html/template.html","r");
    if(htmlTemplate == NULL)
    {
        printf("%s%c%c\n",    "Content-Type:text/html;charset=iso-8859-1",13,10);
        printf("<HTML><HEAD><TITLE>ERROR!</TITLE></HEAD>\n");
        printf("<BODY>\n");
        printf("<H3>ERROR: Unable to open template.html!</H3>\n");
        printf("</BODY></HTML>\n");
        return 0;
    }
//Open example.txt file. If it doesn't exist a new empty file will be created.
    FILE * textFile;
        textFile =  fopen("/sdcard/example.txt","a+");

//start sending template.html to the console
    char row[1000];
    printf("Set-Cookie:MY_COOKIE=ThisIsCookieJustForFun\n"); //This line is only to demonstrate how to set cookie
    printf("%s%c%c\n",    "Content-Type:text/html;charset=iso-8859-1",13,10);

    while(fgets(row,999,htmlTemplate))
    {
        printf(row);
        if(strstr(row,"<TEXTAREA") != NULL)
        {
            if(textFile != NULL)
            {//send example.txt to the console
                while(fgets(row,999,textFile))
                {
                    printf(row);
                }
            }
            printf("</TEXTAREA>\n");
        }
    }
    fclose(htmlTemplate);
    fclose(textFile);
    return 0;
}
   


savefile.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main()
{
//Open example.txt file.
    FILE * textFile;
        textFile =  fopen("/sdcard/example.txt","w");

    char * query;
    query = getenv("QUERY_STRING");

    printf("%s%c%c\n",    "Content-Type:text/html;charset=iso-8859-1",13,10);
    printf("<HTML><HEAD><TITLE>FILE SAVED</TITLE></HEAD>\n");
    printf("<BODY>\n");
    if(textFile != NULL)
    {// save file to disk
        //cut the beginning if it starts with "textarea="
        if(strstr(query,"textarea=") != NULL) fprintf(textFile,&query[9]);
        else fprintf(textFile,query);
        printf("<H3>File example.txt was saved to SD card</H3>\n");
    }
    else printf("<H3>Failed to save example.txt. Reason - unable to open file for writing.</H3>\n");

    printf("<BR><BR>\n");
    printf("QUERY_STRING:%s<BR><BR>\n",query);
    printf("<a href=\"./showfile.cgi\">Return to edit example.txt</a>\n");

//Nex code is just for fun.
    printf("<HR><BR><BR> Now let's read some environment variables just for fun<BR>");
    char *envvar;
    envvar=getenv("HTTP_COOKIE");
    printf("<BR>HTTP_COOKIE=%s",envvar);
    envvar=getenv("SERVER_SOFTWARE");
    printf("<BR>SERVER_SOFTWARE=%s",envvar);
    envvar=getenv("SERVER_NAME");
    printf("<BR>SERVER_NAME=%s",envvar);
    envvar=getenv("GATEWAY_INTERFACE");
    printf("<BR>GATEWAY_INTERFACE=%s",envvar);
    envvar=getenv("SERVER_PROTOCOL");
    printf("<BR>SERVER_PROTOCOL=%s",envvar);
    envvar=getenv("SERVER_PORT");
    printf("<BR>SERVER_PORT=%s",envvar);
    envvar=getenv("REQUEST_METHOD");
    printf("<BR>REQUEST_METHOD=%s",envvar);
    envvar=getenv("SCRIPT_NAME");
    printf("<BR>SCRIPT_NAME=%s",envvar);
    envvar=getenv("REMOTE_ADDR");
    printf("<BR>REMOTE_ADDR=%s",envvar);
    envvar=getenv("CONTENT_TYPE");
    printf("<BR>CONTENT_TYPE=%s",envvar);
    envvar=getenv("CONTENT_LENGTH");
    printf("<BR>CONTENT_LENGTH=%s",envvar);
    envvar=getenv("HTTP_USER_AGENT");
    printf("<BR>HTTP_USER_AGENT=%s",envvar);
    envvar=getenv("HTTP_REFERER");
    printf("<BR>HTTP_REFERER=%s",envvar);

    printf("</BODY></HTML>\n");

    fclose(textFile);
    return 0;
}
   

Compile it with command
arm-linux-gcc showfile.c -o showfile.cgi
arm-linux-gcc savefile.c -o savefile.cgi
 

When "Submit" is clicked on the web page content of the text area is sent back to the web server
and savefile.cgi is called. (Note the FORM tag in template.html)
Used method is "GET" and data is retrieved from the environment variable QUERY_STRING.
If "POST" method is used reading data is read from stdin.
NOTE: When data is sent back to server some special characters are encoded to %XX format. They have to be decoded before saving them to file. To keep this example simple I omitted this step.

Only for demonstration a cookie MY_COOKIE is set and reading some environment variables is implemented.


Upload files to the board:
index.html    -- /www
showfile.cgi  -- /www/cgi-bin
savefile.cgi  -- /www/cgi-bin
template.html -- /sdcard/html


change permissions to execute cgi files with:
[root@FriendlyARM cgi-bin]# chmod a+x showfile.cgi
[root@FriendlyARM cgi-bin]# chmod a+x savefile.cgi
 
If you miss to do it you will get error 

   502 Bad Gateway
   The CGI was not CGI/1.1 compliant.






LINKS:

HTML Tutorial
http://www.w3schools.com/html/default.asp

More on CGI
http://www.jmarshall.com/easy/cgi/

cgic: an ANSI C library for CGI Programming
http://www.boutell.com/cgic/
Excellent library that can save you a lot of typing.

iniParser: stand-alone ini parser library in ANSI C
http://ndevilla.free.fr/iniparser/
This is excellent library if you have to save and retrieve data from ini files.

Няма коментари:

Публикуване на коментар