BOA 调用 CGI 原理

2023-10-31

文章目录

BOA 调用 CGI 原理

  • 环境:
    arm7 i.mx6ul
    源码 boa-0.94.13

boa 移植以及怎么使用CGI网上有很多示例,但是找不到原理相关的。今天项目中有关用到,就看了下源码。

首先我们用放在’cgi-bin/’ 目录下的动xxx.cgi文件是一个可执行文件,可以使用./xxx.cgi来开始执行,其实是可以正常跑的。cgi编译的输出一般是用标准输出来实现,如下语句

fprintf(cgiOut, "		<div class=\"nav_m\">\n");

如果不传入环境变量,那么标准输出就到了登入的控制台。

那么boa是怎么调用我们编译的CGI进程的呢?源码cgi.c中init_cgi中可以发现行管的,调用入口我加了注释

/*
 * Name: init_cgi
 *
 * Description: Called for GET/POST requests that refer to ScriptAlias
 * directories or application/x-httpd-cgi files.  Ties stdout to socket,
 * stdin to data if POST, and execs CGI.
 * stderr remains tied to our log file; is this good?
 *
 * Returns:
 * 0 - error or NPH, either way the socket is closed
 * 1 - success
 */

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();
    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) {
                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) {					// 如果是CGI的请求,则创建新进程
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);  // execve 是把环境变量和进程名字,以及进程参数都传入到要执行性的进程。可以在上面看到fork语句,父程序是不受新建程序影响,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];

        req->status = 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;
}

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

BOA 调用 CGI 原理 的相关文章

  • 查找并删除超过 x 天的文件或文件夹

    我想删除超过 7 天的文件和文件夹 所以我尝试了 17 07 14 email protected cdn cgi l email protection find tmp mindepth 1 maxdepth 1 ctime 7 exec
  • 从哪里获取 iostream.h

    我正在尝试在 Linux 中做一些事情 但它抱怨找不到 iostream h 我需要安装什么才能获取此文件 这个标准头的正确名称是iostream没有扩展名 如果您的编译器仍然找不到它 请尝试以下操作 find usr include na
  • 如何从程序内部获取指向程序的特定可执行文件部分的指针? (也许是诽谤)

    我在 Linux 环境中 需要编写一个程序来检索放置在其可执行文件的某个部分中的一些数据 那么 如何从程序内部获取指向程序某个部分 通过其名称 的指针呢 我知道可以使用elf getdata 将节的索引作为参数传递给 get 和Elf Da
  • 如何指定配置脚本的包含目录

    我的工作场所有一个 Linux 系统 其中包含相当旧的软件包 并且没有 root 访问权限 我正在从源代码编译我需要的包 prefix somewhere in homedir 我的问题是我只是不知道如何说服配置在特定目录中查找头文件 源码
  • Unix 中的访问时间是多少

    我想知道访问时间是多少 我在网上搜索但得到了相同的定义 读 被改变 我知道与touch我们可以改变它 谁能用一个例子来解释一下它是如何改变的 有没有办法在unix中获取创建日期 时间 stat结构 The stat 2 结构跟踪所有文件日期
  • 如何在 Linux 中向热敏打印机发送 ESC/POS 命令

    我正在尝试在热敏打印机上发送 ESC POS 命令 但每当我发送它们时 热敏打印机都会将它们打印为文本 而不是作为命令执行它们 我在 prn 文件中编写这些命令 每当我执行 lp 命令来打印文件时 这些 prn 文件也会被打印 但作为文本
  • Linux 中的 Windows NAmed Pipes 替代品

    我们正在将现有的 Windows 代码移植到 Linux 我们使用 ACE 作为抽象层 我们使用 Windows 命名管道与多个客户端进行通信并执行重叠操作 linux 下这个相当于什么 我检查了linux命名管道 FIFO 但它们似乎只支
  • 点击界面没有出现

    我决定添加一个点击界面并在我的代码中使用它 但我能够得到它的状态 sudo ip f link tuntap add tap10 mode tap sudo ip link set tap10 up 之后当我执行 ip link 时 tap
  • 使用 Python 将阿拉伯语或任何从右到左书写系统的字符串打印到 Linux 终端

    非常简单的例子是 city print city 我期望输出是 但实际上输出是相反的字符串 字母看起来有点不同 因为它们有开始 中间和结束形式 我无法将其粘贴到此处 因为复制粘贴会再次更正字符串的顺序 如何在 Linux 终端上正确打印阿拉
  • 打印 STDOUT/STDERR 并将它们写入 Bash 中的文件?

    有没有办法让 Bash 将 STDOUT STDERR 重定向到文件 但仍然将它们打印到终端 这会将 STDOUT 和 STDERR 重定向到同一个文件 some command 2 gt 1 tee file log Example to
  • 如何使用 PyAudio 选择特定的输入设备

    通过 PyAudio 录制音频时 如何指定要使用的确切输入设备 我的电脑有两个麦克风 一个内置 一个通过 USB 我想使用 USB 麦克风进行录音 这流类 https people csail mit edu hubert pyaudio
  • Linux 上的“软/硬 nofile”是什么意思

    当我尝试在RedHat EL5上安装软件时 我得到了错误 软 硬nofile的期望值是4096 而默认值是1024 我设法增加了这个数字 但我不知道参数是什么 他们指的是软链接和硬链接吗 我改变的方法是 a 修改 etc security
  • 重新链接匿名(未链接但打开)文件

    在 Unix 中 可以创建匿名文件的句柄 例如 使用 creat 创建并打开它 然后使用 unlink 删除目录链接 留下一个带有 inode 和存储的文件 但没有可能的方法重新打开它 此类文件通常用作临时文件 通常这就是 tmpfile
  • Flex 的远程版本误解了我的规则

    我使用 flex 和 bison 编写了一个小汇编程序 可以在我的机器 ubuntu 10 10 上构建并运行正常 现在其他人正在尝试在 arch linux 上构建它 并且他们安装的 flex 产生了不同的 lex yy c 这是不匹配的
  • PHP 日志文件颜色

    我正在编写一个 PHP 日志文件类 但我想为写入文件的行添加颜色 我遇到的问题是颜色也会改变终端的颜色 我想要实现的是仅更改写入日志文件的行的颜色 class logClass extends Singleton private funct
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 路由是否会影响具有绑定源地址的套接字?

    假设我有两个网络接口 eth0有地址10 0 0 1 eth1有地址192 168 0 1 Using route or ip route add我已将其设置为路由 所有地址至eth0 1 2 3 4只为了eth1 所以数据包到1 2 3
  • 我们可以在 Bash 脚本中使用 PHP 吗?

    我有一个 bash 脚本abcd sh bin sh for i in seq 8 do ssh w i uptime ps elf grep httpd wc l free m mpstat done pid sleep 1 kill 9
  • Linux 阻塞与非阻塞串行读取

    I have 这段代码 https stackoverflow com questions 6947413 how to open read and write from serial port in c用于在Linux中从串行读取 但我不
  • python 可以检测它运行在哪个操作系统下吗?

    python 可以检测操作系统 然后为文件系统构建 if else 语句吗 我需要将 Fn 字符串中的 C CobaltRCX 替换为 FileSys 字符串 import os path csv from time import strf

随机推荐

  • VirtualBox 虚拟机里网络很慢的解决方法

    VirtualBox 升级到6 0 4 后发现这个问题 Mac 主机网速很快 但虚拟机 ubuntu 里网络很慢 首先尝试多种不同的网络连接模式 都不能解决 再回头调试 发现域名解析很慢 问题定位在 DNS 问题 ping 一下百度 15秒
  • 使用Python,OpenCV实现简单的场景边界/拍摄转换检测器

    使用Python OpenCV进行简单的场景边界 拍摄转换检测器 1 效果图 2 实现 2 1 步骤 2 2 什么是 场景边界 和 拍摄过渡 2 3 代码目录结构 2 源码 参考 这篇博客起源于朋友分享蝙蝠侠7更新了 而我没有办法去最近的书
  • Learing blockchain in go

    Windows下JetBrains GoLand环境配置记录 根据文末Reference 1 实现的迷你区块链 暂有 block chain pow UTXO 现在实现的bc存在double spending问题 并且创世区块和创世交易的哈
  • C++之合并两个链表

    题目 已有a b两个链表 每个链表中的结点包括学号 成绩 要求把两个链表合并 按学号升序排列 include
  • 程序员不擅长沟通???

    版权声明 原创作品 允许转载 转载时请务必以超链接形式标明文章原始出版 作者信息和本声明 否则将追究法律责任 本文地址 http blog csdn net jobchanceleo archive 2007 01 18 1487073 a
  • c++函数返回引用

    转自 http www cnblogs com floatedclouds archive 2011 10 13 2209917 html 1 什么是引用 引用就是变量的别名 操作一个变量的引用也就相当于操作变量本身 这一点跟指针很类似 但
  • Cursor,程序员的 AI 代码编辑助手

    相信大家都或多或少地听说过 了解过 chatGPT 半个月前发布的 GPT 4 可谓是 AI 赛道上的一个王炸 那么今天咸鱼给大家分享一个开源的 AI 代码编辑器 Cursor 让各位程序员在编程之路上一骑绝尘 介绍 Cursor 是一个人
  • minigui成功移植到ubuntu64位平台

    1 pc系统ubuntu14LTS 64bit 同时在32位ubuntu16 04上经过了测试 官方的所有范例程序都能运行 2 过两天会写份详细的移植教程 现在只是将移植好的文件上传到我的csdn下载 大家可以免费下载 3 做个简单的移植过
  • nginx代理去掉URl前缀

    今天接到一个配置nginx的需求是 需要访问某个域名时 nginx可以去掉前缀去代理访问到后端 正常配置情况下 在nginx配置文件中中设置了 location prod api api 时 浏览器访问 prod api api 反向代理到
  • ModbusPoll和Slave的使用教程

    ModbusPoll和Slave的使用教程 在工业领域 很多地方采用了Modbus协议 简单理解一下Modbus协议 就是把数据存在寄存器地址里面编号 然后通过协议读取 modbus有主机和从机 主机只有一个 从机可以有很多个 玩过Tcp的
  • PAT C语言入门题目-7-52 数组元素循环右移问题 (20 分)

    7 52 数组元素循环右移问题 20 分 一个数组A中存有N gt 0 个整数 在不允许使用另外数组的前提下 将每个整数循环向右移M 0 个位置 即将A中的数据由 A 0 A 1 A N 1 变换为 A N M A N 1 A 0 A 1
  • 尚硅谷-康师傅-MySQL详细笔记(10-18章)

    mysq详细笔记10 18章 第10章 创建和管理表 10 1 基础知识 10 1 1 一条数据存储的过程 10 1 2 标识符命名规则 10 1 3 MySQL中的数据类型 10 2 创建和管理数据库 10 2 1 创建数据库 10 2
  • 安卓移动应用开发之从零开始写安卓小程序3

    实验3 修改我们的HelloWorld程序 让它和我们的手机app外观差不多 一 打开我们的HelloWorld程序 没有的同学请自行创建或者下载我发上去的资源 大家如果遇到sync没有跳出来的 可以点击这个search 然后输入sync回
  • Nmap简单使用教程

    在Web攻防的过程中对有关主机存活 应用版本扫描的相关工具中 Nmap是最常使用的信息收集工具 Nmap是一款开源的网络探测和安全审核的工具 它的设计目标是快速地扫描大型网络 Nmap可以探测网络中有哪些主机存活 这些主机都提供了什么服务
  • 【山河送书第十期】:《Python 自动化办公应用大全》参与活动,送书两本!!

    山河送书第十期 Python 自动化办公应用大全 参与活动 送书两本 前言 一 书籍亮点 二 作者简介 三 内容简介 四 购买链接 五 参与方式 六 往期赠书回顾 前言 在过去的 5 年里 Python 已经 3 次获得 TIOBE 指数年
  • 基于IMU和超声的3D手势识别笔

    随着科技的发展 人机交互在商业中有了越来越多的应用 面对日益复杂的交互场景 手势识别逐渐成为虚拟现实等相关应用的主要交互手段 3D手势识别是一个具有挑战性的问题 常用的手势传感器有三种基本类型 多点触摸屏传感器 基于视觉的传感器和基于安装的
  • 微信小程序(订阅消息)

    小程序模板消息即将被废弃掉 于是有了新接口wx requestSubscribeMessage 订阅消息文档 步骤 1 获取用户openid access token 前面文章提到过 2 获取模板 ID 3 获取下发权限 api 4 发送订
  • 【项目】前端实习——后端接口数据获取与渲染

    后端数据获取与渲染 接口联调 数据渲染 挂载 生命周期 数据更新 实习项目开发与自己平时练习的项目最大的不同就是有接口数据 通过发起一定的请求获取到后端的数据 接口联调 在后端部署好后 通过网络请求去获取数据 前面我们已经定义好一些死的数据
  • uboot环境变量分析

    项目情景 最近我在一个新平台的开发过程中遇到烧录问题 具体的问题是使用原厂提供的烧录脚本烧录成功 但是固件却没有更新 其中kernel和dtb烧录指令如下 adnl exe Partition M mem P 0x1000000 F lin
  • BOA 调用 CGI 原理

    文章目录 BOA 调用 CGI 原理 BOA 调用 CGI 原理 环境 arm7 i mx6ul 源码 boa 0 94 13 boa 移植以及怎么使用CGI网上有很多示例 但是找不到原理相关的 今天项目中有关用到 就看了下源码 首先我们用