项目中使用了基于CGIEx构建的CGI,并且通过CGI调用Protobuf API来完成一些动态解析proto定义之类的功能,上线前使用Valgrind的memcheck工具检测CGI是否存在内存泄漏的风险。
Valgrind的使用十分简单,通过设置一定的参数启动二进制可执行程序,并且在执行结束之后收集结果输出即可。但是我们的CGI是通过Apache运行的,不能直接使用Valgrind启动,Google一圈之后没有找到相关的实践,只好自己动手。
首先,直接执行CGI二进制可执行程序,可以看到进入了交互模式(Intractive Mode),并且提示等待用户输入(如下图)。不过如何输入参数?如何确定GET和POST的调用方法?以及如何区分两种方法的参数,却仍是未知数。
继续深入研究,全局搜索”cgihtml Interactive Mode”后找到了线索,在cgi-lib.c文件中找到了get_DEBUG函数定义如下:
char *get_DEBUG()
{
int bufsize = 1024;
char *buffer;
int i = 0;
char ch;
if ((buffer = (char *)malloc(sizeof(char) * bufsize + 1)) == NULL)
exit(1);
fprintf(stderr,"\n--- cgihtml Interactive Mode ---\n");
fprintf(stderr,"Enter CGI input string. Remember to encode appropriate ");
fprintf(stderr,"characters.\nPress ENTER when done:\n\n");
while ( (i<=bufsize) && ((ch = getc(stdin)) != '\n') ) {
buffer[i] = ch;
i++;
if (i>bufsize) {
bufsize *= 2;
if ((buffer = (char *)realloc(buffer,bufsize)) == NULL)
exit(1);
}
}
buffer[i] = '\0';
fprintf(stderr,"\n Input string: %s\nString length: %d\n",buffer,i);
fprintf(stderr,"--- end cgihtml Interactive Mode ---\n\n");
return buffer;
}
继续搜索get_DEBUG的调用之处,发现只有一处调用,如下:
char* read_cgi_input(llist* entries)
{
char *input;
int status;
/* check for form upload. this needs to be first, because the
standard way of checking for POST data is inadequate. If you
are uploading a 100 MB file, you are unlikely to have a buffer
in memory large enough to store the raw data for parsing.
Instead, parse_form_encoded parses stdin directly.
In the future, I may modify parse_CGI_encoded so that it also
parses POST directly from stdin. I'm undecided on this issue,
because doing so will make parse_CGI_encoded less general. */
if ((CONTENT_TYPE != NULL) &&
(strstr(CONTENT_TYPE,"multipart/form-data") != NULL ))
{
parse_form_encoded(entries);
return NULL;
}
/* get the input */
if (REQUEST_METHOD == NULL)
input = get_DEBUG();
else if (!strcmp(REQUEST_METHOD,"POST"))
{
input = get_POST();
if ((input != NULL) && (strstr(input, "application/x-www-form-urlencoded") == NULL ))
{
return input;
}
}
else if (!strcmp(REQUEST_METHOD,"GET"))
input = get_GET();
else { /* error: invalid request method */
fprintf(stderr,"caught by cgihtml: REQUEST_METHOD invalid\n");
exit(1);
}
/* parse the input */
if (input == NULL)
{
return NULL;
}
status = parse_CGI_encoded(entries,input);
FREE(input);
return NULL;
}
分析到这里,现在大致可以确定如何直接启动CGI二进制文件并输入参数了。
CGI Interactive模式下,输入的参数就是通过GET方式调用时,URL后部所带的参数,形如:
param1=val1¶m2=val2
,所以对于GET接口的测试的步骤很简单
valgrind --tool=memcheck --log-file=./valgrind_report.log --leak-check=full --show-reachable=yes --track-origins=yes ./cgi_get_sample
starttime=2017-07-31%2014%3A59%3A31&endtime=2017-07-31%2015%3A59%3A31&id=1024
POST接口的调用方式稍微复杂一些。
export REQUEST_METHOD=POST export CONTENT_LENGTH=381 export CONTENT_TYPE="application/json"
valgrind --tool=memcheck --log-file=./valgrind_report.log --leak-check=full --show-reachable=yes --track-origins=yes ./cgi_post_sample
{"id":1024,"name":"calvin"}
unset REQUEST_METHOD unset CONTENT_LENGTH unset CONTENT_TYPE
最后,贴一个集成POST/GET两种方式的脚本:
#!/bin/bash
# create by calvinshao
if [ $# -lt 3 ]; then
echo "USAGE: $0 CGI_NAME DATA_LEN METHOD"
exit 1
fi
if [ "$3" == "POST" ]; then
#Set Env param
export REQUEST_METHOD=POST
export CONTENT_LENGTH=$2
export CONTENT_TYPE="application/json"
echo "Input JSON format string:"
valgrind --tool=memcheck --log-file=./valgrind_report.log --leak-check=full --show-reachable=yes --track-origins=yes ./$1
else
unset REQUEST_METHOD
unset CONTENT_LENGTH
unset CONTENT_TYPE
valgrind --tool=memcheck --log-file=./valgrind_report.log --leak-check=full --show-reachable=yes --track-origins=yes ./$1
fi
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。