文章目录
向浏览器打印信息
源码
#include "cgic.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int cgiMain(){
//打印HTTP协议请求头
cgiHeaderContentType("text/html");
fprintf(cgiOut,"<html><HEAD>\n");
fprintf(cgiOut,"<TITLE>Printf information to browser</TITLE></HEAD>\n");
fprintf(cgiOut,"<BODY><H1>Hello CGIC</H1><BODY>\n");
fprintf(cgiOut,"</HTML>\n");
return 0;
}
Makefile
SOURCE := cgic_print.c cgic.c
OBJ := cgic_print.o cgic.o
TARGET :=cgic_print
CC := gcc
CROSS_COMPILE :=
LIBS :=
LDFLAGS :=
INCLUDE := -I .
DEFINES :=
CFLAGS :=-Wall -g $(INCLUDE) $(DEFINES)
OUTPUT := /home/jacky/www/cgi
HTML := index.html
www := /home/jacky/www/www
all:$(TARGET)
$(TARGET):$(OBJ)
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^
cp $@ $(OUTPUT)
%.o:%.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
.PHONY:clean
clean:
rm -f $(TARGET) *.o
测试
启动服务器
浏览器访问
获取请求参数
如果不使用CGIC库,要获取请求参数:
用getenv从环境变量中获取QueryString:char* queryString=getenv("QUERY_STRING");
char* qs=getenv("QUERY_STRING");
//使用sscanf函数,可以从字符串中进行查找字符
使用cgic库函数cgiFormString
:
char pwd[128]={0};
cgiFormString("pwd",pwd,sizeof(pwd)-1);
重定位网页
调用cgic库函数
void cgiHeaderLocation(char* redirectUrl);
重定向到redirectUrl指定的地址。
cgiHeaderLocation("http://www.baidu.com");
就会直接跳转到百度网页
获取GET请求字符串
GET请求就是我们在浏览器地址栏输入URL时发送请求的方式,或者我们在HTML表单中定义一个表单(form)时,把METHOD属性设置为GET
工作时的工作方式;
GET请求字符串就是跟在URL后面以问号?
开始的字符串,但不包括问号,如果有多个值,则使用&
进行分割。比如http:/127.0.0.1/cgi-bin/1.cgi?uer=xxx&pwd=xxx
在上面的例子中?
后面的就是GET请求的字符串。
在进入我们编写的代码前,CGIC库通过环境变量已经获取到了这个字符串,而我们只需要调用函数接口,就可以直接获得。因此我们需要提前声明该函数
extern char* cgiQueryString;
HTML
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8">
<title>CGIC-GET</title>
</head>
<body>
<form action="cgi-bin/cgic_get" method="get" enctype="multipart/form-data" target="_blank">
<input type="text" autocomplete="off" name="user" value="" placeholder="用户名" required/>
<br>
<input type="password" autocomplete="off" name="pwd" placeholder="密码" required maxlength="32"/>
<br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
源码
#include "cgic.h"
#include<stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//声明获取QUERY_STRING环境变量值函数
extern char* cgiQueryString;
int cgiMain(){
char user[128];
char pwd[128];
//打印请求信息头
cgiHeaderContentType("text/html");
fprintf(cgiOut,"<HTML><HEAD>\n");
fprintf(cgiOut,"<TITLE>GET TEST</TITLE></HEAD>\n");
fprintf(cgiOut,"<BODY>");
cgiFormString("user",user,sizeof(user)-1);
cgiFormString("pwd",pwd,sizeof(pwd)-1);
fprintf(cgiOut,"<H1>%s</H1>",cgiQueryString);
fprintf(cgiOut,"<br>");
fprintf(cgiOut,"<h2>%s</h2>",user);
fprintf(cgiOut,"<br>");
fprintf(cgiOut,"<h2>%s</h2>",pwd);
fprintf(cgiOut,"</BODY>\n");
fprintf(cgiOut,"</HTML>\n");
return 0;
}
Makefile
SOURCE := cgic_get.c cgic.c
OBJ := cgic_get.o cgic.o
TARGET :=cgic_get
CC := gcc
CROSS_COMPILE :=
LIBS :=
LDFLAGS :=
INCLUDE := -I .
DEFINES :=
CFLAGS :=-Wall -g $(INCLUDE) $(DEFINES)
OUTPUT := /home/jacky/www/cgi
HTML := index.html
www := /home/jacky/www/www
all:$(TARGET)
$(TARGET):$(OBJ)
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^
cp $@ $(OUTPUT)
cp $(HTML) $(www)
%.o:%.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
.PHONY:clean
clean:
rm -f $(TARGET) *.o
测试
启动程序
浏览器访问
测试
Get方式提交信息
获取POST请求字符串
相信到现在,大家已经对POST和GET方式请求服务器数据已经非常清晰了,这里我还是进行说明,POST传递请求参数不会放在URL
中,而是放在请求信息
中,所以不会有大小的限制,而且相对安全。下面我们以POST的方式来传递表单信息。
HTML
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8">
<title>CGIC-GET</title>
</head>
<body>
<form action="cgi-bin/cgic_post" method="post" enctype="multipart/form-data" target="_blank">
<input type="text" autocomplete="off" name="user" value="" placeholder="用户名" required/>
<br>
<input type="password" autocomplete="off" name="pwd" placeholder="密码" required maxlength="32"/>
<br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
源码
#include "cgic.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern char* cgiQueryString;
int cgiMain(){
char user[128];
char pwd[128];
//打印HTTP协议头
cgiHeaderContentType("text/html");
fprintf(cgiOut,"<html><head>\n");
fprintf(cgiOut,"<title>POST TEST</title></head>\n");
fprintf(cgiOut,"<body>");
fprintf(cgiOut,"<h1>%s</h1>",cgiQueryString);
cgiFormString("user",user,sizeof(user)-1);
cgiFormString("pwd",pwd,sizeof(pwd)-1);
fprintf(cgiOut,"<br>");
fprintf(cgiOut,"<h2>%s</h2>",user);
fprintf(cgiOut,"<br>");
fprintf(cgiOut,"<h2>%s</h2>",pwd);
fprintf(cgiOut,"</body>\n");
fprintf(cgiOut,"</html>\n");
return 0;
}
Makefile
SOURCE := cgic_post.c cgic.c
OBJ := cgic_post.o cgic.o
TARGET :=cgic_post
CC := gcc
CROSS_COMPILE :=
LIBS :=
LDFLAGS :=
INCLUDE := -I .
DEFINES :=
CFLAGS :=-Wall -g $(INCLUDE) $(DEFINES)
OUTPUT := /home/jacky/www/cgi
HTML := index.html
www := /home/jacky/www/www
all:$(TARGET)
$(TARGET):$(OBJ)
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^
cp $@ $(OUTPUT)
cp $(HTML) $(www)
%.o:%.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
.PHONY:clean
clean:
rm -f $(TARGET) *.o
测试
浏览器访问
CGIC反转义
在前面的GET请求中,已经介绍过反转义是什么了。这里在详细介绍并告诉大家如何操作
浏览器在发送GET请求时,会把请求字符串进行转义操作;
比如我们在地址栏输入
http://localhost/~Jack/cgi-bin/out.cgi?it's me
浏览器就会自动转义为
http://localhost/~Jack/cgi-bin/out.cgi?it%27s%20me
那么通过CGIC,我们可以把这些转义后的字符还原为本来的输入,这就是反转义
操作
第一步:
在cgic.c
中找到该函数的声明,注意不是定义
去掉这个static
关键字
第二步:
在第一步函数声明上方有一个枚举
将这几行语句复制到cgic.h头文件中,并在这里将它注释掉
第三步:
下面我们就可以愉快的使用该函数了
extern cgiUnescapeResultType cgiUnescapeChars(char **sp,char *cp ,int len);
HTML
<!DOCTYPE html>
<html lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8">
<title>CGIC-GET</title>
</head>
<body>
<form action="cgi-bin/cgic_unescape" method="GET" enctype="multipart/form-data" target="_blank">
<input type="text" autocomplete="off" name="user" value="" placeholder="信息" required/>
<br>
<input type="submit" name="submit" value="submit">
</form>
</body>
</html>
源码
#include "cgic.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
extern char* cgiQueryString;
extern cgiUnescapeResultType cgiUnescapeChars(char **sp,char *cp,int len);
int cgiMain(){
//打印HTTP协议信息头
char *buffer;
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n");
fprintf(cgiOut, "<BODY>");
cgiUnescapeChars(&buffer,cgiQueryString,strlen(cgiQueryString));
fprintf(cgiOut, "<H1>%s</H1>",buffer);
fprintf(cgiOut, "</BODY>\n");
fprintf(cgiOut, "</HTML>\n");
//释放掉由CGIC库函数在堆上申请的空间
free(buffer);
return 0;
}
Makefile
SOURCE := cgic_unescape.c cgic.c
OBJ := cgic_unescape.o cgic.o
TARGET :=cgic_unescape
CC := gcc
CROSS_COMPILE :=
LIBS :=
LDFLAGS :=
INCLUDE := -I .
DEFINES :=
CFLAGS :=-Wall -g $(INCLUDE) $(DEFINES)
OUTPUT := /home/jacky/www/cgi
HTML := index.html
www := /home/jacky/www/www
all:$(TARGET)
$(TARGET):$(OBJ)
$(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^
cp $@ $(OUTPUT)
cp $(HTML) $(www)
%.o:%.c
$(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
.PHONY:clean
clean:
rm -f $(TARGET) *.o
测试
浏览器访问
反转义成功
注意
buffer的存储空间是cgiUnescapeChars帮我们分配的,但是最后是需要我们手动释放的,防止内存泄漏
为什么不得不用hacker的方式来完成该让任务,而CGIC不显示提供?
CGIC 的出发点是,我们平时只需要解析请求中的键值对,比如:”?q=nice&client=IE”,当我们在服务端查询“q”的值时,我们就能得到 “nice”。CGIC有一族函数帮助我们完成这个任务,比如cgiFormString
。在解析这种请求格式的时候,如果我们提供的参数值含有被转义的字符,那么CGIC就会在内部调用cgiUnescapeChars
完成反转义。
但是,有时候我们会发送非常复杂的Get请求字符串,但并不是“键-值”对的格式
。这就需要直接使用cgiUnescapeChars进行反转义了。
例如:假设我们有个服务端cgi程序chat.cgi,这是个网络聊天机器人(也许你可以开发自己的Web版MSN机器人、QQ机器人)。如果我们发送如下请求:
http://127.0.0.1/cgi-bin/chat.cgi?"this is a cgi user"
那么chat.cgi
就会把“this is a cgi user”
当做你对它说的话,经过处理,它会回复一段语句。为了方便,我们并没有写成“键-值”对的形式
。这个时候被我们hack的cgiUnescapeChars就能派上用场了。
浏览器上传文件
在上一个CGIC博客中实现的就是上传文件到BOA,需要的朋友可以去看上一篇博客。