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

📄 request.c

📁 boa:Linux系统中的轻量级Web服务
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Boa, an http server *  Copyright (C) 1995 Paul Phillips <paulp@go2net.com> *  Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org> *  Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 1, or (at your option) *  any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *//* $Id: request.c,v 1.112.2.3 2002/07/24 03:03:59 jnelson Exp $*/#include "boa.h"#include <stddef.h> /* for offsetof */int total_connections;struct status status;static int sockbufsize = SOCKETBUF_SIZE;/* function prototypes located in this file only */static void free_request(request ** list_head_addr, request * req);/* * Name: new_request * Description: Obtains a request struct off the free list, or if the * free list is empty, allocates memory * * Return value: pointer to initialized request */request *new_request(void){    request *req;    if (request_free) {        req = request_free;     /* first on free list */        dequeue(&request_free, request_free); /* dequeue the head */    } else {        req = (request *) malloc(sizeof (request));        if (!req) {            log_error_time();            perror("malloc for new request");            return NULL;        }    }    memset(req, 0, offsetof(request, buffer) + 1);    return req;}/* * Name: get_request * * Description: Polls the server socket for a request.  If one exists, * does some basic initialization and adds it to the ready queue;. */void get_request(int server_s){    int fd;                     /* socket */    struct SOCKADDR remote_addr; /* address */    struct SOCKADDR salocal;    int remote_addrlen = sizeof (struct SOCKADDR);    request *conn;              /* connection */    size_t len;    static int system_bufsize = 0; /* Default size of SNDBUF given by system */    remote_addr.S_FAMILY = 0xdead;    fd = accept(server_s, (struct sockaddr *) &remote_addr,                &remote_addrlen);    if (fd == -1) {        if (errno != EAGAIN && errno != EWOULDBLOCK)            /* abnormal error */            WARN("accept");        else            /* no requests */            pending_requests = 0;        return;    }    if (fd >= FD_SETSIZE) {        WARN("Got fd >= FD_SETSIZE.");        close(fd);	return;    }#ifdef DEBUGNONINET    /* This shows up due to race conditions in some Linux kernels       when the client closes the socket sometime between       the select() and accept() syscalls.       Code and description by Larry Doolittle <ldoolitt@boa.org>     */#define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x)))    if (remote_addr.sin_family != AF_INET) {        struct sockaddr *bogus = (struct sockaddr *) &remote_addr;        char *ap, ablock[44];        int i;        close(fd);        log_error_time();        for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) {            *ap++ = ' ';            *ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f);            *ap++ = HEX(bogus->sa_data[i] & 0x0f);        }        *ap = '\0';        fprintf(stderr, "non-INET connection attempt: socket %d, "                "sa_family = %hu, sa_data[%d] = %s\n",                fd, bogus->sa_family, remote_addrlen, ablock);        return;    }#endif/* XXX Either delete this, or document why it's needed *//* Pointed out 3-Oct-1999 by Paul Saab <paul@mu.org> */#ifdef REUSE_EACH_CLIENT_CONNECTION_SOCKET    if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,                    sizeof (sock_opt))) == -1) {        DIE("setsockopt: unable to set SO_REUSEADDR");    }#endif    len = sizeof(salocal);    if (getsockname(fd, (struct sockaddr *) &salocal, &len) != 0) {        WARN("getsockname");        close(fd);        return;    }    conn = new_request();    if (!conn) {        close(fd);        return;    }    conn->fd = fd;    conn->status = READ_HEADER;    conn->header_line = conn->client_stream;    conn->time_last = current_time;    conn->kacount = ka_max;    ascii_sockaddr(&salocal, conn->local_ip_addr, NI_MAXHOST);    /* nonblocking socket */    if (set_nonblock_fd(conn->fd) == -1)        WARN("fcntl: unable to set new socket to non-block");    /* set close on exec to true */    if (fcntl(conn->fd, F_SETFD, 1) == -1)        WARN("fctnl: unable to set close-on-exec for new socket");    /* Increase buffer size if we have to.     * Only ask the system the buffer size on the first request,     * and assume all subsequent sockets have the same size.     */    if (system_bufsize == 0) {        len = sizeof (system_bufsize);        if (getsockopt            (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0            && len == sizeof (system_bufsize)) {            /*               fprintf(stderr, "%sgetsockopt reports SNDBUF %d\n",               get_commonlog_time(), system_bufsize);             */            ;        } else {            WARN("getsockopt(SNDBUF)");            system_bufsize = 1;        }    }    if (system_bufsize < sockbufsize) {        if (setsockopt            (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &sockbufsize,             sizeof (sockbufsize)) == -1) {            WARN("setsockopt: unable to set socket buffer size");#ifdef DIE_ON_ERROR_TUNING_SNDBUF            exit(errno);#endif        }    }    /* for log file and possible use by CGI programs */    ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);    /* for possible use by CGI programs */    conn->remote_port = net_port(&remote_addr);    status.requests++;#ifdef USE_TCPNODELAY    /* Thanks to Jef Poskanzer <jef@acme.com> for this tweak */    {        int one = 1;        if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY,                       (void *) &one, sizeof (one)) == -1) {            DIE("setsockopt: unable to set TCP_NODELAY");        }    }#endif#ifndef NO_RATE_LIMIT    if (conn->fd > max_connections) {        send_r_service_unavailable(conn);        conn->status = DONE;        pending_requests = 0;    }#endif                          /* NO_RATE_LIMIT */    total_connections++;    enqueue(&request_ready, conn);}/* * Name: free_request * * Description: Deallocates memory for a finished request and closes * down socket. */static void free_request(request ** list_head_addr, request * req){    int i;    /* free_request should *never* get called by anything but       process_requests */    if (req->buffer_end && req->status != DEAD) {        req->status = DONE;        return;    }    /* put request on the free list */    dequeue(list_head_addr, req); /* dequeue from ready or block list */    if (req->logline)           /* access log */        log_access(req);    if (req->mmap_entry_var)        release_mmap(req->mmap_entry_var);    else if (req->data_mem)        munmap(req->data_mem, req->filesize);    if (req->data_fd)        close(req->data_fd);    if (req->post_data_fd)        close(req->post_data_fd);    if (req->response_status >= 400)        status.errors++;    for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i) {        if (req->cgi_env[i]) {            free(req->cgi_env[i]);        } else {            log_error_time();            fprintf(stderr, "Warning: CGI Environment contains NULL value" \                    "(index %d of %d).\n", i, req->cgi_env_index);        }    }    if (req->pathname)        free(req->pathname);    if (req->path_info)        free(req->path_info);    if (req->path_translated)        free(req->path_translated);    if (req->script_name)        free(req->script_name);    if ((req->keepalive == KA_ACTIVE) &&        (req->response_status < 500) && req->kacount > 0) {        int bytes_to_move;        request *conn = new_request();        if (!conn) {            /* errors already reported */            enqueue(&request_free, req);            close(req->fd);            total_connections--;            return;        }        conn->fd = req->fd;        conn->status = READ_HEADER;        conn->header_line = conn->client_stream;        conn->kacount = req->kacount - 1;        /* close enough and we avoid a call to time(NULL) */        conn->time_last = req->time_last;        /* for log file and possible use by CGI programs */        memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);        memcpy(conn->local_ip_addr, req->local_ip_addr, NI_MAXHOST);        /* for possible use by CGI programs */        conn->remote_port = req->remote_port;        status.requests++;        /* we haven't parsed beyond req->parse_pos, so... */        bytes_to_move = req->client_stream_pos - req->parse_pos;        if (bytes_to_move) {            memcpy(conn->client_stream,                   req->client_stream + req->parse_pos, bytes_to_move);            conn->client_stream_pos = bytes_to_move;        }        enqueue(&request_block, conn);        BOA_FD_SET(conn->fd, &block_read_fdset);        enqueue(&request_free, req);        return;    }    /*     While debugging some weird errors, Jon Nelson learned that     some versions of Netscape Navigator break the     HTTP specification.     Some research on the issue brought up:     http://www.apache.org/docs/misc/known_client_problems.html     As quoted here:     "     Trailing CRLF on POSTs     This is a legacy issue. The CERN webserver required POST     data to have an extra CRLF following it. Thus many     clients send an extra CRLF that is not included in the     Content-Length of the request. Apache works around this     problem by eating any empty lines which appear before a     request.     "     Boa will (for now) hack around this stupid bug in Netscape     (and Internet Exploder)     by reading up to 32k after the connection is all but closed.     This should eliminate any remaining spurious crlf sent     by the client.     Building bugs *into* software to be compatable is     just plain wrong     */    if (req->method == M_POST) {        char buf[32768];        read(req->fd, buf, 32768);    }    close(req->fd);    total_connections--;    enqueue(&request_free, req);    return;}/* * Name: process_requests * * Description: Iterates through the ready queue, passing each request * to the appropriate handler for processing.  It monitors the

⌨️ 快捷键说明

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