[项目][WebServer][CGI机制 设计]详细讲解

news2024/11/17 3:06:34

目录

  • 1.何为CGI机制?
  • 2.理解CGI机制
  • 3.CGI接口设计
    • 1.ProcessNonCgi
    • 2.ProcessCgi


1.何为CGI机制?

  • CGI(Common Gateway Interface)是外部应用程序(CGI程序)与WEB服务器之间的接口标准,是在CGI程序和WEB服务器之间传递信息的过程
    请添加图片描述

2.理解CGI机制

  • 真正理解CGI并不简单,先从现象入手
    • 浏览器除了从服务器获得资源(网页、图片、文字等),有时候还能上传一些东西(提交表单、注册用户之类)
    • 目前HttpServer只能进行获得资源,并不能进行资源上传,所以目前HttpServer并不具有交互式功能
    • 为了让网站能够实现交互式,需要使用CGI功能完成
  • 理论上,可以使用任何语言来编写CGI程序
    • 注意:http提供CGI机制,和CGI程序是两码事
      • 如:学校(http)提供教学平台(CGI机制),学生(CGI程序)来学习
  • 实现上理解,首先要理解GET方法和POST方法的区别
    • GET方法从浏览器传参给http服务器时,是将参数跟套URI后面的
      • 如:www.baidu.com/test_cgi?x=100&y=200
      • GET方法,如果没有传参,http按照一般的方式进行,返回资源即可
        • 静态网页、各种资源
      • GET方法,如果有参数传入,http就需要按照CGI方式处理参数,并将执行结果(期望资源)返回给浏览器
    • POST方法从浏览器传参给http服务器时,是将参数放到请求正文的
      • POST方法,一般都需要使用CGI方式来进行处理
  • 什么时候,需要使用CGI来进行数据处理呢?
    • 只要用户有数据上传上来
  • 如何看待CGI程序呢?
    • 子CGI程序的标准输入时浏览器
    • 子CGI程序的标准输出时浏览器
    • 通信细节由http完成
  • 浏览器和Server进行数据交互的本质,就是进程间通信,也是socket通信的本质
    请添加图片描述

3.CGI接口设计

1.ProcessNonCgi

  • 该接口处理静态网页的请求,只需要将静态网页打开即可
int ProcessNonCgi()
{
    _response.fd = open(_request.path.c_str(), O_RDONLY);
    if(_response.fd >= 0)
    {
        return OK;
    }

    return NOT_FOUND;
}

2.ProcessCgi

  • 父子进程间如何传递数据?
    • POST参数、子进程处理结果用匿名管道通信
    • 请求方法、GET参数用环境变量通信
      • 环境变量是具有全局属性的,可以被子进程继承下去,不受exec*程序替换的影响
  • 给子进程传递环境变量时,亲测用setenv()putenv()靠谱些
    • putenv()不会复制传递的字符串大小,而setenv()会的
  • 注意:程序替换,只替换代码和数据,并不替换内核进程相关的数据结构
    • 如文件描述符表
    • 在程序替换之后,数据没有了,但是曾经打开的文件PIPE还在
  • 进程替换之后,子进程如何得知,对应的读写文件描述符时多少呢?
    • 虽然替换后子进程不知道对应的读写fd,但是一定知道0 && 1
    • 此时不需要知道读写fd了,只需要读0写1即可
    • 在执行exec*前,dup2重定向
int ProcessCgi()
{
    int code = 0; // 退出码
    std::string &bin = _request.path;

    // 父子间通信用匿名管道 // TODO 待整理
    int input[2]; // 父进程读
    int output[2]; // 父进程写

    if(pipe(input) < 0)
    {
        LOG(ERROR, "Pipe Input Error");
        code = SERVER_ERROR;
        return code;
    }

    if(pipe(output) < 0)
    {
        LOG(ERROR, "Pipe Output Error");
        code = SERVER_ERROR;
        return code;
    }

    pid_t id = fork();
    if(id == 0) // Child
    {
        close(output[1]);
        close(input[0]);

        // 子进程如何知道方法是什么?
        setenv("METHOD", _request.method.c_str(), 1);

        // GET带参通过环境变量导入子进程
        if(_request.method == "GET")
        {
            setenv("ARG", _request.arg.c_str(), 1);
            LOG(INFO, "GET Method, Add ARG");
        }
        else if (_request.method == "POST")
        {
            setenv("CLENGTH", std::to_string(_request.content_length).c_str(), 1);
            LOG(INFO, "POST Method, Add Content_Length");
        }
        else
        {
            // Do Nothing
        }

        // 进程替换之后,子进程如何得知,对应的读写文件描述符是多少呢?
        // 虽然替换后子进程不知道对应读写fd,但是一定知道0 && 1
        // 此时不需要知道读写fd了,只需要读0写1即可
        // 在exec*执行前,dup2重定向
        dup2(input[1], 1);
        dup2(output[0], 0);

        execl(bin.c_str(), bin.c_str(), nullptr);

        exit(5);
    }
    else if(id < 0)
    {
        LOG(ERROR, "Fork Error");
        code = SERVER_ERROR;
        return code;
    }
    else // Parent
    {
        close(output[0]);
        close(input[1]);

        if(_request.method == "POST")
        {
            // 不能确保一次性就能写完,所以
            const char *start = _request.request_body.c_str();
            int size = 0, total = 0;
            while (total < _request.request_body.size() &&
                   (size = write(output[1], start + total, _request.request_body.size() - total) > 0))
            {
                total += size;
            }
        }

        // 读取CGI子进程的处理结果
        char ch = 'K';
        while(read(input[0], &ch, 1) > 0)
        {
            // CGI执行完之后的结果,并不可以直接返回给浏览器,因为这部分内容只是响应正文
            _response.response_body += ch;
        }

        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret == id)
        {
            if(WIFEXITED(status))
            {
                if(WEXITSTATUS(status) == 0)
                {
                    code = OK;
                }
                else
                {
                    code = BAD_REQUEST;
                }
            }
            else
            {
                code = SERVER_ERROR;
            }
        }

        close(output[1]);
        close(input[0]);
    }

    return OK;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2137106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙OS Service Ability

鸿蒙OS Service模板的Ability基本概念 基于 Service 模板的 Ability&#xff08;以下简称“Service”&#xff09;主要用于后台运行任务&#xff08;如执行音乐播放、文件下载等&#xff09;&#xff0c;但不提供用户交互界面。Service 可由其他应用或 Ability 启动&#xff0…

WEB攻防-PHP特性缺陷对比函数CTF考点CMS审计实例

知识点&#xff1a; 1、过滤函数缺陷绕过&#xff1b; 2、CTF考点与代码审计&#xff1b; 1、赋值 不会对比类型 类型也会对比 2、MD5 在使用比较md5的时候&#xff0c;只要第一位是相等的数字&#xff0c;则会值相等 3、intval 3、 %0a代表换行 4、 6、 7、 代码审计

Amoco:一款针对二进制源码的安全分析工具

关于Amoco Amoco是一款功能强大的二进制源码静态分析工具&#xff0c;该工具基于Python 3.8开发&#xff0c;可以帮助广大研究人员轻松对二进制程序执行静态符号分析。 工具特性 1、一个通用的指令解码框架&#xff0c;旨在减少实现对新架构的支持所需的时间。例如&#xff0c…

.NET内网实战:通过命令行解密Web.config

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏&#xff0c;主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧&#xff0c;对内网和后渗透感兴趣的朋友们可以订阅该电子报刊&#xff0c;解锁更多的报刊内容。 02基本介绍 本文内容部分节选自小报童…

ICM20948 DMP代码详解(22)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;21&#xff09; 上一回讲到了inv_icm20948_wakeup_mems函数&#xff0c;没有讲完&#xff0c;本回把余下的内容讲完。为了便于理解和回顾&#xff0c;再次贴出inv_icm20948_wakeup_mems函数代码&#xff0c;在EMD-Cor…

【LLM:Gemini】文本摘要、信息提取、验证和纠错、重新排列图表、视频理解、图像理解、模态组合

开始使用Gemini 目录 开始使用Gemini Gemini简介 Gemini实验结果 Gemini的多模态推理能力 文本摘要 信息提取 验证和纠错 重新排列图表 视频理解 图像理解 模态组合 Gemini多面手编程助理 库的使用 引用 本文概述了Gemini模型和如何有效地提示和使用这些模型。本…

Linux:git

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《Linux&#xff1a;git》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xff01;&…

基于java网吧管理系统设计与实现

博主介绍&#xff1a;专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的可以…

Pytorch_CPU鸢尾花lirsDataset 尝试

鸢尾花数据集&#xff08;lris Dataset&#xff09; &#xff08;1&#xff09;下载地址【引用】&#xff1a;鸢尾花数据集下载 &#xff08;2&#xff09;鸢尾花数据集特点 茑尾花数据集有150 条样本记录&#xff0c;分为3个类别&#xff0c;每个类别有 50 个样本&#xff…

学习笔记JVM篇(一)

1、类加载的过程 加载->验证->准备->解析->初始化->使用->卸载 2、JVM内存组成部分&#xff08;HotSpot&#xff09; 名称作用特点元空间&#xff08;JDK8之前在方法区&#xff09;用于存储类的元数信息&#xff0c;例如名称、方法名、字段等&#xff1b;…

【程序分享】express 程序:可扩展的高级工作流程,用于更快速的从头算材料建模

分享一个 express 程序&#xff1a;可扩展的高级工作流程&#xff0c;用于更快速的从头算材料建模。 感谢论文的原作者&#xff01; 主要内容 “在这项工作中&#xff0c;我们介绍了一个开源的Julia项目express&#xff0c;这是一个可扩展的、轻量级的、高通量的高级工作流框…

学python要下什么包吗,有推荐的教程或者视频吗?

初学者可以尝试三种方法来学习Python第三方库&#xff0c;第一种传统&#xff0c;第二种省心&#xff0c;第三种轻量。 1、安装PythonPycharm&#xff0c;通过pip进行包管理&#xff0c;或者Pycharm后台也可以 2、安装Anaconda&#xff0c;预装了几百个数据科学包&#xff0c…

模仿抖音用户ID加密ID的算法MB4E,提高自己平台ID安全性

先看抖音的格式 对ID加密的格式 MB4EENgLILJPeQKhJht-rjcc6y0ECMk_RGTceg6JBAA 需求是 同一个ID 比如 413884936367560 每次获取得到的加密ID都是不同的&#xff0c;最终解密的ID都是413884936367560 注意这是一个加密后可解密原文的方式&#xff0c;不是单向加密 那么如下进行…

Windows 环境下 vscode 配置 C/C++ 环境

vscode Visual Studio Code&#xff08;简称 VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器。它支持多种编程语言&#xff0c;并提供了代码高亮、智能代码补全、代码重构、调试等功能&#xff0c;非常适合开发者使用。VSCode 通过安装扩展&#xff08;Extension…

abVIEW 可以同时支持脚本编程和图形编程

LabVIEW 可以同时支持脚本编程和图形编程&#xff0c;但主要依赖其独特的 图形编程 环境&#xff08;G语言&#xff09;&#xff0c;其中程序通过连线与节点来表示数据流和功能模块。不过&#xff0c;LabVIEW 也支持通过以下方式实现脚本编程的能力&#xff1a; 1. 调用外部脚本…

第4步CentOS配置SSH服务用SSH终端XShell等连接方便文件上传或其它操作

宿主机的VM安装CENTOS文件无法快速上传&#xff0c;也不方便输入命令行&#xff0c;用SSH终端xshell连接虚拟机的SSH工具就方便多了&#xff0c;实现VM所在宿主机Win10上的xshell能连接vm的centos要实现以下几个环节 1、确保宿主机与虚拟机的连通性。 2、虚拟机安装SSH服务&…

ESP8266_MicroPython——GPIO_LED_KEY_外部中断

MicroPython 文章目录 MicroPython前言一、安装软件二、点亮第一颗LED灯三、KEY按键四、外部中断总结 前言 MicroPython比较简单但是没有系统的更新过文章&#xff0c;准备写一下ESP8266——MicroPython的文章做一个系列。 一、安装软件 安装开发软件 Thonny&#xff0c;安装…

豆包MarsCode编程助手:产品功能解析与应用场景探索!

随着现代技术的不断进化升级&#xff0c;人工智能正在逐步改变着我们的日常工作方式。特别是对于复杂的项目&#xff0c;代码编写、优化、调试、测试等环节充满挑战。为了简化这些环节、提高开发效率&#xff0c;许多智能编程工具应运而生&#xff0c;豆包MarsCode 编程助手就是…

瑞芯微Android6 内核编译报错解决方案

1、报错内容如下图所示 错误内容&#xff1a; Kernel: arch/arm/boot/zImage is ready make: *** [kernel.img] Error 127 2、分析与解决方法 由于之前在ubuntu环境下编译没问题&#xff0c;现在是在centos环境下重新编译的时候报错&#xff0c;所以经过分析对比两个环境的…

非关系型数据库Redis

文章目录 一&#xff0c;关系型数据库和非关系型数据可区别1.关系型数据库2.非关系型数据库3.区别3.1存储方式3.2扩展方式3.2事务性的支持 二&#xff0c;非关系型数据为什么产生三&#xff0c;Redis1.Redis是什么2.Redis优点3.Redis适用范围4. Redis 快的原因4.1 基于内存运行…