深入解读Althttpd: 第二部分

在第一部分, 已经了解大概, 接下来, 从源码层次来理解一下吧.

althttpd.c

关于具体源码, 由于 C 语言, 所以打算从宏定义/静态变量/静态函数入手, 再从 main 函数进行流程解读. 对于文件头部一些注释, 暂且不单独翻译, 大部分同 md 文档一致 .

宏定义

  • DEFAULT_PORT http 服务默认监听端口;
  • MAX_CONTENT_LENGTH http 请求内容最大长度(报文主体);
  • MAX_CPU 每秒 CPU 周期最大值.

静态变量

  • zRoot 站点根目录, 定义 static char *zRoot = 0 ;
  • zTmpNam 临时文件名称, 定义 static char *zTmpNam = 0 ;
  • zTmpNamBuf 临时文件名缓冲区, 定义 static char zTmpNamBuf[500] ;
  • zProtocol 浏览器(客户端)使用的协议, 定义 static char *zProtocol = 0 ;
  • zMethod 客户端请求类型, 定义 static char *zMethod = 0 ;
  • zScript 脚本路径, 定义 static char *zScript = 0 ;
  • zRealScript 实际脚本路径, 如果没有, 将追加 /index.html , 定义 static char *zRealScript = 0 ;
  • zHome 包含脚本的根目录, 定义 static char *zHome = 0 ;
  • zQueryString 查询字符串, 定义 static char *zQueryString = 0 ;
  • zFile 执行脚本文件名称, 定义 static char *zFile = 0 ;
  • lenFile 执行脚本文件名称长度, 定义 static int lenFile = 0 ;
  • zDir 包含脚本当前目录, 定义 static char *zDir = 0 ;
  • zPathInfo 脚本路径的部分, 定义 static char *zPathInfo = 0 ;
  • zAgent 客户端类型, 定义 static char *zAgent = 0 ;
  • zServerName 站点域名, 定义 static char *zServerName = 0 ;
  • zServerPort 站点端口, 定义 static char *zServerPort = 0 ;
  • zCookie 客户端请求携带的 cookie, 定义 static char *zCookie = 0 ;
  • zHttpHost 请求主机, 定义 static char *zHttpHost = 0 ;
  • zRealPort 守护模式运行实际 TCP 端口, 定义 static char *zRealPort = 0 ;
  • zRemoteAddr 客户端的 IP 地址, 定义 static char *zRemoteAddr = 0 ;
  • zReferer 当前请求的来源请求, 定义 static char *zReferer = 0 ;
  • zAccept 请求接收类型, 定义 static char *zAccept = 0 ;
  • zAcceptEncoding 请求接收编码, 压缩或默认, 定义 static char *zAcceptEncoding =0 ;
  • zContentLength 请求主体长度, 定义 static char *zContentLength = 0 ;
  • zContentType 请求主体类型, 定义 static char *zContentType = 0 ;
  • zQuerySuffix 查询参数后缀(主要是第一个 ? 后面的字符串), 定义 static char *zQuerySuffix = 0 ;
  • zAuthType 请求认证类型, 基础或摘要认证, 定义 static char *zAuthType = 0 ;
  • zAuthArg 请求认证参数, 定义 static char *zAuthArg = 0 ;
  • zRemoteUser 通过认证模块发送的用户, 定义 static char *zRemoteUser = 0 ;
  • zIfNoneMatch 未匹配的请求头值, 定义 static char *zIfNoneMatch= 0 ;
  • zIfModifiedSince 未变更的请求头值, 定义 static char *zIfModifiedSince=0 ;
  • nIn 接收字符数量, 定义 static int nIn = 0 ;
  • nOut 输出字符数量, 定义 static int nOut = 0 ;
  • zReplyStatus 响应状态, 定义 static char zReplyStatus[4] ;
  • statusSent 是否已发送响应状态, 定义 static int statusSent = 0 ;
  • zLogFile 日志文件, 定义 static char *zLogFile = 0 ;
  • debugFlag 调试标识, 定义 static int debugFlag = 0 ;
  • beginTime 当前进程启动时间, 定义 static struct timeval beginTime ;
  • closeConnection 是否已向连接发送关闭响应, 定义 static int closeConnection = 0 ;
  • nRequest 进程中请求的数量, 定义 static int nRequest = 0 ;
  • omitLog 忽略日志标识, 定义 static int omitLog = 0 ;
  • useHttps 使用 https 标识, 定义 static int useHttps = 0 ;
  • zHttp http 类型, httphttps , 定义 static char *zHttp = "http" ;
  • useTimeout 使用超时标识, 定义 static int useTimeout = 1 ;
  • standalone 独立服务运行标识, 定义 static int standalone = 0 ;
  • ipv6Only 仅使用 IPv6 模式标识, 定义 static int ipv6Only = 0 ;
  • ipv4Only 仅使用 IPv4 模式标识, 定义 static int ipv4Only = 0 ;
  • priorSelf 当前进程占用资源情况, 定义 static struct rusage priorSelf ;
  • priorChild 子进程占用资源情况, 定义 static struct rusage priorChild;
  • mxAge 缓存控制最大存活时间, 定义 static int mxAge = 120;
  • default_path 默认环境目录, 定义 static char *default_path = "/bin:/usr/bin" ;
  • zScgi SCGI 环境变量值, 定义 static char *zScgi = 0 ;
  • rangeStart 请求主体的开始, 定义 static int rangeStart = 0 ;
  • rangeEnd 请求主体的结束, 定义 static int rangeEnd = 0 ;
  • maxCpu 每秒最大 CPU 时间, 定义 static int maxCpu = MAX_CPU ;
  • cgienv CGI 环境变量:
static struct {
   
  char *zEnvName; // 变量名称
  char **pzEnvValue; // 变量值
} cgienv[] = {
   
  {
    "CONTENT_LENGTH",          &zContentLength }, /* Must be first for SCGI */
  {
    "AUTH_TYPE",                   &zAuthType },
  {
    "AUTH_CONTENT",                &zAuthArg },
  {
    "CONTENT_TYPE",                &zContentType },
  {
    "DOCUMENT_ROOT",               &zHome },
  {
    "HTTP_ACCEPT",                 &zAccept },
  {
    "HTTP_ACCEPT_ENCODING",        &zAcceptEncoding },
  {
    "HTTP_COOKIE",                 &zCookie },
  {
    "HTTP_HOST",                   &zHttpHost },
  {
    "HTTP_IF_MODIFIED_SINCE",      &zIfModifiedSince },
  {
    "HTTP_IF_NONE_MATCH",          &zIfNoneMatch },
  {
    "HTTP_REFERER",                &zReferer },
  {
    "HTTP_USER_AGENT",             &zAgent },
  {
    "PATH",                        &default_path },
  {
    "PATH_INFO",                   &zPathInfo },
  {
    "QUERY_STRING",                &zQueryString },
  {
    "REMOTE_ADDR",                 &zRemoteAddr },
  {
    "REQUEST_METHOD",              &zMethod },
  {
    "REQUEST_URI",                 &zScript },
  {
    "REMOTE_USER",                 &zRemoteUser },
  {
    "SCGI",                        &zScgi },
  {
    "SCRIPT_DIRECTORY",            &zDir },
  {
    "SCRIPT_FILENAME",             &zFile },
  {
    "SCRIPT_NAME",                 &zRealScript },
  {
    "SERVER_NAME",                 &zServerName },
  {
    "SERVER_PORT",                 &zServerPort },
  {
    "SERVER_PROTOCOL",             &zProtocol },
}

静态函数

  • Escape 规避双引号干扰, 原型 static char *Escape(char *z) ;
static char *Escape(char *z){
   
  size_t i, j; // 循环计数控制循环变量, j为叠加双引号时的计数
  size_t n; // 双引号计数变量
  char c; // 循环中当前字符临时变量
  char *zOut; // 加工处理后的字符串
  /**
   * 截断字符串, 如果出现双引号的情况, 或越界退出
   * 如果出现双引号, 那么退出循环时, c为双引号, 继续后续处理
   * 反之, c为越界获取, 异常字符, 和0对等(待加强理解, 未申明空间为0?), 直接返回当前传入字符串即可
   */
  for(i=0; (c=z[i])!=0 && c!='"'; i++){
   }
  if( c==0 ) return z;
  // 已经检测到有个双引号, 所以这里初始值为1
  n = 1;
  // 统计双引号出现次数 从上次循环截断时继续往后查找, 处理非常漂亮
  for(i++; (c=z[i])!=0; i++){
    if( c=='"' ) n++; }
  // 动态分配空间(从堆中分配) i为当前字符总量, n为需要增加双引号的数量, 1为字符串终止符\0
  zOut = malloc( i+n+1 );
  if( zOut==0 ) return "";
  for(i=j=0; (c=z[i])!=0; i++){
   
    zOut[j++] = c;
    // 双引号叠加
    if( c=='"' ) zOut[j++] = c;
  }
  // 补充终止符
  zOut[j] = 0;
  return zOut;
}
  • tvms 将时间转化为微秒数, 主要参考 ((long long int)p->tv_sec)*1000000 将秒转为微秒, 然后加上当时的微秒数即可, 原型 static long long int tvms(struct timeval *p) ;
  • MakeLogEntry 创建日志入口, 如果连接关闭, 就结束这个进程, 反之, 正常返回. 原型 static void MakeLogEntry(int exitCode, int lineNum) ;
static void MakeLogEntry(int exitCode, int lineNum){
   
  FILE *log; // 日志文件指针
  // 如果指定了临时文件名, 这里需做删除处理
  if( zTmpNam ) unlink(zTmpNam);
  // 存在日志文件名称, 且不忽略日志
  if( zLogFile && !omitLog ){
   
    struct timeval now; // 当前时间 秒/微秒
    struct tm *pTm; // 可分解时间类型
    struct rusage self, children; // 资源利用统计结构 当前进程 和子进程
    int waitStatus; // 等待子进程状态描述
    char *zRM = zRemoteUser ? zRemoteUser : "";
    char *zFilename; // 保存处理后日志文件名
    size_t sz; // 保存 strftime 返回
    char zDate[200]; // 格式化后的时间(指定形式)
    char zExpLogFile[500]; // 导出日志文件的名称
	// 转化宏定义 zScript/zRealScript/zRemoteAddr/zHttpHost/zReferer/zAgent if 0, then ""
    if( zScript==0 ) zScript = "";
    // ...
    if( zAgent==0 ) zAgent = "";
    gettimeofday(&now, 0); // 获取当前时间
    pTm = localtime(&now.tv_sec); // 将当前时间秒数转为本地可分解时间类型
    // 格式化时间, 根据指定格式处理可分解时间转存最大长度到指定字符串
    // strftime(target, max_length, format, tm_struct)
    // 如果产生的字符串小于 max_length 个字符(包括空结束字符), 则会返回复制到 target 中的字符总数(不包括空结束字符), 否则返回零
    strftime(zDate, sizeof(zDate), "%Y-%m-%d %H:%M:%S", pTm);
    // 进行时间格式化处理, 如果其中包含有时间形式
    sz = strftime
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值