/*
* Software name: mini_httpd
* Version: 1.0
* Description: simple and portable HTTP server
* Features: web page, cgi
* Not implemented: If-Modified-Since, SSL, Basic Auth, Cookies support
* Author: zhukenan <zhekenan@gmail.com>
*/
#define VERSION "1.0" /* 版本号 */
#define BUFSIZE 16*1024 /* 缓存大小 */
#define MAXHEADER 64 /* 允许的最大请求头数目 */
#define MAXARG 64 /* 允许的最大参数数目 */
#define NUM_HANDLER_THREADS 3 /* 处理请求的线程数 */
#include <stdio.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
/*************************************************数据结构********************************************************/
/*
* 连接结构,存储提出请求的client端的socket、
* 请求字符串及其长度、client端的地址及其长度
* 和指向链表中下一个结构的指针
*/
struct connect
{
int fdclient; /* client端的socket文件描述符 */
char buffer[BUFSIZE]; /* 请求字符串 */
int buflen; /* 请求字符串长度 */
struct sockaddr_in clientAddr; /* client端的地址 */
int addrLen; /* client端的地址长度 */
struct connect *next; /* 指向链表中下一个结构的指针 */
};
/*
* 向量结构,用来通过指针和长度表示一个字符串
*/
struct vec
{
int len;
const void *ptr;
};
/*
* 名值对结构,用来表示HTTP请求头和cgi请求参数
*/
struct nv
{
struct vec name;
struct vec value;
};
/*
* 请求结构,存储与请求相关的信息
*/
struct request
{
int reqlen; /* 请求行长度 */
int totlen; /* 请求行+请求头长度 */
struct vec method; /* 请求采用的方法 */
struct vec url; /* 请求的url,包括uri和参数 */
struct vec proto; /* 请求的协议 */
struct vec uri; /* 请求的uri */
struct vec argstr; /* 请求的url中‘?’后面的字符串 */
struct nv arg[MAXARG]; /* cgi请求的参数数组 */
int numOfArg; /* cgi请求的参数个数 */
struct nv header[MAXHEADER]; /* 请求头数组 */
int numOfHeader; /* 请求头个数 */
/* 根据请求头进行设置,用来进行授权检测扩展或设置环境变量 */
struct vec auth; /* Auth: */
struct vec cookie; /* Cookie: */
struct vec clength; /* Content-Length: */
struct vec ctype; /* Content-Type: */
struct vec location; /* Location: */
struct vec status; /* Status: */
time_t ims; /* If-Modified-Since: */
};
/*
* HTTP请求头回调函数
*/
typedef void (*hcb_t)(const struct nv *header, struct request *reqp);
/*************************************************全局变量********************************************************/
int sockPort = 80; /* 服务器端口号 */
const char *docroot = "."; /* 访问根目录,初时化为当前工作目录 */
int num_of_connect = 0; /* 连接数 */
struct connect *chead; /* 连接链表的首 */
struct connect *ctail; /* 连接链表的尾 */
pthread_mutex_t connect_mutex; /* 连接链表的互斥量 */
pthread_mutex_t condition_mutex; /* 条件变量的互斥量 */
pthread_cond_t got_request = PTHREAD_COND_INITIALIZER; /* 程序的全局条件变量 */
int readPortOfPipeIsClosed = 0;
char *path_php = "/root/bin/php/bin/php";
/*************************************************方法函数********************************************************/
/*
* 在分析http请求时(函数parseRequest),调用的回调函数,对每
* 个请求头调用该回调函数,设置request的相应的成员变量
*/
void
cbheader(const struct nv *header, struct request *reqp)
{
struct vec auth = {13, "Authorization"},
cookie = {6, "Cookie"},
cl = {14, "Content-Length"},
loc = {8, "Location"},
status = {6, "Status"},
ims = {18, "If-Modified-Since:"},
ct = {12, "Content-Type"};
if (vcasecmp(&header->name, &auth))
reqp->auth = header->value;
else if (vcasecmp(&header->name, &cookie))
reqp->cookie = header->value;
else if (vcasecmp(&header->name, &cl))
reqp->clength = header->value;
else if (vcasecmp(&header->name, &ct))
reqp->ctype = header->value;
else if (vcasecmp(&header->name, &loc))
reqp->location = header->value;
else if (vcasecmp(&header->name, &status))
reqp->status = header->value;
/*else if (vcasecmp(&header->name, &ims))
reqp->ims = datetosec(&header->value);*/
}
/*
* 根据存储着数字信息的vec返回一个int型数据
*/
int
vtoint(const struct vec *v)
{
int i, n;
for (i = n = 0; i < v->len; i++)
{
n *= 10;
n += ((char *) v->ptr)[i] - '0';
}
return (n);
}
/*
* 显示出错信息
*/
void
showError(char *message)
{
printf("%s\n", message);
fflush(stdout);
}
/*
* 比较两个vec是否相等
*/
int
vcasecmp(struct vec *v1, const struct vec *v2)
{
char *s1;
char *s2;
char *end;
int equal = 0;
if (v1->len == v2->len)
{
for (s1 = (char*)v1->ptr, s2 = (char *)v2->ptr, end = s1 + v1->len; s1 < end; s1++, s2++)
{
if (tolower(*s1) != tolower(*s2))
{
break;
}
}
if (s1 == end)
{
equal++;
}
}
return (equal);
}
/*
* 发送响应头,包括要给出mime类型
*/
int
sendheaders(struct request *reqp, int fdclient)
{
int i;
int n;
char headers[2048];
char *mime = "text/plain";
struct vec tmpv;
struct
{
struct vec v;
char *mime;
} tab[] = {
{{5, ".html"}, "text/html"},
{{4, ".htm"}, "text/html"},
{{4, ".css"}, "text/css"},
{{4, ".gif"}, "image/gif"},
{{4, ".jpg"}, "image/jpeg"},
{{5, ".jpeg"}, "image/jpeg"},
{{4, ".png"}, "image/png"},
{{4, ".mpg"}, "video/mpeg"},
{{4, ".asf"}, "video/x-ms-asf"},
{{4, ".avi"}, "video/x-msvideo"},
{{4, ".bin"}, "application/octet-stream"},
{{4, ".bmp"}, "image/bmp"},
{{4, ".doc"}, "application/msword"},
{{4, ".exe"}, "application/octet-stream"},
{{4, ".zip"}, "application/zip"},
};
/* 判断mime类型 */
for (i = 0; i < (int)(sizeof(tab)/sizeof(tab[0])); i++)
{
if (reqp->uri.len <= tab[i].v.len)
{
continue;
}
tmpv.ptr = (char *)reqp->uri.ptr + reqp->uri.len-tab[i].v.len;
tmpv.len = tab[i].v.len;
if(vcasecmp(&tmpv, &tab[i].v) == 1)
{
mime = tab[i].mime;
break;
}
}
n = snprintf(headers, sizeof(headers),
"HTTP/1.0 200 OK\r\n"
"Content-type: %s\r\n"
"\r\n", mime);
/* 发送响应头 */
if(send(fdclient, headers, n, 0) == -1)
{
showError("sendheaders : send");
return -1;
}
return 0;
}
/*
* 发送错误信息
*/
int
sendError(int fdclient, int status, const char *descr, const char *headers, const char *fmt, ...)
{
char msg[512];
va_list ap;
int n;
n = snprintf(msg, sizeof(msg), "HTTP/1.0 %d %s\r\n%s\r\n\r\n", status, descr, headers);
/* 可变参数的用法 */
va_start(ap, fmt);
n += vsnprintf(msg + n, sizeof(msg) - n, fmt, ap);
va_end(ap);
if(send(fdclient, msg, n, 0) == -1)
{
showError("sendError : send");
return -1;
}
return 0;
}
/*
* 处理页面请求
*/
int
dealPage(struct request *reqp, int fdclient)
{
char file[BUFSIZE];
FILE *fpfile;
FILE *fpsock;
int ch;
struct stat filestate;
strcpy(file, docroot);
strncat(file, reqp->uri.ptr, reqp->uri.len);
/* 文件不存在 */
if (stat(file, &filestate) != 0)
{
if(sendError(fdclient, 404, "Not Found", "", "Not Found") == -1)
{
showError("dealPage : sendError");
return -1;
}
}
/* 禁止访问文件夹 */
else if (filestate.st_mode & S_IFDIR)
{
if(sendError(fdclient, 403, "Forbidden", "", "Directory listing denied") == -1)
{
showError("dealPage : sendError");
return -1;
}
}
/* 正常访问文件 */
else if((fpfile = fopen(file, "r")) != NULL)
{
if((fpsock = fdopen(fdclient, "w")) != NULL)
{
if(sendheaders(reqp, fdclient) == -1)
{
showError("dealPage : sendheaders");
return -1;
}
while( (ch = getc(fpfile) ) != EOF )
{
putc(ch, fpsock);
}
fclose(fpfile);
fclose(fpsock);
}
else
{
mini_httpd(php).rar_mini_httpd.rar_site:www.pudn.com
版权申诉
36 浏览量
2022-09-19
13:11:53
上传
评论
收藏 11KB RAR 举报
APei
- 粉丝: 63
- 资源: 1万+
最新资源
- 当涉及到数据库的资源介绍时,以下是一个约500字的概述: 数据库是现代信息技术中不可或缺的核心组件,它承载着组织内部的关键数据
- 自用 3~9 所有自用整理出来时的数据和截图 后台配置、业务操作等
- 基于matlab实现App Designer工具制作而成的一款集音频采集、播放、时域频域分析、加噪、滤波
- 基于matlab实现的振动信号的KAISER滤波与频谱分析,可用于加速度传感器信号 (1).rar
- 基于matlab实现MVDR谱估计,用于噪声估计,在手机麦克风降噪上有很广的应用.rar
- 基于matlab实现8个振动信号处理的经典matlab程序,是学习振动信号处理的重要基础知识 程序中的参数可以根据需要更改
- 基于matlab实现 音乐分析 学习matlab的gui功能 帮助学习matlab 信号处理 音乐分析.rar
- pycharm配置python环境
- 基于matlab实现对机械振动信号的预处理,以及滤波,频域变换等.rar
- 基于matlab实现对锅炉主蒸汽温度控制进行预测控制仿真,适用于大延迟系统的Matlab仿真.rar
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈