加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Perl & Python编写CGI

发布时间:2020-12-15 23:58:44 所属栏目:大数据 来源:网络整理
导读:最近偶然玩了一下CGI,收集点资料写篇在这里留档。?现在想做HTTP Cache回归测试了,为了模拟不同的响应头及数据大小,就需要一个CGI按需要传回指定的响应头和内容,这是从老外的 测试页面 学习到的经验。 CGI其实就是使用STDIN和环境变量作为输入,?STDOUT做

最近偶然玩了一下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

Key

Value

DOCUMENT_ROOT

The root directory of your server

HTTP_COOKIE

The visitor's cookie,if one is set

HTTP_HOST

The hostname of the page being attempted

HTTP_REFERER

The URL of the page that called your program

HTTP_USER_AGENT

The browser type of the visitor

HTTPS

"on" if the program is being called through a secure server

PATH

The system path your server is running under

QUERY_STRING

The query string (see GET,below)

REMOTE_ADDR

The IP address of the visitor

REMOTE_HOST

The hostname of the visitor (if your server has reverse-name-lookups on; otherwise this is the IP address again)?

REMOTE_PORT

The port the visitor is connected to on the web server

REMOTE_USER

The visitor's username (for .htaccess-protected pages)

REQUEST_METHOD

GET or POST

REQUEST_URI

The interpreted pathname of the requested document or CGI (relative to the document root)

SCRIPT_FILENAME

The full pathname of the current CGI

SCRIPT_NAME

The interpreted pathname of the current CGI (relative to the document root)

SERVER_ADMIN

The email address for your server's webmaster

SERVER_NAME

Your server's fully qualified domain name (e.g. www.cgi101.com)

SERVER_PORT

The port number your server is listening on

SERVER_SOFTWARE

The server software you're using (e.g. Apache 1.3)?


当你需要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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读