⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cgi.c

📁 用于移植到嵌入式linux系统的boa http服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
     Which therefore means     "=", "+", "~", "!", "*", "'", "(", ")", ","     are *not* escaped and should be?     Wait, we don't do any escaping, and nor should we.     According to the RFC draft, we unescape and then re-escape     in a "system defined manner" (here: none).     The CGI/1.1 draft (03, latest is 1999???) is very unclear here.     I am using the latest published RFC, 2396, for what does and does     not need escaping.     Since boa builds the argument list and does not call /bin/sh,     (boa uses execve for CGI)     */    if (q && !strchr(q, '=')) {        /* we have an 'index' style */        q = strdup(q);        if (!q) {            log_error_doc(req);            fputs("unable to strdup 'q' in create_argv!\n", stderr);            _exit(EXIT_FAILURE);        }        for (aargc = 1; q && (aargc < CGI_ARGC_MAX);) {            r = q;            /* for an index-style CGI, + is used to separate arguments             * an escaped '+' is of no concern to us             */            if ((p = strchr(q, '+'))) {                *p = '\0';                q = p + 1;            } else {                q = NULL;            }            if (unescape_uri(r, NULL)) {                /* printf("parameter %d: %s\n",aargc,r); */                aargv[aargc++] = r;            }        }        aargv[aargc] = NULL;    } else {        aargv[1] = NULL;    }}/* * 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->cgi_type) {        if (complete_env(req) == 0) {            return 0;        }    }    DEBUG(DEBUG_CGI_ENV) {        int i;        for (i = 0; i < req->cgi_env_index; ++i)            log_error_time();            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",                    __FILE__, req->cgi_env[i]);    }    /* we want to use pipes whenever it's a CGI or directory */    /* otherwise (NPH, gunzip) we want no pipes */    if (req->cgi_type == CGI ||        (!req->cgi_type &&         (req->pathname[strlen(req->pathname) - 1] == '/'))) {        use_pipes = 1;        if (pipe(pipes) == -1) {            log_error_doc(req);            perror("pipe");            return 0;        }        /* set the read end of the socket to non-blocking */        if (set_nonblock_fd(pipes[0]) == -1) {            log_error_doc(req);            perror("cgi-fcntl");            close(pipes[0]);            close(pipes[1]);            return 0;        }    }    child_pid = fork();    switch (child_pid) {    case -1:        /* fork unsuccessful */        /* FIXME: There is a problem here. send_r_error (called by         * boa_perror) would work for NPH and CGI, but not for GUNZIP.           * Fix that.          */        boa_perror(req, "fork failed");        if (use_pipes) {            close(pipes[0]);            close(pipes[1]);        }        return 0;        break;    case 0:        /* child */        reset_signals();        if (req->cgi_type == CGI || req->cgi_type == NPH) {            char *c;            unsigned int l;            char *newpath, *oldpath;            c = strrchr(req->pathname, '/');            if (!c) {                /* there will always be a '.' */                log_error_doc(req);                fprintf(stderr,                        "unable to find '/' in req->pathname: \"%s\"\n",                        req->pathname);                if (use_pipes)                    close(pipes[1]);                _exit(EXIT_FAILURE);            }            *c = '\0';            if (chdir(req->pathname) != 0) {                int saved_errno = errno;                log_error_doc(req);                fprintf(stderr, "Could not chdir to \"%s\":",                        req->pathname);                errno = saved_errno;                perror("chdir");                if (use_pipes)                    close(pipes[1]);                _exit(EXIT_FAILURE);            }            oldpath = req->pathname;            req->pathname = ++c;            l = strlen(req->pathname) + 3;            /* prefix './' */            newpath = malloc(sizeof (char) * l);            if (!newpath) {                /* there will always be a '.' */                log_error_doc(req);                perror("unable to malloc for newpath");                if (use_pipes)                    close(pipes[1]);                _exit(EXIT_FAILURE);            }            newpath[0] = '.';            newpath[1] = '/';            memcpy(&newpath[2], req->pathname, l - 2); /* includes the trailing '\0' */            free(oldpath);            req->pathname = newpath;        }        if (use_pipes) {            /* close the 'read' end of the pipes[] */            close(pipes[0]);            /* tie CGI's STDOUT to our write end of pipe */            if (dup2(pipes[1], STDOUT_FILENO) == -1) {                log_error_doc(req);                perror("dup2 - pipes");                _exit(EXIT_FAILURE);            }            close(pipes[1]);        } else {            /* tie stdout to socket */            if (dup2(req->fd, STDOUT_FILENO) == -1) {                log_error_doc(req);                perror("dup2 - fd");                _exit(EXIT_FAILURE);            }            close(req->fd);        }        /* Switch socket flags back to blocking */        if (set_block_fd(STDOUT_FILENO) == -1) {            log_error_doc(req);            perror("cgi-fcntl");            _exit(EXIT_FAILURE);        }        /* 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);        }#ifdef USE_SETRLIMIT        /* setrlimit stuff.         * This is neat!         * RLIMIT_STACK    max stack size         * RLIMIT_CORE     max core file size         * RLIMIT_RSS      max resident set size         * RLIMIT_NPROC    max number of processes         * RLIMIT_NOFILE   max number of open files         * RLIMIT_MEMLOCK  max locked-in-memory address space         * RLIMIT_AS       address space (virtual memory) limit         *         * RLIMIT_CPU      CPU time in seconds         * RLIMIT_DATA     max data size         *         * Currently, we only limit the CPU time and the DATA segment         * We also "nice" the process.         *         * This section of code adapted from patches sent in by Steve Thompson         * (no email available)         */        {            struct rlimit rl;            int retval;            if (cgi_rlimit_cpu) {                rl.rlim_cur = rl.rlim_max = cgi_rlimit_cpu;                retval = setrlimit(RLIMIT_CPU, &rl);                if (retval == -1) {                    log_error_time();                    fprintf(stderr,                            "setrlimit(RLIMIT_CPU,%d): %s\n",                            rlimit_cpu, strerror(errno));                    _exit(EXIT_FAILURE);                }            }            if (cgi_limit_data) {                rl.rlim_cur = rl.rlim_max = cgi_rlimit_data;                retval = setrlimit(RLIMIT_DATA, &rl);                if (retval == -1) {                    log_error_time();                    fprintf(stderr,                            "setrlimit(RLIMIT_DATA,%d): %s\n",                            rlimit_data, strerror(errno));                    _exit(EXIT_FAILURE);                }            }            if (cgi_nice) {                retval = nice(cgi_nice);                if (retval == -1) {                    log_error_time();                    perror("nice");                    _exit(EXIT_FAILURE);                }            }        }#endif        umask(cgi_umask);       /* change umask *again* u=rwx,g=rxw,o= */        /*         * tie STDERR to cgi_log_fd         * cgi_log_fd will automatically close, close-on-exec rocks!         * if we don't tie STDERR (current log_error) to cgi_log_fd,         *  then we ought to tie it to /dev/null         *  FIXME: we currently don't tie it to /dev/null, we leave it         *  tied to whatever 'error_log' points to.  This means CGIs can         *  scribble on the error_log, probably a bad thing.         */        if (cgi_log_fd) {            dup2(cgi_log_fd, STDERR_FILENO);        }        if (req->cgi_type) {            char *aargv[CGI_ARGC_MAX + 1];            create_argv(req, aargv);            execve(req->pathname, aargv, req->cgi_env);        } else {            if (req->pathname[strlen(req->pathname) - 1] == '/')                execl(dirmaker, dirmaker, req->pathname, req->request_uri,                      (void *) NULL);#ifdef GUNZIP            else                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",                      req->pathname, (void *) NULL);#endif        }        /* execve failed */        log_error_doc(req);        fprintf(stderr, "Unable to execve/execl pathname: \"%s\"",                req->pathname);        perror("");        _exit(EXIT_FAILURE);        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->cgi_type == 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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -