server.c
<pre name="code" class="cpp">#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <signal.h>
#define SERVER_NAME "IAMCAP-SERVER"
#define PROTOCOL "HTTP/1.1"
#define REQUESTLEN 4096
#define RESPONSELEN 1024000
#define LISTENNUM 5
#define TIMELEN 55
#define TEMPLEN 100
#define BUFFERLEN 1024
#define HOMEPATH "/Users/iamcap/http/showhttp/"
static char* add_header(int , char *, char *, off_t , char *, int );
void parsedata(char*,int);
int main(int argc, char **argv){
if(argc <=2){
printf("usage: %s ip_address port_number\n", (argv[0]));
return 1;
}
const char *ip = argv[1];
int port = atoi(argv[2]);
//initialize the struct
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
//reuse the port
int sock = socket(PF_INET, SOCK_STREAM, 0);
assert( sock >= 0);
int opt = 1;
setsockopt(sock, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt));
int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
printf("listening ...\n");
ret = listen(sock, LISTENNUM);
assert(ret != -1);
fd_set fp_socketselect;
FD_ZERO(&fp_socketselect);
FD_SET(sock,&fp_socketselect);
int max_fp = sock;
struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);
int temp;
int fdarr[65535];
fdarr[0] = sock;
printf("------>>%d\n",fdarr[0]);
int boundcount = 1;
signal(SIGCHLD,SIG_IGN);
while(1){
printf("i am coming to accept\n");
temp = accept(sock,(struct sockaddr*)&client,&client_addrlength);
printf("connect = %d",temp);
max_fp = max_fp > temp ? max_fp : temp;
fdarr[boundcount++]=temp;
FD_SET(temp, &fp_socketselect);
int num = select(max_fp+1,&fp_socketselect,NULL,NULL,NULL);
//return the number which suit to the rules
printf("num = %d\n",num);
printf("boundcount = %d",boundcount);
if(num > 0){
int i = 0;
printf("polling..\n");
while(i++ < boundcount )
{
FD_SET(fdarr[i],&fp_socketselect);
if(FD_ISSET(fdarr[i],&fp_socketselect)){
if(fdarr[i] == sock){
temp = accept(sock,(struct sockaddr*)&client,&client_addrlength);
max_fp = max_fp > temp ? max_fp : temp;
fdarr[boundcount++]=temp;
FD_SET(temp, &fp_socketselect);
printf("\nconnected with ip: %s and port: %d\n", inet_ntoa(client.sin_addr),ntohs(client.sin_port));
}else if(fdarr[i]>3){
char recvdata[REQUESTLEN];
memset(recvdata,'\0',REQUESTLEN);
int ret = recv(fdarr[i],recvdata,REQUESTLEN-1,0);
printf("\n%s\n", recvdata);
pid_t pid = fork();
if(-1 == pid){
printf("fork() is wrong!!!\n");
}else if(0 == pid){
parsedata(recvdata,fdarr[i]);
break;
}else{
close(fdarr[i]);
}
}
}
}
}else if(0==num){
printf("time out \n");
}else{
printf("something wrong\n");
}
}
close(sock);
return 0;
}
// send header to the browser
static char* add_header(int status, char *title, char *mime_type, off_t length, char *buffer , int buffersize)
{
char temp[TEMPLEN];
memset(buffer, 0, sizeof(buffersize));
sprintf(temp, "%s %d %s\r\n", PROTOCOL, status, title);
strcat(buffer, temp);
sprintf(temp, "Server: %s\r\n", SERVER_NAME);
strcat(buffer, temp);
sprintf(temp, "Connection: Keep-Alive\r\n");
strcat(buffer, temp);
sprintf(temp, "Content-Type: %s\r\n", mime_type);
strcat(buffer, temp);
sprintf(temp, "Content-Length: %d\r\n", (int)length);
strcat(buffer, temp);
sprintf(temp, "Content-Language: zh-CN\r\n");
strcat(buffer, temp);
strcat(buffer, "\r\n");
return buffer;
}
static char* get_mime_type(char *filename)
{
char *postfix;
postfix = strrchr(filename, '.');
if (!strcasecmp(postfix, ".html") || !strcasecmp(postfix, ".htm")){
return "text/html; charset=UTF-8";
}else if (!strcasecmp(postfix, ".jpg") || !strcasecmp(postfix, ".jpeg")){
return "image/jpeg";
}else{
return "text/plain; charset=UTF-8";
}
}
void parsedata(char *recvdata, int connectfd){
if(chdir(HOMEPATH)<0){
// printf("chdir error\n");
exit(0);
}
char method[BUFFERLEN];
char path[BUFFERLEN];
char protocol[BUFFERLEN];
memset(method,'\0',BUFFERLEN);
memset(path,'\0',BUFFERLEN);
memset(protocol,'\0',BUFFERLEN);
sscanf(recvdata, "%[^ ] %[^ ] %[^ ]", method, path, protocol);
//open file or dir
struct stat property;
stat(path,&property);
if(S_ISDIR(property.st_mode)){
if(0 == strcmp(path,"/")){
if(0 == strcasecmp(method,"GET"))
{
FILE *fp;
if(fp = fopen("index.html","r")){
char head[BUFFERLEN];
memset(head,'\0',BUFFERLEN);
stat(path+1,&property);
stat("index.html",&property);
add_header(200, "OK", "text/html", property.st_size, head, BUFFERLEN);
char temp[RESPONSELEN];
memset(temp,'\0',RESPONSELEN);
strcpy(temp,head);
fread(temp+strlen(head),1,property.st_size,fp);
send(connectfd, temp, strlen(head)+property.st_size,0);
close(connectfd);
}
}else if(0 == strcasecmp(method,"POST")){
char *postemp=strtok(recvdata, "\r\n\r\n");
char *pos = postemp;
while (postemp) {
postemp=strtok(NULL, "\r\n\r\n");
if(postemp){
pos = postemp;
}
}
char mes[500]={"<html><script>alert(\""};
strcat(mes,pos);
strcat(mes,"\");</script></html>");
char head[BUFFERLEN];
memset(head,'\0',BUFFERLEN);
add_header(200, "OK", "text/html", strlen(mes), head, BUFFERLEN);
char temp[RESPONSELEN];
memset(temp,'\0',RESPONSELEN);
strcpy(temp,head);
strcat(temp,mes);
send(connectfd, temp, strlen(head)+strlen(mes),0);
close(connectfd);
}
}else{ //other dir
exit(0);
}
}else{ //if it is a file
if(0 == strcasecmp(method,"GET")){
FILE *fp;
if(fp = fopen(path+1,"rb")){
char head[BUFFERLEN];
memset(head,'\0',BUFFERLEN);
stat(path+1,&property);
add_header(200, "OK", get_mime_type((path + 1)), property.st_size, head, BUFFERLEN);
char temp[RESPONSELEN];
memset(temp,'\0',RESPONSELEN);
strcpy(temp,head);
fread(temp+strlen(head),1,property.st_size,fp);
send(connectfd, temp, strlen(head)+property.st_size,0);
close(connectfd);
}
}else if(0 == strcasecmp(method,"POST")){
}else if(0 == strcasecmp(method,"HEAD")){
}else if(0 == strcasecmp(method,"PUT")){
}else{
exit(0);
}
}
}
index.html
<html>
<script type="text/javascript">
<span style="white-space:pre"> </span>function mdo(){
<span style="white-space:pre"> </span>var flag = confirm("Do you want to download ?");
<span style="white-space:pre"> </span>if(flag == true){
<span style="white-space:pre"> </span>var x = document.getElementById('mydo').href = "1.zip";
<span style="white-space:pre"> </span>alert("you confirmed");
<span style="white-space:pre"> </span>}else{
<span style="white-space:pre"> </span>alert("you canceled");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
</script>
<span style="white-space:pre"> </span><body>
<span style="white-space:pre"> </span><H1>this is a page</H1>
<span style="white-space:pre"> </span><img src="mypic.jpg" />
<span style="white-space:pre"> </span><form method="post">
<span style="white-space:pre"> </span><input id="firstid" type="text" name="first" />
<span style="white-space:pre"> </span><input id="secondid" type="text" name="second"/>
<span style="white-space:pre"> </span><input id="sumid" type="text" name="sum" readonly="true">
<span style="white-space:pre"> </span><input type="submit" value="compute" οnclick="location.reload(true)">
<span style="white-space:pre"> </span></form>
<span style="white-space:pre"> </span><a id="mydo" href="" οnclick="mdo()" >click to download zip</a>
<span style="white-space:pre"> </span></body>
</html>
加入了一个POST请求,并将请求数据用alert显示出来。带了文件下载功能,附带了CGI的处理,就将输入的数传给服务器,服务器执行一段shell脚本,然后将数据打包回馈给浏览器,在代码中,我使用了中间文件存储处理生成的结果,后来我发现可以利用更好的方法利用 popen函数来处理,自己改动吧!
CGI执行的代码:
#!/bin/sh
echo "<HTML><HEAD>"
echo "<TITLE>bigger or not</TITLE>"
echo "</HEAD><BODY>"
if [ $1 -gt 0 ]
then echo "<script>alert(\"$1 > 0\");</script>"
else
echo "<script>alert(\"$1 <= 0\");</script>"
fi
echo "</BODY></HTML>"