Perl & Python编写CGI
最近偶然玩了一下CGI,收集点资料写篇在这里留档。?现在想做HTTP Cache回归测试了,为了模拟不同的响应头及数据大小,就需要一个CGI按需要传回指定的响应头和内容,这是从老外的测试页面学习到的经验。 CGI其实就是使用STDIN和环境变量作为输入,?STDOUT做为输出,依照Http协议生成对应的数据。 一. 数据输出数据输出遵循HTTP协议,分为四部分: ? 状态行 (Status Line): ? ? ?200 OK ? 响应头(Response Headers): ? ? ?Content-Type: text/html ? ? ?Content-Length: 3072 ? ?空白行(代表响应头已经列完,只能包含回车和换行符): ? ? ? ?数据(文本或二进制数据): ? ?<html>xxxxxx</html> ?参考:?HTTP Protocol 状态行和响应头中每一行都必须以rn(回车及换行)结束。使用这个规则,以简单的文本组装就可以完成响应了。 只要注意二进制数据输出方法就可以了。 尝试设定Content-Length时可能没办法设定的准确,至少对于Apache Server是这样,不过不影响最后返回的数据量。 二. 数据输入CGI的数据输入主要是环境变量,下面这个链接有一串定义, ? ? ?CGI Environment Variables
当你需要CGI处理POST请求时,CGI就要使用STDIN做为输入来接收数据了。 在Perl里使用下面的代码读取: ? use CGI; ??my $cgi = CGI->new(); ? my %params = $cgi->Vars(); 而在Python则是: ?import cgi ?cgi.FieldStorage() 参考:?Perl CGI Input Test 三. 开发语言可以写CGI的开发语言太多,下面附上两个分别使用Perl和Python编写的相同功能的CGI,正好可以做个对比。 这两个脚本可以接收Query String,然后返回不同的文件,数据大小,以及缓存相关的头信息,可以区分二进制数据和文本数据。 CGI脚本支持以Query String修改以下响应头: ? ?content type, ? ?cache control, ? ?content length (只返回对应大小的数据), ? ?last modified, ? ?expires 下面是返回一个指定大小图片的例子: ? /cgi/cache_factory.pl?type=image&size=32&last-modified=Fri,02 Apr 2014 02:34:06 GMT&cache-control=private,max-age=60&expires=Fri,22 Apr 2014 02:34:06 GMT 代码很简单,可以做个参考。 Perl版本#!/usr/bin/perl use strict; use warnings; use CGI; use constant BUFFER_SIZE => 4_096; use constant DATA_DIRECTORY => "/var/www/Cache"; my $cgi = CGI->new(); my %params = $cgi->Vars(); &parserCommonHeaders; if(exists $params{'type'} && $params{'type'}=="image"){ &generateImageData; } else{ &generateTextData; } sub parserCommonHeaders{ if(exists $params{'cache-control'}){ print 'Cache-Control:',$params{'cache-control'},"rn"; } if(exists $params{'last-modified'}){ print 'Last-Modified:',$params{'last-modified'},"rn"; } if(exists $params{'expires'}){ print 'Expires:',$params{'expires'},"rn"; } if(exists $params{'etag'}){ print 'ETag:ea6186e11526ce1:0',"rn"; } } sub generateImageData{ my $buffer = ""; my $targetSize = 100*1024*1024; if(exists $params{'size'} && $params{'size'}>0){ $targetSize = 1024*$params{'size'}; print "Content-length: $targetSize rn"; } my $image = DATA_DIRECTORY .'/images/very_big.jpg'; my( $type ) = $image =~ /.(w+)$/; $type eq "jpg" and $type == "jpeg"; print $cgi->header( -type => "image/$type",-expires => "-1d" ); binmode STDOUT; local *IMAGE; open IMAGE,$image or die "Cannot open file $image: $!"; my $sentSize = 0; while ( read( IMAGE,$buffer,BUFFER_SIZE ) ) { print $buffer; $sentSize += BUFFER_SIZE; if($sentSize>=$targetSize){ last; } } close IMAGE; } sub generateTextData{ my $startHeader = '<html><head><title>HTTP Cache Testing HTML</title></head><body>'; my $tailPart = '</body></html>'; if(exists $params{'type'}){ print "Content-type:$params{'type'}rn"; } else{ print "Content-type:text/htmlrn"; } my $targetTextSize = 100*1024*1024; if(exists $params{'size'} && $params{'size'}>0){ $targetTextSize = 1024*$params{'size'}; print "Content-length: $targetTextSize rn"; } print "rn"; $targetTextSize -= length($startHeader) + length($tailPart); print "$startHeader"; my $filepath = DATA_DIRECTORY .'/files/big_text.txt'; open(FILE,$filepath) or die $!; my @lines = <FILE>; close(FILE); foreach my $line (@lines) { if( length($line)<=$targetTextSize ){ print $line; } else{ print substr($line,$targetTextSize); } $targetTextSize -= length($line); if($targetTextSize<=0){ last; } } print "$tailPart"; } Python版本#!/usr/bin/python import os import cgi import sys BUFFER_SIZE = 4096 DATA_DIRECTORY = "/var/www/Cache" def parserCommonHeaders(formQuery): if('cache-control' in formQuery.keys()): print 'Cache-Control:',formQuery['cache-control'].value,"rn",if('last-modified' in formQuery.keys()): print 'Last-Modified:',formQuery['last-modified'].value,if('expires' in formQuery.keys()): print 'Expires:',formQuery['expires'].value,if('etag' in formQuery.keys()): print 'ETag:ea6186e11526ce1:0',def generateImageData(formQuery): targetSize = 100*1024*1024; if('size' in formQuery.keys()): targetSize = 1024*int(formQuery['size'].value) print "Content-length:",targetSize,image = DATA_DIRECTORY+'/images/very_big.jpg' print "Content-Type:image/jpegrn",print sentSize = 0 f = open(image,'rb') while True: data = f.read(4096) sentSize = sentSize + BUFFER_SIZE sys.stdout.write(data) if sentSize>targetSize: break sys.stdout.flush() close(f) def generateTextData(formQuery): startHeader = '<html><head><title>HTTP Cache Testing HTML</title></head><body>' tailPart = '</body></html>' targetTextSize = 2.3*1024*1024; if('size' in formQuery.keys()): targetTextSize = 1024*int(formQuery['size'].value) print "Content-length:",targetTextSize,if('type' in formQuery.keys()): print "Content-type: %srn"%(formQuery['type'].value),else: print "Content-type: text/htmlrn",print print startHeader targetTextSize = targetTextSize - len(startHeader) - len(tailPart) filepath = DATA_DIRECTORY + '/files/big_text.txt' file = open(filepath) lines = file.readlines() file.close() for line in lines: if( len(line) <= targetTextSize ): print line else: print line[0:targetTextSize] targetTextSize = targetTextSize - len(line) if(targetTextSize<=0): break print tailPart if __name__ =="__main__": formQuery = cgi.FieldStorage() #os.environ['QUERY_STRING'] parserCommonHeaders(formQuery) if('type' in formQuery.keys() and formQuery['type'].value=="image"): generateImageData(formQuery) else: generateTextData(formQuery) 四. 服务器??服务器端使用Apache Server+WANem,配合CGI完成灵活的需求,开通SFTP端口供相关同学编辑,方便共享测试用例。 ???? .-----.?? .-------. ???? | CGI |?? | WANem | ???? '-----'---'-------' ???? | Apache Server?? | ???? '-----------------' ????????????? ^ ????????????? | ???????? SFTP & HTTP ????????????? | ??? .------------------. ??? | Web Page Editor? | ??? | and Browser????? | ??? '------------------' ? ? 配有WANem最大的好处就是可以根据需求进网络状态调整,甚至可以用类似下面的方式在测试用例动态调整。 参考:? ?Apache配置?(不要忘记给CGI脚本加上可执行权限) ? ?CGI Programming 101 (Perl) ? ?Debugging CGI Programs (Perl) ? ?Python CGI编程 ? ?Python CGI Debugging (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |