CVS diff for response.c between 1.18 and 1.14:

Revision 1.14 Revision 1.18
Line 70 Line 70
char r504[HEADS]; 
char r505[HEADS]; 
 
char r504[HEADS]; 
char r505[HEADS]; 
 
#ifdef RESPONSE_CONCURRENCY
/* Number of threads sending data right now */
int active_responders = 0;
#endif 
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 SERVER_STRING(VER) "cow" #VER 
#define SERVER_STRING "cow" 
#define HTTPV "1.1" 
 
/* 
* 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. 
*/
#define HTTPV "1.1" 
 
/* 
* 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(PTH_VERSION); 
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; 
 
/* 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"                            \
            "\r\n"                              \
            BODY, strlen(BODY), constant_headers); 
#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() 
 
/**** 
* response_init() 
Line 108 Line 113
 * buffer and can be written with just one write() system call. 
****/ 
int response_init() { 
 * 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(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") 
Line 134 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 199 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 223 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 266 Line 273

return 0; 

return 0; 
 
#endif 
 
int response_get(msg* req) { 
char *pathname = req->p_pathname; 
struct stat ifstat;
 
int response_get(msg* req) { 
char *pathname = req->p_pathname; 
struct stat ifstat;
    size_t header_len;
    int rv = 0; 
    //bzero(req->r_buf, sizeof(req->r_buf));
 
 
#ifdef HAVE_LIBDMALLOC 
/* 
 
#ifdef HAVE_LIBDMALLOC 
/* 
Line 358 Line 364
 
// fix here s.t. proper header (ie. keepalive etc) would be generated. 
// request is GET, and uri found, so compose a header for 200 
 
// 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.
    send_header_200(req);

    if (M_HEAD == req->p_method) 
    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;
        return 0;
 
 
#ifdef USE_SENDFILE 
/* 
 
#ifdef USE_SENDFILE 
/* 
Line 387 Line 387
         * 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, 
         * 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 if we're locked in anyway. 
         * so we're locked in anyway. 
         */
         */
        setsockopt(req->fdp, SOL_TCP, TCP_CORK, &one, sizeof(one));
        if (write(req->fdp, req->r_buf, header_len) == -1) { 
        //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); 
            perror("header write()"); 
exit(1); 
Line 398 Line 398
            perror("sendfile"); 
exit(1); 
            perror("sendfile"); 
exit(1); 
        setsockopt(req->fdp, SOL_TCP, TCP_CORK, &zero, sizeof(zero)); 
        assert(rv == req->r_filesize);
 
        //setsockopt(req->fdp, SOL_TCP, TCP_CORK, &zero, sizeof(zero));
 
COW_CLOSE(req->fdd); 
return 0; 
 
COW_CLOSE(req->fdd); 
return 0; 
Line 408 Line 409
 
/* memory map the file and then send it to the socket */ 
 
/* memory map the file and then send it to the socket */ 
#ifdef USE_WRITEV
        struct iovec vec[2];
        int i;
#endif 
 
        ssize_t sent;
        ssize_t sent;
        ssize_t left, length; 
        ssize_t length; 
        ssize_t offset = 0; 
 
char *m;
        ssize_t offset = 0; 
 
char *m;
        length = left = req->r_filesize;
        m = mmap(0, left, PROT_READ, MAP_FILE|MAP_SHARED, req->fdd, 0); 
        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; 

        if (NULL == m) { 
STATIC_RESPONSE(req->fdp, 500); 
COW_CLOSE(req->fdd); 
return -1; 

#ifdef RESPONSE_CONCURRENCY
        /* Don't respond until there are few enough other responding threads */
        while (active_responders >= RESPONSE_CONCURRENCY)
            pth_yield(NULL);
        active_responders++;
#endif

#ifdef USE_WRITEV
        vec[0].iov_base = req->r_buf;
        vec[0].iov_len  = strlen(req->r_buf);
        vec[1].iov_base = m;
        vec[1].iov_len  = req->r_filesize;
        if (writev_all(req->fdp, vec, 2) < 0)
        /* 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
            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 */ 
            fprintf(ELOG, "Failed to send part of %s\n", req->p_uri);

#else /* USE_WRITEV -> false */
        // send header
        COW_SEND_R(req->fdp, req->r_buf, sent);
        if (0 > sent) {
            COW_CLOSE(req->fdd);
            return -1;
 
        }
        }
        /* Send the body of the requested page */
        while (left > 0) {
            errno = 0;
            sent = pth_send(req->fdp, m + offset, left, 0);
            if (sent < left && errno && errno != EINTR) {
                /* Some kind of error */
#ifdef LOGGING
                fprintf(ELOG, "Failed to write part of %s to socket; "
                              "already sent %d bytes, remaining were "
                              "not sent.\n",
                              req->p_uri,
                              offset,
                              left);
#endif /* LOGGING */
                if (munmap(m, length))
                    perror("munmap");
                COW_CLOSE(req->fdd);
                return -1;
            }

            /* Write successful */
            left -= sent;
            offset += sent;
	}
#endif /* USE_WRITEV */

#ifdef RESPONSE_CONCURRENCY
        /* Done responding; update # of active responders */
        active_responders--;
#endif 
 
 
/* Unmap the file from memory */ 
if (munmap(m, length))
 
/* Unmap the file from memory */ 
if (munmap(m, length))
	    perror("munmap"); 
            perror("munmap"); 
	COW_CLOSE(req->fdd); 
}
	COW_CLOSE(req->fdd); 
}
    return 0;
}

/****
 * writev_all()
    return rv;
}


void send_header_200(msg * req) 
 *
 * Although building the iovec structures for writev() is simple, figuring
 * out what to do when only part of the data was written is a real pain.
 * This function will continue writev'ing until everything has been written
 * or until an error occurs.  This code is almost directly out of Apache's
 * source code.
 *
 * @param fd   File descriptor to write to
 * @param vec  iovec pointing to set of buffers to send
 * @param nvec Number of buffers in iovec set
 *
 * @return 0 on success, -1 if writev fails with a fatal error (not EINTR)
 ****/
int writev_all(int fd, struct iovec* vec, int nvec) {
    int i = 0;
    int ret;

    i = 0;
    while (i < nvec) {
        do
            ret = pth_writev(fd, &vec[i], nvec - i);
        while (ret == -1 && errno == EINTR);
        if (ret == -1)
            return -1;

        /* recalculate vec to deal with partial writes */
        while (ret > 0) {
            if (ret < vec[i].iov_len) {
                vec[i].iov_base = (char *) vec[i].iov_base + ret;
                vec[i].iov_len -= ret;
                ret = 0;
            }
            else {
                ret -= vec[i].iov_len;
                ++i;
            }
        }
    }

    /* If we get here, we wrote it all */
    return 0;
}



void compose_header_200(msg * req)
 
{
{
    // TODO (mdr): modify for new writev code...
    strcat(req->r_buf, "HTTP/1.0 200 OK\r\n");
    cow_write(req->fdp, "HTTP/1.0 200 OK\r\n", 17);
    send_http_headers(req); 
    add_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 553 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

 
 

 
 
Line 651 Line 555
    return -1; 

 
    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.14