深入解读Althttpd: 第三部分

最后的冲刺.

althttpd.c

静态函数

  • ProcessOneRequest 请求处理过程, 原型 void ProcessOneRequest(int forceClose) ;
void ProcessOneRequest(int forceClose){
   
  int i, j, j0;
  char *z; // 格式化字符串空间
  struct stat statbuf; // 获取到的文件信息
  FILE *in; // 从 CGI 脚本中读取到的文件描述符
#ifdef LOG_HEADER
  FILE *hdrLog = 0; // 记录请求头, 如果定义了 LOG_HEADER 宏
#endif
  char zLine[1000]; // 保存输入行或格式化名称的缓冲区

  // 切换 HTTP 根目录
  if( chdir(zRoot[0] ? zRoot : "/")!=0 ){
   
    char zBuf[1000];
    // getcwd 将当前工作目录的绝对路径复制到参数 buffer 所指的内存空间中
    Malfunction(190, "cannot chdir to [%s] from [%s]", zRoot, getcwd(zBuf,999));
  }
  nRequest++; // request 请求数量统计
  
  // 必须在15s内接受到一个完整的头信息
  signal(SIGALRM, Timeout); // 时钟信号 在Linux系统下, 每一个进程都有惟一的一个定时器, 该定时器提供了以秒为单位的定时功能. 在定时器设置的超时时间到达后, 调用alarm的进程将收到SIGALRM信号
  signal(SIGSEGV, Timeout); // 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据
  signal(SIGPIPE, Timeout); // 管道破裂信号量
  signal(SIGXCPU, Timeout); // 超过CPU时间资源限制
  if( useTimeout ) alarm(15); // 设置定时器
  
  // 从标准输入中读取 请求的第一行, 然后解析出请求类型, 脚本和协议, 如果读取失败, 直接 exit
  if( fgets(zLine,sizeof(zLine),stdin)==0 )exit(0);
  gettimeofday(&beginTime, 0);
  omitLog = 0;
  nIn += strlen(zLine); // 计算有效字符, 不含结束符

  /* Parse the first line of the HTTP request */
  zMethod = StrDup(GetFirstElement(zLine,&z));
  zRealScript = zScript = StrDup(GetFirstElement(z,&z));
  zProtocol = StrDup(GetFirstElement(z,&z));
  if( zProtocol==0 || strncmp(zProtocol,"HTTP/",5)!=0 || strlen(zProtocol)!=8 ){
   
    StartResponse("400 Bad Request");
    nOut += printf(
      "Content-type: text/plain; charset=utf-8\r\n"
      "\r\n"
      "This server does not understand the requested protocol\n"
    );
    MakeLogEntry(0, 200); // 请求协议异常
    exit(0);
  }
  if( zScript[0]!='/' ) NotFound(210);
  while( zScript[1]=='/' ){
    // 移除 头部 连续 /
    zScript++;
    zRealScript++;
  }
  if( forceClose ){
    // 强制关闭连接条件
    closeConnection = 1;
  }else if( zProtocol[5]<'1' || zProtocol[7]<'1' ){
    // 未看懂
    closeConnection = 1;
  }
  
  // 只支持 GET/POST/HEAD请求的简单服务
  if( strcmp(zMethod,"GET")!=0 && strcmp(zMethod,"POST")!=0
       && strcmp(zMethod,"HEAD")!=0 ){
   
    StartResponse("501 Not Implemented");
    nOut += printf(
      "Content-type: text/plain; charset=utf-8\r\n"
      "\r\n"
      "The %s method is not implemented on this server.\n",
      zMethod);
    MakeLogEntry(0, 220);
    exit(0);
  }
  
// 打开请求头记录文件 如果设置了的话 
#ifdef LOG_HEADER
  if( zLogFile
   && strstr(zScript,"FullHeaderLog")!=0
   && strlen(zLogFile)<sizeof(zLine)-50
  ){
   
    sprintf(zLine, "%s-hdr", zLogFile);
    hdrLog = fopen(zLine, "wb");
  }
#endif

  // 从标准输入获取的第一行中可选字段
  zCookie = 0;
  zAuthType = 0;
  zRemoteUser = 0;
  zReferer = 0;
  zIfNoneMatch = 0;
  zIfModifiedSince = 0;
  rangeEnd = 0;
  while( fgets(zLine,sizeof(zLine),stdin) ){
   
    char *zFieldName;
    char *zVal;

#ifdef LOG_HEADER
    if( hdrLog ) fprintf(hdrLog, "%s", zLine); // 请求头日志
#endif
    nIn += strlen(zLine);
    zFieldName = GetFirstElement(zLine,&zVal);
    if( zFieldName==0 || *zFieldName==0 ) break;
    RemoveNewline(zVal);
    if( strcasecmp(zFieldName,"User-Agent:")==0 ){
   
      zAgent = StrDup(zVal);
    }else if( strcasecmp(zFieldName,"Accept:")==0 ){
   
      zAccept = StrDup(zVal);
    }else if( strcasecmp(zFieldName,"Accept-Encoding:")==0 ){
   
      zAcceptEncoding = StrDup(zVal);
    }else if( strcasecmp(zFieldName,"Content-length:")==0 ){
   
      zContentLength = StrDup(zVal);
    }else if( strcasecmp(zFieldName,"Content-type:")==0 ){
   
      zContentType = StrDup(zVal);
    }else if( strcasecmp(zFieldName,"Referer:")==0 ){
   
      zReferer = StrDup(zVal);
      // 指定 Referer
      if( strstr(zVal, "devids.net/")!=0 ){
    
        zReferer = "devids.net.smut";
        Forbidden(230);
      }
    }else if( strcasecmp(zFieldName,"Cookie:")==0 ){
   
      zCookie = StrAppend(zCookie,"; ",zVal); // 多 cookie, 所以采用 append 模式
    }else if( strcasecmp(zFieldName,"Connection:")==0 ){
   
      if( strcasecmp(zVal,"close")==0 ){
   
        closeConnection = 1;
      }else if( !forceClose && strcasecmp(zVal, "keep-alive")==0 ){
   
        closeConnection = 0;
      }
    }else if( strcasecmp(zFieldName,"Host:")==0 ){
   
      int inSquare = 0;
      char c;
      if( sanitizeString(zVal) )Forbidden(240); // 非法主机地址
      zHttpHost = StrDup(zVal);
      zServerPort = zServerName = StrDup(zHttpHost);
      while( zServerPort && (c = *zServerPort)!=0
              && (c!=':' || inSquare) ){
   
        if( c=='[' ) inSquare = 1;
        if( c==']' ) inSquare = 0;
        zServerPort++;
      }
      if( zServerPort && *zServerPort ){
   
        *zServerPort = 0;
        zServerPort++;
      }
      if( zRealPort ){
   
        zServerPort = StrDup(zRealPort);
      }
    }else if( 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值