boa服务器实现CGI功能

2023-11-04

CGI简介

        CGI 是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。CGI 应用程序能与浏览器进行交互,还可通过数据库API 与数据库服务器等外部数据源进行通信,从数据库服务器中获取数据。格式化为HTML文档后,发送给浏览器,也可以将从浏览器获得的数据放到数据库中。几乎所有服务器都支持CGI,可用任何语言编写CGI,包括流行的C、C ++、VB 和Delphi 等。CGI 分为标准CGI 和间接CGI两种。标准CGI 使用命令行参数或环境变量表示服务器的详细请求,服务器与浏览器通信采用标准输入输出方式。间接CGI 又称缓冲CGI,在CGI 程序和CGI 接口之间插入一个缓冲程序,缓冲程序与CGI 接口间用标准输入输出进行通信。

简而言之:CGI就是web服务器可以调用的其他程序,该程序将输出重定向,在该程序中通过printf生成html,通过管道将数据发给web服务器,完成交互。


boa CGI实现

1.boa获取到数据时,执行process_requests()-->读取http头read_header()--->process_header_end();根据头部信息,获取到该请求为CGI

2.执行init_cgi()

int init_cgi(request * req)
{
    int child_pid;
    int pipes[2];
    int use_pipes = 0;

    SQUASH_KA(req);

    if (req->is_cgi) {
        if (complete_env(req) == 0) {        //设置环境变量
            return 0;
        }
    }
#ifdef FASCIST_LOGGING
    {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }
#endif

    if (req->is_cgi == CGI || 1) {
        use_pipes = 1;                //使用管道
        if (pipe(pipes) == -1) {
            log_error_time();
            perror("pipe");
            return 0;
        }

        /* set the read end of the socket to non-blocking */
        if (set_nonblock_fd(pipes[0]) == -1) {        //设置读管道为非阻塞
            log_error_time();
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();        //创建子进程,用于启动cgi程序,程序执行完成后退出boa
    switch(child_pid) {
    case -1:
        /* fork unsuccessful */
        log_error_time();
        perror("fork");

        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        send_r_error(req);
        /* FIXME: There is aproblem here. send_r_error would work
           for NPH and CGI, but not for GUNZIP.  Fix that. */
        /* i'd like to send_r_error, but.... */
        return 0;
        break;
    case 0:
        /* child */
        if (req->is_cgi == CGI || req->is_cgi == NPH) {
            char *foo = strdup(req->pathname);
            char *c;

            if (!foo) {
                WARN("unable to strdup pathname for req->pathname");
                _exit(1);
            }
            c = strrchr(foo, '/');
            if (c) {
                ++c;
                *c = '\0';
            } else {
                /* we have a serious problem */
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
            if (chdir(foo) != 0) {
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
        }
        if (use_pipes) {
            close(pipes[0]);
            /* tie cgi's STDOUT to it's write end of pipe */
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {        //将写管道重定向到标准输出,在cgi中使用printf,数据就会被发送到管道中
                log_error_time();
                perror("dup2 - pipes");
                close(pipes[1]);
                _exit(1);
            }
            close(pipes[1]);
            if (set_block_fd(STDOUT_FILENO) == -1) {        //设置管道为阻塞
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        } else {
            /* tie stdout to socket */
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - fd");
                _exit(1);
            }
            /* Switch socket flags back to blocking */
            if (set_block_fd(req->fd) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        }
        /* tie post_data_fd to POST stdin */
        if (req->method == M_POST) { /* tie stdin to file */
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
        }
        /* Close access log, so CGI program can't scribble
         * where it shouldn't
         */
        close_access_log();

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tied STDERR (current log_error) to cgi_log_fd,
         *  then we ought to close it.
         */
        if (!cgi_log_fd)
            dup2(devnullfd, STDERR_FILENO);
        else
            dup2(cgi_log_fd, STDERR_FILENO);

        if (req->is_cgi) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);        //启动cgi程序
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, NULL);
#endif
        }
        /* execve failed */
        WARN(req->pathname);
        _exit(1);
        break;

    default:
        /* parent */
        /* if here, fork was successful */
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {
            close(req->post_data_fd); /* child closed it too */
            req->post_data_fd = 0;
        }

        /* NPH, GUNZIP, etc... all go straight to the fd */
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];            //保存读管道的fd

        req->status = PIPE_READ;            //状态置为PIPE_READ
        if (req->is_cgi == CGI) {
            req->cgi_status = CGI_PARSE; /* got to parse cgi header */
            /* for cgi_header... I get half the buffer! */
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            /* I get all the buffer! */
            req->header_line = req->header_end = req->buffer;
        }

        /* reset req->filepos for logging (it's used in pipe.c) */
        /* still don't know why req->filesize might be reset though */
        req->filepos = 0;
        break;
    }

    return 1;                //more to do
}
3.下一次轮询中,程序回到process_request,状态为 PIPE_READ,准备读取管道中的数据。读取后,继续轮询,直至全部读取完毕,状态置为 PIPE_WRITE,将数据发送给客户端。(正是由于boa的这种轮询机制,使得它可以处理多个请求而不会卡住)


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

boa服务器实现CGI功能 的相关文章

  • Erlang Ports:与类似“wc”的程序交互?

    我有一个外部 exe 程序 它从标准输入读取并生成结果 它的工作原理就像wc编程并读取直到EOF 或者更确切地说 流结束 Update 让我再添加一条解释 我基本上是在尝试编写一个 Erlang 管道 我可以在批处理文件中调用该程序 例如e
  • 在任何文件中打印 Perl 警告而没有“使用警告”或 -w

    我有很多经常被调用的旧 Perl 代码 我一直在编写一个新模块 突然间我在 Apache 的 error log 中收到很多警告 它们针对当前正在使用的每个模块 例如 my variable variable masks earlier d
  • os.close(0) 和 sys.stdin.close() 之间的区别

    我正在编写一些 Python 代码 它是从 Apache 调用的 CGI 脚本 代码所做的第一件事是 我相信 尝试使用以下命令关闭 stdin stdout stderr for fd in 0 1 2 try os close fd ex
  • CPAN 安装新模块是否会影响同一实时生产服务器上的 Perl-CGI 应用程序?

    我在 CentOS Linux 网络服务器上有一些 Perl CGI 程序 我希望编写更多需要当前未安装的 Perl 模块的应用程序 在同一实时生产服务器上运行 CPAN 是否会以任何方式影响这些程序 显然 当前不使用这些模块 有一种可能的
  • Python CGIHTTPServer 崩溃并显示“OSError:[Errno 13] 权限被拒绝”

    我正在从我的主目录运行以下命令 python m CGIHTTPServer 这会运行服务器 但是当我尝试访问 cgi bin 目录中的脚本时 我得到 Traceback most recent call last File usr lib
  • 2 个 cgi 脚本中的会话登录和注销

    我需要在用户登录时存储登录会话 并在用户退出系统或会话超时时删除登录会话 我正在用 Perl 编码 我知道我可以在 Perl 中使用 CGI Session 模块 但是如何确保会话是由 1 个 cgi 脚本创建并由另一个 cgi 脚本删除的
  • 从 CGI C 模块返回 http 错误代码

    我有一个用 C 编写的 CGI 模块 在某些情况下我想从该模块返回 HTTP 错误 400 问题是 我不知道如何从模块返回 HTTP 错误 看起来像我的模块中的 return 1 返回 500 内部服务器错误 我尝试过退回 400 等 但还
  • Bash 脚本中的命令输出到下拉框?

    首先 我感谢回答这个问题的所有帮助 我在 bash 脚本中有一个命令 该命令将输出以下内容 255 254 253 252 7 6 5 4 3 2 1 它是一个特定的数字列表 从最大的数字开始 这就是我想要的 然后到最小的 数据集以空格分隔
  • 编写一个以 root 身份运行的 perl cgi 应用程序

    我正在编写一个 Perl CGI 应用程序 在某些时候 此 cgi 应用程序需要以 root 身份运行才能访问和写入特定文件 我想知道我到底应该如何执行此操作以及执行此操作时应采取的安全预防措施 你几乎不应该 如果您无法避免它 请创建一小段
  • 如何在Python中读取cookie

    我是 python cgi 脚本的新手 我想用Python读取cookie 我尝试了以下代码 from urllib2 import Request build opener HTTPCookieProcessor HTTPHandler
  • SQLite 的磁盘 I/O 错误

    我有一个 很小的 动态网站 它 大致 是一个使用 SQLite 数据库的 Perl CGI 脚本 DBI 包是 Perl 中使用的抽象层 大约一周前 我开始看到此错误消息 disk I O error 10 at dbdimp c line
  • 这里是 Python 菜鸟:在支持 Python 的 Web 服务器上,如何使用 Python?

    usr bin env python coding UTF 8 enable debugging import cgitb cgitb enable print Content Type text plain charset utf 8 p
  • 在 Perl 中,如何在命令行上发送 CGI 参数?

    通常我从网页获取数据 但我想从命令行发送它以方便调试 为了获取数据我做了类似的事情 my query new CGI my username query gt param the username 这似乎不起作用 script pl the
  • 编写 Perl CGI 应用程序的最佳方法是什么?

    我见过的每个 CGI Perl 示例基本上都是一堆包含 HTML 的打印语句 这似乎不是编写 CGI 应用程序的最佳方法 有一个更好的方法吗 谢谢 编辑 我决定使用 CGI Application 和 HTML Template 并使用以下
  • 如何以不依赖扩展的方式禁用 htaccess 中的 cgi?

    我想在文档根目录下的目录中禁用任何类型的 CGI 执行 任何类型 php perl ruby 等等 我想以一种不依赖于文件扩展名的方式来执行此操作 在我的文档根目录下 因为用户必须能够放置和查看 HTML 文件 它必须位于 htaccess
  • 如何将变量值从 javascript 传递到 perl

    我正在使用 JavaScript 插件来获取 IP 地址 如果 IP 地址开头为10 15我想为一个变量分配一个值 如果IP以10 13我想为同一个变量分配不同的值 我不知道该变量是否必须在 Perl 或 JavaScript 中 我正在尝
  • Apache + PHP 中的“标题之前的脚本输出结束”

    UPDATE 此问题是由于脚本完成之前服务器请求超时造成的 我在共享 LAMP 主机 nearlyfreespeech net 上运行遗留代码 并且最近添加了一个无法在生产中工作的新脚本 我的 apache 错误日志显示该消息End of
  • Python:CGI在脚本退出前更新网页

    好吧 这是我的情况 我编写了一个带有文本区域的 HTML 表单 该文本区域向我的 python 脚本提交 POST 请求 我使用 cgi 库来解析文本区域并将其拆分为一个数组 然后 我使用循环处理这些项目并在处理时打印它们 看来 即使我将打
  • 创建新的 Expect 对象时,cgi-perl 文件中出现 Apache [PTY 错误]

    我有一个 perl 脚本 usr bin perl w use DateTime use Expect use IO Pty use CGI Fast while q new CGI Fast my ip q gt param ip my
  • 在 Ubuntu 中执行 .cgi 文件

    我在 Ubuntu 下运行 Apache PHP 当我运行 cgi 文件时 通过http localhost mycgi cgi 浏览器将显示代码而不是运行它 如何让浏览器执行 CGI 文件而不是显示其内容 将这些行添加到您的 apache

随机推荐

  • 《Python进阶系列》六:Python中的文件对象

    文件对象的seek 和tell 打开一个文件 读取内容 是很常见的操作 不过有的时候我们还需要反复读取文件中的内容 如果多次打开文件读取再多次关闭 显然不是特别好的操作 我们可以借助Python文件对象的seek 和tell 函数 来实现反
  • 为什么那么多人用小智ai

    ChatGPT丨小智ai丨chatgpt丨人工智能丨OpenAI丨聊天机器人丨AI语音助手丨GPT 3 5丨OpenAI ChatGPT GPT 4 GPT 3 人机对话 ChatGPT应用 小智ai 小智ai 小智ai 小智ai Chat
  • Shader理论(2):Unity中的各种坐标系

    目录 前言 一 坐标系 1 1 世界坐标系 World Space 1 2 本地坐标系 Local Space 模型坐标系 1 3 屏幕坐标系 Screen Space 1 4 观察坐标系 ViewPort Space 视口坐标系 1 5
  • 如何设计一个短信发送功能

    本文主要分享了如何设计一个发送短信功能 一 总结简述 1 梳理多个平台短信API的发送参数 集成封装提供统一的API 支持多个短信平台 阿里云 腾讯云 百度云 京东云 七牛云 灵活切换 2 提供存储方案 表结构设计 3 提供真实生产项目代码
  • 内核配置中的:Multifunction device drivers

    Multifunction Device Drivers 多功能设备Linux下驱动开发 先来一个英文简介 Multifunction devices embed several functions e g GPIOs touchscree
  • kafka的一些基本命令

    kafka brokers test 8090 zookeeper servers test 2181 1 查看test服务器中的所有topic bin kafka topics sh list zookeeper test 2181 2
  • stable diffusion(Lora的训练)

    以坤坤为例 上网随便找了几个坤坤的人脸图像 作为训练的数据集 1 训练环境搭建 建议看一遍教程 虽然这个up主好像不是很专业的样子 不过流程差不多是这样的 重点关注一下虚拟环境搭建完之后 在终端选择配置的操作 就是一堆yes no 的选项
  • 国产麒麟系统KylinOS Server V10 SP2安装MongoDB6.0版本

    1 下载安装包 安装下载链接 https fastdl mongodb org linux mongodb linux aarch64 rhel82 6 0 6 tgz 2 上传到服务器 3 解压安装包 tar zxvf mongodb l
  • AF Http request 代理形式回调

    AF是以block的方式将请求结果返回 这样的处理思路我感觉很好 每个请求都单独处理自己的回调 AF的请求也可以使代理的形式进行回调 HIHTTPRequest 以代理的形式回调的话需要创建一个请求类 然后将请求结果以代理的形式回调 HIH
  • 毕业论文参考文献格式设置(以GB/T 7714-2015为例)

    Ref https zhuanlan zhihu com p 376138185 下载链接 https www endnote com style download chinese standard gb t7714 numeric 链接
  • 四路服务器选型项目,四路服务器详细

    四路服务器详细 内容精选 换一换 弹性云服务器 Elastic Cloud Server 是一种可随时自动获取 计算能力可弹性伸缩的云服务器 可帮助您打造可靠 安全 灵活 高效的应用环境 确保服务持久稳定运行 提升运维效率 本节介绍REST
  • 【Unity】UnityのTimelineが実機で再生されない件について

    Unity Unity Timeline 実機 再生 件 https qiita com hide gugen items 7fee18be2c789144ed74 経緯 Editor上 普通 再生 日AssetBundle化 iPhone
  • 华为隐藏功能扩大内存代码大全_华为手机绝密功能,在拨号界面就能揭开

    你知道吗 华为手机里的那些隐藏功能 打开方式居然是 拨号界面 只要在拨号界面输入指定代码 就会自动弹出隐藏功能 今天我就来给大家科普科普 那些隐藏在华为手机里的代码大全 测试代码 虽然这个代码叫测试代码 但对咱们普通用户来说却是一个非常实用
  • JS大坑之19位数的Number型精度丢失问题详解

    这篇文章主要介绍了JS大坑之19位数的Number型精度丢失问题 文中通过示例代码介绍的非常详细 对大家的学习或者工作具有一定的参考学习价值 有兴趣的朋友们可以一起来学习探讨 最近在实现一个需求的时候 需要接入第三方的接口 先调用A接口 A
  • 关于ip5306芯片按键关机后仍然有输出

    官方手册中提到 负载自动检测时间 TloadD 负载电流持续小于 45mA 32 s时 芯片会自动进入休眠状态 实际上可能会因为个体差异 芯片空载就60ma 导致无法关机 实际上做这个芯片测试 发现了几个问题 芯片PIN5按键不可抛弃 如果
  • 计算机网络原理选择题

    1 1 电信业一般认为宽带骨干网数据传输速率应达到 d a 640kbps b 640mbps c 1gbps d 2gbps 2 异步时分多路复用 tdm 技术中的时间片分配策略是 c a 预先分配但不固定 b 预先分配固定不变 c 动态
  • 第八章 真实的谎言

    第八章 真实的谎言 我先给大家讲一个石头汤的故事 很久以前 在东欧的一个地方 发生了一次大饥荒 人们都以戒备的心理囤积起他们可以找到的任何食物 并把这些食物都藏了起来 甚至于连他们的朋友和邻居都 不告诉 有一天 一个小商贩驾着他的马车来到一
  • Ant Design与Ant Design pro入门

    一 Ant Design入门 1 什么是Ant Design Ant Design是阿里蚂蚁金服团队基于React开发的ui组件 主要用于中后台系统的使用 官网 https ant design index cn 特性 提炼自企业级中后台产
  • 网易笔试编程题-不要二

    题目描述 二货小易有一个W H的网格盒子 网格的行编号为0 H 1 网格的列编号为0 W 1 每个格子至多可以放一块蛋糕 任意两块蛋糕的欧几里得距离不能等于2 对于两个格子坐标 x1 y1 x2 y2 的欧几里得距离为 x1 x2 x1 x
  • boa服务器实现CGI功能

    CGI简介 CGI 是Web 服务器运行时外部程序的规范 按CGI 编写的程序可以扩展服务器功能 CGI 应用程序能与浏览器进行交互 还可通过数据库API 与数据库服务器等外部数据源进行通信 从数据库服务器中获取数据 格式化为HTML文档后