在前面的文章 里讲了如何安装、配置boa,这篇文章主要讲一下一些boa测试实例,主要涉及到html以及cgi程序的编写。
测试环境: 虚拟机(虚拟机软件为VMware)Fedora(以下与Linux为同义词),Linux的IP为192.168.184.100,通过VMnet8方式与物理机MS Windows连接,使用常用浏览器访问,如IE、Maxthon、Chrome等。 html不用介绍了。cgi全称为Common Gate Interface,它不是一种具体的语言,它可以使用其它语言来实现,比如C、C++、Perl、shell,等等。我们使用C语言来编写cgi程序。 我们需要使用到两个文件,一个是用于页面显示的使用html语言编写的hello.html,该文件放到/var/www/html目录中。另一个是用于响应该页面的cgi程序hello.c,该程序使用C语言编写,编译方式为:
1 $ gcc hello.c –o hello.cgi
编译后的可执行文件hello.cgi放到/var/www/cgi-bin目录中 完整的hello.html如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <html> <head> <title>this is my first HTML page</title> </head> <body> <center><p><h1>this is is a simple test of <I>HTML</I></h1></p></center> <center><img src="img/logo.jpg" alt="CST studio" /> hello from <a href="http://www.latelee.org"><b>Late Lee</b></a></center> <br /> <center><p>you can visit my website at <a href = "http://www.latelee.org">www.latelee.org</a></p><center> <hr /> <!-- a test --> <form name="form1" action="/cgi-bin/hello.cgi" method="post"> <table align="center"> <tr><td align="center" colspan="2"></td></tr> <tr> <td align="center">user name</td> <td><input type="text" name="Username"></td> </tr> <tr> <td align="center">password</td> <td><input type="password" name="Password"></td> </tr> <tr> <td><input type="submit" value="login"></td> <td><input type="reset" value="cancel"></td> </tr> </table> </form> </body> </html>
这个html文件分两部分,前半部分是一些常见的页面显示语句,这里包括了标题、图片显示、超链接。后半部分是我们真正的测试程序,主要设计了两个输入框,分别输入用户名和密码;两个按钮,分别是登陆和清除,这里的“登陆”并非实际中的登陆,它只是测试cgi程序的响应,结果是显示输入的信息。 注意到这一句:
1 <form name="form1" action="/cgi-bin/hello.cgi" method="post">
它的action表明了由哪一个cgi程序来响应来自该页面的消息,而method为http响应的方法,常用的有两种,分别是“post”和“get”,这里非专业地介绍一下。post,顾名思义,就是“提交”,用于更新信息;而get,即“获取”,用于从服务器中获取、查询信息。在下文将会看到,这两者在地址栏中的区别,使用post方法时数据是不会在地址栏中显示的,而get方法则会显示。不过本文不介绍这两者的本质区别。 如果直接输入Linux的IP地址,则会显示Fedora Project的启动页面,而要访问我们的测试网页,还需要再添加一些目录才行。这里的实际地址应该是:
1 http://192.168.184.100/html/hello.html
当然,IP地址需要根据实际情况而改变。 下面是响应的cgi程序hello.c完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #include <stdlib.h> #include <stdio.h> #include <string.h> char* get_cgi_data(FILE* fp, char* method) { char* input; int len; int size=1024; int i=0; if (strcmp(method, "GET") == 0) /**< GET method */ { input = getenv("QUERY_STRING"); return input; } else if (strcmp(method, "POST") == 0) /**< POST method */ { len = atoi(getenv("CONTENT_LENGTH")); input = (char*)malloc(sizeof(char) * (size+1)); if (len == 0) { input[0] = '\0'; return input; } while (1) { input[i] = (char)fgetc(fp); if (i == size) { input[i+1] = '\0'; return input; } --len; if (feof(fp) || (!(len))) { i++; input[i] = '\0'; return input; } i++; } } return NULL; } int main(void) { char* input; char* method; char name[64]; char passwd[64]; int i=0; int j=0; printf("Content-type:text/html\n\n"); printf("The following is query result:"); method = getenv("REQUEST_METHOD"); input = get_cgi_data(stdin, method); printf("string is: %s", input); int len = strlen(input); /* sizeof("username=") = 9 */ for (i=9; i<len; i++) { if (input[i] == '&') { name[j]='\0'; break; } name[j++]=input[i]; } /* sizeof("username=")+sizeof(&password=) = 19 */ for (i=19+strlen(name),j=0; i<(int)strlen(input); i++) { passwd[j++] = input[i]; } passwd[j]='\0'; printf("your username is %s your password is %s\n", name, passwd); return 0; }
这里不讨论代码的逻辑、风格等问题。 这个程序功能十分简单,就是打印获取到的请求字符串以及用户名称和密码。该程序与普通的C语言程序并无区别,只是多了我们不常用的getenv函数,它在stdlib.h头文件中声明,作用是获取指定的环境变量的值,比如我的系统中HOME这个环境变量值为/home/latelee/,则该函数返回指向这个值的指针。这里出现了QUERY_STRING,这是boa特有的环境变量,从字面上理解为“请求字符串”,我们打印了这个变量的值,也从该字符串中分析得到用户名和密码,下面将会看到。 在boa源代码目录下的examples目录中有一个cgi程序:cgi-test.cgi,它使用perl语言编写。将它复制到/var/www/cgi-bin目录中,在浏览器输入其地址:
1 http://192.168.184.100/cgi-bin/cgi-test.cgi
则显示下面的cgi测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Boa CGI test Date: Thu Jan 27 13:45:19 CST 2011 Method: GET Basic GET Form: Basic POST Form: Sample ISINDEX form: /cgi-bin/cgi-test.cgi?param1+param2+param3 Query String: Arguments: Environment: • SCRIPT_NAME = /cgi-bin/cgi-test.cgi • SERVER_NAME = FightNow • HTTP_ACCEPT_ENCODING = gzip, deflate • SERVER_ADMIN = • REQUEST_METHOD = GET • SERVER_SOFTWARE = Boa\0.94.13 • REMOTE_PORT = 3892 • HTTP_USER_AGENT = Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) • SERVER_PORT = 80 • HTTP_ACCEPT_LANGUAGE = zh-cn • REMOTE_ADDR = 192.168.184.1 • SERVER_PROTOCOL = HTTP/1.1 • PATH = /bin:/usr/bin:/usr/local/bin • GATEWAY_INTERFACE = CGI/1.1 • REQUEST_URI = /cgi-bin/cgi-test.cgi • SERVER_ADDR = 192.168.184.100 • HTTP_HOST = 192.168.184.100 No input stream: (not POST) id: uid=99(nobody) gid=0(root) groups=99(nobody) Boa http server
这里我们看到许多的环境变量以及它们的值,它们可以直接使用getenv函数获取。QUERY_STRING是客户端提交的数据,这些数据在传输过程中是经过了编码的,因此,要正确显示它们,必须进行解码。
表单中每个字段用字段名后跟等号,再接上这个字段的值来表示,每个字段之间的内容用“&”连结,前面的程序就是依据“&”进行判断用户名和密码的。
空格符号用加号(“+”)代替,而其它的特殊字符,如“!”、“#”等,使用百分号(“%”)加对应的ASCII码来表示。汉字也是这样表示。 下面是页面显示的效果图: 当输入用户名和密码分别输入latelee和latelee.org提交后,将出现如下提示信息:1 2 3 4 5 The following is query result: string is: Username=latelee&Password=latelee.org your username is latelee your password is latelee.org
可见,程序正确解析出了用户名和密码,不过当字段值有空格时,则显示:1 2 3 4 5 The following is query result: string is: Username=Late+Lee&Password=Late+Lee your username is Late+Lee your password is Late+Lee
可以看到,还没正确解析出空格(我不知道在字段值中出现空格本身就是是非法的还是程序的问题)。 当cgi程序采用get方法时,地址栏的变化为:1 http://192.168.184.100/cgi-bin/hello.cgi?Username=latelee&Password=latelee.org
而采用post方法时,地址栏为:1 http://192.168.184.100/cgi-bin/hello.cgi
未尽事宜:中文解析还没有完成,当用户名为“李迟”时,显示如下:
1 2 3 4 5 The following is query result: string is: Username=%C0%EE%B3%D9&Password=123 your username is %C0%EE%B3%D9 your password is 123