CVS diff for response.c between 1.18 and 1.9:

Revision 1.9 Revision 1.18
Line 4 Line 4
#include <sys/unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
 
#include <sys/uio.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <string.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <string.h> 
Line 11 Line 12
#include <stdlib.h> 
#include <time.h> 
#include <pth.h> 
#include <stdlib.h> 
#include <time.h> 
#include <pth.h> 
 
#include "cow.h" 
#include "request.h" 
#include "response.h" 
#include "mime.h" 
#include "request.h" 
#include "response.h" 
#include "mime.h" 
Line 19 Line 21
#include "defines.h" 
#include "logs.h" 
 
#include "defines.h" 
#include "logs.h" 
 
extern char *server_root;	/* config.c */
extern int ka_max_con;
extern time_t ka_max_dur;
extern int cow_noof;
 
 
// usually the size of response message headers is 120 bytes, 
// with body (e.g. "501 : Requested service ... " is 40 or so. 
// Thus 256 is more than enough. (but change it if necessary). 
// usually the size of response message headers is 120 bytes, 
// with body (e.g. "501 : Requested service ... " is 40 or so. 
// Thus 256 is more than enough. (but change it if necessary). 
Line 31 Line 28
char r100[HEADS]; 
char r101[HEADS]; 
 
char r100[HEADS]; 
char r101[HEADS]; 
 
char r200[HEADS]; 
 
char r201[HEADS]; 
char r202[HEADS]; 
char r203[HEADS]; 
char r201[HEADS]; 
char r202[HEADS]; 
char r203[HEADS]; 
Line 74 Line 70
char r504[HEADS]; 
char r505[HEADS]; 
 
char r504[HEADS]; 
char r505[HEADS]; 
 
 
int r100_len, r101_len, r201_len, r202_len, r203_len, r204_len, r205_len;
int r206_len, r300_len, r301_len, r302_len, r303_len, r304_len, r305_len;
int r306_len, r307_len, r400_len, r401_len, r402_len, r403_len, r404_len;
int r405_len, r406_len, r407_len, r408_len, r409_len, r410_len, r411_len;
int r412_len, r413_len, r414_len, r415_len, r416_len, r417_len, r500_len;
int r501_len, r502_len, r503_len, r504_len, r505_len;
 
/* initialize static reply contents */ 
/* for now, we use pth version */
/* initialize static reply contents */ 
/* for now, we use pth version */
#define COW_VERSION PTH_VERSION 
#define SERVER_STRING "cow" 
#define HTTPV "1.1"
#define HTTPV "1.1"
int response_init()
{

#define GEN_HEAD(BUF,STARTLINE,BODY)\
sprintf(BUF,\
"HTTP/" HTTPV " " STARTLINE "\r\n"\
"Server: cow/%x\r\n"\
"Connection: close\r\n"\
"Content-type: text/plain\r\n"\
"Content-Length: %d\r\n"\
"\r\n"\
BODY, COW_VERSION, strlen(BODY));

    GEN_HEAD(r200, "200 OK", "")	// don't use this
	GEN_HEAD(r200, "204 No Content", "204 : Requested file has no content")
	GEN_HEAD(r400, "400 Bad Request", "400 : Bad Request")
	GEN_HEAD(r401, "401 Unauthorized", "401 : Authorization failure")
	GEN_HEAD(r403, "403 Forbidden", "403 : Forbidden")
	GEN_HEAD(r404, "404 Not Found", "404 : Not Found")
	GEN_HEAD(r414, "414 Request-URI Too Long",
		 "414 : Requested URI is too long")
	GEN_HEAD(r500, "500 Internal Server Error",
		 "500 : Internal Server Error")
        GEN_HEAD(r501, "501 Not Implemented",
                 "501 : Requested service is not implemented")
	GEN_HEAD(r503, "503 Service Unavailable",
		 "503 : Requested service is not available") return 0;
}

inline int response_static(int fd, char *str) {
    COW_SEND(fd, str) return 0;
}

inline int response_204(int fd) {
    return response_static(fd, r204);
}
inline int response_400(int fd) {
    return response_static(fd, r400);
}
inline int response_404(int fd) {
    return response_static(fd, r404);
}
inline int response_414(int fd) {
    return response_static(fd, r414);
}
inline int response_500(int fd) {
    return response_static(fd, r500);
}
inline int response_501(int fd) {
/*
 * Some things never change...keep these in a static memory buffer.  Note that
 * the final header in this string should not include the \r\n line terminator.
 */
static char constant_headers[] = "Server: " SERVER_STRING "/" VERSION ", Pth " PTH_VERSION_STR "\r\n";
static int constant_headers_len;

/* Variables used by setsockopt */
static int one = 1;
static int zero = 0;

#define GEN_HEAD(BUF,STARTLINE,BODY) {              \
    sprintf(BUF,                                    \
            "HTTP/" HTTPV " " STARTLINE "\r\n"      \
            "Connection: close\r\n"                 \
            "Content-type: text/plain\r\n"          \
            "Content-Length: %d\r\n"                \
            "%s"                                    \
            "\r\n"                                  \
            BODY, strlen(BODY), constant_headers);  \
    BUF##_len = strlen(BUF);                        \
}

/****
 * response_init()
 *
 * Generates the standard error pages that we may want to send back to the
 * user.  The entire response (including headers) is contained in a single
 * buffer and can be written with just one write() system call.
 ****/
int response_init() {
    constant_headers_len = strlen(constant_headers);

    GEN_HEAD(r204, "204 No Content", "204 : Requested file has no content")
    GEN_HEAD(r400, "400 Bad Request", "400 : Bad Request")
    GEN_HEAD(r401, "401 Unauthorized", "401 : Authorization failure")
    GEN_HEAD(r403, "403 Forbidden", "403 : Forbidden")
    GEN_HEAD(r404, "404 Not Found", "404 : Not Found")
    GEN_HEAD(r414, "414 Request-URI Too Long",
             "414 : Requested URI is too long")
    GEN_HEAD(r500, "500 Internal Server Error",
             "500 : Internal Server Error")
    GEN_HEAD(r501, "501 Not Implemented",
             "501 : Requested service is not implemented")
    GEN_HEAD(r503, "503 Service Unavailable",
             "503 : Requested service is not available") return 0;
}
 
    return response_static(fd, r501);
}
inline int response_503(int fd) {
    return response_static(fd, r503);
}
inline int response_default(int fd) {
    return response_static(fd, r503);
}
 
 
/*  
put => just put the entity body at specified uri (server takes care it all). 
 
/*  
put => just put the entity body at specified uri (server takes care it all). 
Line 146 Line 141
    return (int)req; 

 
    return (int)req; 

 
 
#ifdef ENABLE_PUT 
int response_put(msg * req) 

char *pathname = req->p_pathname; 
int response_put(msg * req) 

char *pathname = req->p_pathname; 
Line 160 Line 156
    if ((MAX_PATH_LENGTH - strlen(server_root) - 1) < 
(unsigned)(req->p_uri_len)) { 
/* 414 "Request-URI Too Large" */ 
    if ((MAX_PATH_LENGTH - strlen(server_root) - 1) < 
(unsigned)(req->p_uri_len)) { 
/* 414 "Request-URI Too Large" */ 
	response_414(req->fdp); 
	STATIC_RESPONSE(req->fdp, 414); 
	return -1; 

pathname[0] = '\0'; 
	return -1; 

pathname[0] = '\0'; 
Line 174 Line 170
#ifdef LOGGING 
fprintf(ELOG, "PUT: Failed to open %s\n", pathname); 
#endif 
#ifdef LOGGING 
fprintf(ELOG, "PUT: Failed to open %s\n", pathname); 
#endif 
	response_404(req->fdp); 
	STATIC_RESPONSE(req->fdp, 404); 
	return -1;
	return -1;
    }
    } else { 
    else
 
	++cow_noof;
	++cow_noof;
 
 
/* 
stat (pathname, &ifstat); 
 
/* 
stat (pathname, &ifstat); 
Line 211 Line 207
		int ReaD; 
int siz = sizeof(BUF); 
pth_event_t ev = NULL; 
		int ReaD; 
int siz = sizeof(BUF); 
pth_event_t ev = NULL; 
		ev = pth_event(PTH_EVENT_TIME, pth_timeout(xS, xU)); 
 
		while (1) { 
bzero(BUF, siz); 
ReaD = -1;
		while (1) { 
bzero(BUF, siz); 
ReaD = -1;
 
                    ev = pth_event(PTH_EVENT_TIME, pth_timeout(xS, xU)); 
		    ReaD = pth_read_ev(req->fdp, BUF, (size_t) siz, ev);
		    ReaD = pth_read_ev(req->fdp, BUF, (size_t) siz, ev);
 
                    pth_event_free(ev, PTH_FREE_THIS); 
		    if (ReaD <= 0) {
		    if (ReaD <= 0) {
			printf("\n !!! fuck end !!!\n"); 
                        printf("Error!\n"); 
			break; 

if (0 > pth_write(req->fdd, BUF, ReaD) 
			break; 

if (0 > pth_write(req->fdd, BUF, ReaD) 
Line 235 Line 232

pth_yield(NULL);  
*/ 

pth_yield(NULL);  
*/ 
		    ev = pth_event(PTH_EVENT_TIME, pth_timeout(xS, xU)); 
 
		}		// end of while 
		}		// end of while 
		pth_event_free(ev, PTH_FREE_THIS); 
 
		COW_CLOSE(req->fdd) return 0; 

 
		COW_CLOSE(req->fdd) return 0; 

 
Line 271 Line 266
	left += header_len; 
while (left > 0) { 
sent = pth_send(req->fdp, req->r_buf + offset, left, 0); 
	left += header_len; 
while (left > 0) { 
sent = pth_send(req->fdp, req->r_buf + offset, left, 0); 
 
            if (sent < 0)
                return -1; 
	    pth_yield(NULL); 


return 0; 
}
	    pth_yield(NULL); 


return 0; 
}
int response_get(msg * req)
{ 
#endif

int response_get(msg* req) { 
    char *pathname = req->p_pathname; 
struct stat ifstat;
    char *pathname = req->p_pathname; 
struct stat ifstat;
    size_t header_len;

    bzero(req->r_buf, sizeof(req->r_buf));

    if ((MAX_PATH_LENGTH - strlen(server_root) - 1) <
	(unsigned)(req->p_uri_len)) {
	/* 414 "Request-URI Too Large" */
//write(1,&" (414@response_get) ", 20);
	response_414(req->fdp); 
    int rv = 0;

#ifdef HAVE_LIBDMALLOC
    /*
     * Signals don't seem to work properly when linked with dmalloc; we need
     * some other way to shutdown.  Since dmalloc is only going to be linked
     * during debugging, this should be fine.
     */
    if (0 == strcmp(req->p_uri, "/SHUTDOWN")) {
 
        fprintf(stderr, "SHUTTING DOWN\n");
        exit(0);
    }
#endif

    /*
     * Make sure the URI doesn't force us to build a path that's too long to
     * fit in our buffers.
     */
    if (server_root_len + req->p_uri_len + 1 > MAX_PATH_LENGTH) {
        /* Request URI is too long; respond with 414 */
	STATIC_RESPONSE(req->fdp, 414);
	return -1; 
}
	return -1; 
}
    pathname[0] = '\0';
    strcat(pathname, server_root); 
    /* Make sure the URI starts with a slash */
 
    if (req->p_uri[0] != '/') {
        STATIC_RESPONSE(req->fdp, 404);
        return -1;
    }

    strcpy(pathname, server_root);
    strcat(pathname, req->p_uri);
    strcat(pathname, req->p_uri);
 
    /* Does the URI refer to a directory?  If so, search for an index file */ 
    stat(pathname, &ifstat);
    stat(pathname, &ifstat);
/* 1 tmp_cgi */
    if (0 == strncmp(req->p_uri, "/cgi-bin", 8) || 
    if (S_ISDIR(ifstat.st_mode)) {
        /* Add a trailing slash if we don't already have one */
        if (pathname[req->p_uri_len + server_root_len - 1] != '/')
 
            pathname[req->p_uri_len + server_root_len] = '/';
        req->fdd = find_index_file(pathname);

        /* If no index found, just return a 404.  TODO: Generate index */
        if (req->fdd == -1) {
            STATIC_RESPONSE(req->fdp, 404);
            return -1;
        }

        /*
         * We need to stat the actual file that was opened so that we know
         * its size later.
         */
        fstat(req->fdd, &ifstat);
    } 
    
    /* Does the URI refer to a CGI script (if enabled)?  If so, flag it. */
    else if (0 == strncmp(req->p_uri, "/cgi-bin", 8) ||
	0 == strncmp(req->p_uri, "cgi-bin", 7)) { 
req->is_cgi = 1; // revise to CGI or NPH
	0 == strncmp(req->p_uri, "cgi-bin", 7)) { 
req->is_cgi = 1; // revise to CGI or NPH
    }

/* 1 end of tmp_cgi */

    if ('/' == pathname[strlen(pathname) - 1])
	strcat(pathname, "index.html");
    else if (S_ISDIR(ifstat.st_mode)) {
	strcat(pathname, "/index.html");
    }

/* 2 tmp_cgi */
/* init_cgi */
    if (req->is_cgi) {
	printf("init_cgi...\n");
	if (-1 == (req->fdd = open(pathname, O_RDONLY | S_IROTH | S_IXOTH))) {
	    perror("open");
	    return -1;
	}
	++cow_noof;
	return tmp_cgi(req);	// see cgi.c
    }
/* 2 end of tmp_cgi */

    /* init_get */
    req->fdd = open(pathname, O_RDONLY);
    if (-1 == req->fdd) { 
        return tmp_cgi(req);	// see cgi.c
    }

    /* Regular file; just open it for reading */
    else {
        req->fdd = open(pathname, O_RDONLY);
        if (req->fdd == -1) {
            if (errno == EACCES) {
                STATIC_RESPONSE(req->fdp, 403);
                LOG1(ELOG, "GET: 403 %s", pathname);
            } else {
                STATIC_RESPONSE(req->fdp, 404);
                LOG1(ELOG, "GET: 404 %s", pathname);
            }
            return -1;
        }
        ++cow_noof;
    }

    /* Is the response file empty? */
    if (0 == (req->r_filesize = ifstat.st_size)) {
        STATIC_RESPONSE(req->fdp, 204);
    }

    req->r_mimes = get_mime_type(pathname);
 
    // fix here s.t. proper header (ie. keepalive etc) would be generated.
    // request is GET, and uri found, so compose a header for 200
    send_header_200(req);

    if (M_HEAD == req->p_method)
        return 0;

#ifdef USE_SENDFILE
    /*
     * Using sendfile() should give us the best performance since it can use
     * the "zero-copy" kernel feature to avoid any buffer copies.  Although
     * many OS's have sendfile(), they almost all have different options and
     * semantics, so this is really Linux-specific.  Also note that there is
     * no non-blocking version of this call so there is no concurrency
     * possible here.  Depending on the size of the files, this may or may
     * not be an issue.
     */
    {
        int offset = 0;
        int rv;

        /*
         * TCP_CORK prevents the transmission of partial packets.  I.e. it
         * forces us to wait and combine the response body with the response
         * headers.  This is linux-specific, but sendfile() really is too,
         * so we're locked in anyway.
         */
        //setsockopt(req->fdp, SOL_TCP, TCP_CORK, &one, sizeof(one));
        if (pth_write(req->fdp, req->r_buf, header_len) == -1) {
            perror("header write()");
            exit(1);
        }
        if ((rv = sendfile(req->fdp, req->fdd, &offset, req->r_filesize)) == -1) {
            perror("sendfile");
            exit(1);
        }
        assert(rv == req->r_filesize);
        //setsockopt(req->fdp, SOL_TCP, TCP_CORK, &zero, sizeof(zero));

        COW_CLOSE(req->fdd);
        return 0;
    }
#endif


    /* memory map the file and then send it to the socket */
    {
        ssize_t sent;
        ssize_t length;
        ssize_t offset = 0;

        char *m;
        length = req->r_filesize;
        m = mmap(0, length, PROT_READ, MAP_FILE|MAP_SHARED, req->fdd, 0);
        if (NULL == m) {
            STATIC_RESPONSE(req->fdp, 500);
            COW_CLOSE(req->fdd);
            return -1;
        }

        /* Send the body of the requested page */
        sent = cow_write(req->fdp, m, req->r_filesize);
        if (sent < req->r_filesize) {
            /* Some kind of error */
            rv = -1;
#ifdef LOGGING
#ifdef LOGGING
	fprintf(ELOG, "GET: 404 %s (%s)\n", pathname, strerror(errno));
#endif
	//printf("cow_noof is %d\n", cow_noof);
	//write(1,&" (RG 404@response_get) ", 22);
	response_404(req->fdp);
	return -1;
    }
    ++cow_noof;

    stat(pathname, &ifstat);

    req->r_mimes = get_mime_type(pathname);
            fprintf(ELOG, "Failed to write part of %s to socket; "
                          "already sent %d bytes, remaining were "
                          "not sent.\n",
                          req->p_uri,
                          sent,
                          left-sent);
#endif /* LOGGING */
        }

        /* Unmap the file from memory */
	if (munmap(m, length))
            perror("munmap"); 
    if (0 == (req->r_filesize = ifstat.st_size))
	return response_204(req->fdp);
    // fix here s.t. proper header (ie. keepalive etc) would be generated.

    // request is GET, and uri found, so compose a header for 200
    req->r_buf[0] = '\0';
    compose_header_200(req);	// add keepalive to this func.

    header_len = strlen(req->r_buf);

    if (M_HEAD == req->p_method) {
	pth_send(req->fdp, req->r_buf, header_len, 0);
	COW_CLOSE(req->fdd) return 0;
    }

    {				// mmap 
	ssize_t sent;
	ssize_t left, length;
	ssize_t offset = 0;

#define MAP_OPTIONS MAP_FILE|MAP_PRIVATE	/* linux */
	char *m;
	length = left = req->r_filesize;
	m = mmap(0, left, PROT_READ, MAP_OPTIONS, req->fdd, 0);
	if (NULL == m) {
	    //write(1,&" (500@response_get) ", 20);
	    response_500(req->fdp);
	    COW_CLOSE(req->fdd) return -1;
	}

// send header    
	{
	    int ret_val;
	    COW_SEND_R(req->fdp, req->r_buf, ret_val);
	    if (0 > ret_val) {
//printf("sent header FAILED w/ ret_val = %d\n", ret_val);
		COW_CLOSE(req->fdd) return -1;
	    }
	}

// send body
	{
//pth_fdmode(req->fdp, PTH_FDMODE_BLOCK)
	    pth_fdmode(req->fdp, PTH_FDMODE_NONBLOCK);
// here we played w/ pth fdmode a bit.
// old version of pth didn't work w/ block (and it does not make fd
// non-blocking internally anyways), so i made this option nonblock
// explicitly. pth1.4 or later implicitly make fd nonblock.

	    while (left > 0) {
		sent = 0;
		// do NOT use send_ev  (see defines.h COW_SEND_EV)

// w/ implicit =  NOT work
// w/ explicit block = NOT works
// w/ explicit nonblock = works
//      sent = pth_send(req->fdp, m+offset, left, 0);

// explicit block -> stack
// explicit nonblock -> works fine
// implicit (by default) -> stack
//      sent = pth_write(req->fdp, m+offset, left);

// works (w/ or w/o fdmode block) (i.e. default)
// works (w/ fdmode NON-block)
// works (w/ fdmode block)
		sent = write(req->fdp, m + offset, left);

                /* Can't immediately write buffer; yield then try again */
                if (sent < 0 && (errno == EAGAIN || errno == EINTR)) {
                    pth_yield(NULL);
                    continue;
                }

		//pth_yield(NULL);
		left -= sent;
		offset += sent;

		if (left > 0 || sent <= 0) {
		    PRINT5("<fd=%d, sent=%d, left=%d, offset=%d, len=%d>\n",
			   req->fdp, sent, left, offset, length);

		}

		if (0 > sent) {
                    printf(" (xxx@response_get) \n");
                    perror("Sending");
                }

		    //write(1, &" (xxx@response_get) \n\0", 21);
		    //response_500(req); // error during response, so no more send
		    if (munmap(m, length)) {
			perror("munmap");
		    }
		    COW_CLOSE(req->fdd) return -1;
		}
	    }
	}
	if (munmap(m, length)) {
	    perror("munmap");
	}
 
	COW_CLOSE(req->fdd);
	COW_CLOSE(req->fdd);
    }				// end mmap
    return 0;
}

void compose_header_200(msg * req) 
    }
    return rv;
}

 
void send_header_200(msg * req)
{
{
    strcat(req->r_buf, "HTTP/1.0 200 OK\r\n");
    add_http_headers(req); 
    cow_write(req->fdp, "HTTP/1.0 200 OK\r\n", 17);
    send_http_headers(req); 

 
// inline

 
// inline
void add_http_headers(msg * req) 
void send_http_headers(msg * req) 

char rfc822_time_buf[32]; // ={'\0'}; 
char *s; 

char rfc822_time_buf[32]; // ={'\0'}; 
char *s; 
Line 465 Line 464
 
time(&mytime); 
mytm = (struct tm *)gmtime(&mytime); 
 
time(&mytime); 
mytm = (struct tm *)gmtime(&mytime); 
    // strftime(s, 128, "%a, %d %b %Y %H:%M:%S %Z", mytm);
    // strftime(s, 128, "%a, %d %b %Y %H:%M:%S %z", mytm);
    strftime(s, 128, "%d %b %Y %H:%M %Z", mytm);	// shortest possible
    // printf( "%s\n", s);
    strcat(req->r_buf, "Date: ");
    strcat(req->r_buf, s);
    strcat(req->r_buf, "\r\nServer: Cow/0.01\r\n");

    // print_ka_pharse(req); // not yet
    add_keepalive_lines(req);
    strftime(s, 128, "%d %b %Y %H:%M %Z\r\n", mytm);	// shortest possible

    cow_write(req->fdp, "Date: ", 6);
    cow_write(req->fdp, s, strlen(s));
    cow_write(req->fdp, constant_headers, constant_headers_len);

    send_keepalive_lines(req);
    send_content_type(req);
    send_content_length(req);
    //send_last_modified(req);
    cow_write(req->fdp, "\r\n", 2); 
    add_content_type(req);
    add_content_length(req);
//add_last_modified(req);

    // end of header.
    strcat(req->r_buf, "\r\n");
 

 
// inline

 
// inline
void add_content_type(msg * req) 
void send_content_type(msg * req) 
{
{
    strcat(req->r_buf, "Content-Type: ");
    strcat(req->r_buf, req->r_mimes);
    strcat(req->r_buf, "\r\n"); 
    cow_write(req->fdp, "Content-type: ", 14);
    cow_write(req->fdp, req->r_mimes, strlen(req->r_mimes));
    cow_write(req->fdp, "\r\n", 2); 

 
// inline

 
// inline
void add_content_length(msg * req) {
    req = 0;        /* get rid of compiler warning */
/*
  char buf[32]={'\0'};
  strcat(req->r_buf, "Content-Length: ");
  //sprintf(buf, "%lu\r\n\0", (long unsigned)(req->r_filesize));
  sprintf(buf, "%d\r\n\0", (int)(req->r_filesize));
void send_content_length(msg * req) {
    static char buf[30] = {'\0'};
    int buflen;
    
    buflen = sprintf(buf, "%d\r\n", req->r_filesize);
    cow_write(req->fdp, "Content-Length: ", 16);
    cow_write(req->fdp, buf, buflen); 
  strcat(req->r_buf, buf);
*/
 

 
// inline

 
// inline
void add_keepalive_lines(msg * req) 
void send_keepalive_lines(msg * req) 
{
{
/*
  if (req->ka_count >0
  &&  req->ka_status == KA_ACTIVE
  )
//&&  req->response_status < 500)
  {
    char buf_ka_timeout[32];
    char buf_ka_count[32];
    sprintf(buf_ka_timeout, "timeout=%lu, ", ka_max_dur);
    sprintf(buf_ka_count,   "max=%d\r\n", req->ka_count);
    strcat(req->r_buf, "Connection: Keep-Alive\r\nKeep-Alive: timeout=15\r\n");
  }
  else
*/ 
#ifndef DISABLE_KEEPALIVE
    if (req->ka_count >0 && req->ka_status == KA_ACTIVE) {
        char buf_ka_timeout[32];
        char buf_ka_count[32];
        int bkt_len, bkc_len;
        bkt_len = sprintf(buf_ka_timeout, "timeout=%lu, ", ka_max_dur);
        bkc_len = sprintf(buf_ka_count,   "max=%d\r\n", req->ka_count);
        cow_write(req->fdp, "Connection: Keep-Alive\r\nKeep-Alive: ", 36);
        cow_write(req->fdp, buf_ka_timeout, bkt_len);
        cow_write(req->fdp, buf_ka_count, bkc_len);
    } else {
        req->ka_status = KA_INACTIVE;
        cow_write(req->fdp, "Connection: close\r\n", 19);
    }
#else 
    req->ka_status = KA_INACTIVE;
    req->ka_status = KA_INACTIVE;
    strcat(req->r_buf, "Connection: close\r\n");
}
 
    cow_write(req->fdp, "Connection: close\r\n", 19);
#endif
}
 

/****
 * find_index_file()
 *
 * Given a directory, searches for a suitable index file based on server
 * settings and returns a file descriptor to it.
 *
 * This function reads the list of suitable index filenames from the
 * index_files linked list.
 *
 * Important Note:  this function modifies filename so that it includes
 *      the name of the actual index file selected.
 *
 * @param pathname The pathname of the directory to scan for an index file
 *
 * @return A file descriptor to a suitable index file, or -1 if no suitable
 *         index file was found.
 ****/
int find_index_file(char* pathname) {
    idxfilename* i;
    int fd;
    int pathlen;
    
    pathlen = strlen(pathname);
    for (i = index_files; i != NULL; i = i->next) {
        strcpy(&pathname[pathlen], i->name);
        if (fd = open(pathname, O_RDONLY) != -1) {
            cow_noof++;
            return fd;
        }
    }

    /* No suitable index files */
    pathname[pathlen] = '\0';
    return -1;
}

#ifdef USE_TCPCORK
#define SOCKET_FLUSH(S) setsockopt(S, SOL_TCP, TCP_CORK, &zero, sizeof(zero))
#define SOCKET_HALFCLOSE(S) shutdown(S, SHUT_WR)
#define SOCKET_FULLCLOSE(S) close(S)
#define SOCKET_READ pth_read_ev
#else /* not USE_TCPCORK */
#define SOCKET_FLUSH(S) ap_bflush(S)
#define SOCKET_HALFCLOSE(S) shutdown(S->fd, SHUT_WR)
#define SOCKET_FULLCLOSE(S) ap_bclose(S)
#define SOCKET_READ ap_bread
#endif

/****
 * cow_close_socket()
 *
 * Cleanly closes a socket connection.  If there's unsent data in the buffer,
 * that will be sent first.  We also implement the 'lingering close' required
 * by HTTP/1.1.
 *
 * @param sock The socket to close
 ****/
void cow_close_socket(SOCKTYPE sock) {
    int rv;
    char junkbuf[2048];

    SOCKET_FLUSH(sock);

#ifndef USE_TCPCORK
    /* Set 'end of output' flag on buffer so we don't reflush later */
    ap_bsetflag(sock, B_EOUT, 1);
#endif

    if (SOCKET_HALFCLOSE(sock) == -1) {
        /* Closing half the socket failed; give up and do a regular close */
        SOCKET_FULLCLOSE(sock);
        return;
    }

    do {
        /*
         * Read anything coming in over the network and discard it.  Keep
         * doing this until the client closes the connection or until we've
         * been idle for two seconds.
         *
         * This 'lingering close' is important so that if we decide to close
         * a persistent connection, the client won't send something which makes
         * us generate a RST --- our RST could get back to the client before
         * earlier, valid data and cause the client to close its connection
         * before the valid data showed up.  See section 8 of the
         * draft-ietf-http-connection-00.txt document (available many places
         * on the web) for more details.
         */
         pth_event_t timeout = pth_event(PTH_EVENT_TIME, pth_timeout(2, 0));
         rv = SOCKET_READ(sock, junkbuf, sizeof(junkbuf), timeout);
         pth_event_free(timeout, PTH_FREE_THIS);
    } while (rv > 0);

    /*
     * Okay, either the client closed the connection or the connection was
     * idle too long.  Do a real close now.
     */
    SOCKET_FULLCLOSE(sock);
    
    --cow_noof;                                                 \
}


Legend
Lines deleted from 1.18  
Lines Modified
  Lines added in revision 1.9