CVS diff for request.c between 1.15 and 1.6:

Revision 1.6 Revision 1.15
#include <sys/types.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "pth.h" 
 
#include "cow.h" 
#include "config.h" 
#include "cow_config.h" 
#include "cow.h" 
#include "config.h" 
#include "cow_config.h" 
Line 16 Line 6
#include "defines.h" 
#include "response.h" 
 
#include "defines.h" 
#include "response.h" 
 
int simple_parse_header(msg*);
int simple_parse_request(msg*);
int simple_parse_request_line(msg*);

/*
 * Name: read_request
 * Description: see request.h
 */

int read_request(msg * req) { 
#define MIN(a,b)  (a <= b ? a : b)

/****
 * read_request()
 *
 * Reads an HTTP request from a request socket.  This function will return
 * when it has read at least to the end of the message headers, although
 * it may also read part of the request body (e.g. for POST) as well.
 *
 * @param req A request structure containing the file descriptor to read from
 
 *            and buffers to read into.
 * @return 0 or 1 on success, -1 on failure
 ****/
int read_request(msg* req) {
    int ret_val; 
    int ret_val; 
    /* initialize fields in msg* req */
    /* Initialize connection settings */ 
    req->simple = 1;
 
    req->ka_status = KA_ACTIVE;         /* by default by http/1.1 */
    req->ka_status = KA_ACTIVE;         /* by default by http/1.1 */
    req->ka_count = ka_max_con - 1;     /* revise here, and read config && use int */ 
    req->ka_count = ka_max_con - 1;     /* Limit keep-alive req's remaining */ 
    req->ka_timeout = ka_max_dur + time(NULL);
    req->ka_timeout = ka_max_dur + time(NULL);
    req->status = START_LINE;
    req->is_cgi = 0;

    /* RFC 2616 - Section 5

       Request  = Request-Line              ; Section 5.1
       *(( general-header        ; Section 4.5
       | request-header         ; Section 5.3
       | entity-header ) CRLF)  ; Section 7.1
       CRLF
       [ message-body ]          ; Section 4.3

       Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
     */

    /* man 2 recv

       All  three  routines  return  the length of the message on
       successful completion.  If a message is too long to fit in
       the supplied buffer, excess bytes may be discarded depend-
       ing on the type of socket the  message  is  received  from
       (see socket(2)).

       If  no  messages  are available at the socket, the receive
       calls wait for a message to arrive, unless the  socket  is
    /* Keep-alive loop */
    for (;;) {
        pth_event_t ev_read;
        
        /* Set per-request settings */
        req->simple = 1;                    /* Assume HTTP/0.9 by default */
        req->status = START_LINE;
        req->is_cgi = 0;
        req->p_buf_left = MAX_BUF_SIZE - 1; // off 1 to put '\0'
        req->p_buf_head = req->p_buf;
        req->p_eof = 0;
        req->p_buf_read = 0;
        req->p_entity_body = NULL;

        /* Wait the "keep-alive" timeout even for new connections */
        ev_read = pth_event(PTH_EVENT_TIME,
                            pth_timeout(MIN(cow_rto_s, ka_max_dur), 0));
        ret_val = cow_read_line(req->fdp, req->p_buf, MAX_BUF_SIZE, ev_read);
        pth_event_free(ev_read, PTH_FREE_THIS);

        /* If a socket error/timeout occurs, just close the connection */
        if (ret_val < 0) {
            cow_close_socket(req->fdp);
            --cow_cur_conn; 
       nonblocking  (see  fcntl(2)) in which case the value -1 is
       returned and the external variable errno  set  to  EAGAIN.
       The  receive  calls normally return any data available, up
       to the requested amount, rather than waiting  for  receipt
       of the full amount requested.
     */

    /* additional initialization */
    req->p_buf_left = MAX_BUF_SIZE - 1; // off 1 to put '\0'
    req->p_buf_head = req->p_buf;
    req->p_eof = 0;
    req->p_buf_read = 0;
    //cleaning buf is not needed.
    //memset( req->p_buf, 0, sizeof(req->p_buf));
    //bzero(req->p_buf, sizeof(req->p_buf));

    req->p_entity_body = NULL;

    /* read the [first] portion for the first time */
    ret_val = read_request_more(req);

    for (;;)                    // keep-alive loop
    {
        if (0 > ret_val) {
            PRINT2("ret_val=%d < 0 @request.c <#openfile %d>\n", ret_val,
                   cow_noof);
            COW_CLOSE(req->fdp);
 
            return (ret_val); 
}
            return (ret_val); 
}
        if (1 == ret_val)       // read \r\n\r\n
        {
            // we can use simple_parse_request
            ret_val = simple_parse_request(req);
            if (0 > ret_val)    // error
            {
                // bad header. appropreate response has been sent.
                COW_CLOSE(req->fdp);
                return -1; 
        //printf("DEBUG: read line '%s' with retval %d, %d remains (%s)\n", req->p_buf, ret_val, req->fdp->incnt, req->fdp->inptr);
        
        /* Parse the first line of the request */
        ret_val = parse_request_line(req);
        if (ret_val < 0) {
            cow_close_socket(req->fdp);
            return ret_val;
        }

        /* Parse all header lines */
 
        for (;;) {
            ev_read = pth_event(PTH_EVENT_TIME,
                                pth_timeout(cow_rto_s, cow_rto_u));
            int len = cow_read_line(req->fdp, req->p_buf, MAX_BUF_SIZE, ev_read);
            pth_event_free(ev_read, PTH_FREE_THIS);
            if (len < 0) {
                /* Error; close connection */
                cow_close_socket(req->fdp);
                return len;
            } else if (len == 0) {
                /* Blank header line --> end of headers */
                break;
            }
            }
        }
        else                    // i.e. ( 0 == ret_val)
        {
            // The end of HTTP message was not \r\n\r\n , which means one of
            // 1. Read header not completed.
            // 2. Message contains body (and read part of the body).
            ret_val = parse_request(req);
            if (0 != ret_val) {
                COW_CLOSE(req->fdp);
                return -1;
            }
        }

        if ((KA_ACTIVE != req->ka_status) || (1 > --req->ka_count)) {
            COW_CLOSE(req->fdp) return ret_val;
        }

        /* read the [first] portion for the second time or later */
        ret_val = read_request_ka(req);

    }                           // end oF KEEP-ALIVE LOOP
}                               // end of read_request() 
            //printf("DEBUG: read header '%s' with ret val %d, %d remains (%s)\n", req->p_buf, len, req->fdp->incnt, req->fdp->inptr);

            /* Parse the header */
            parse_header(req);
        }

        /* Done reading/parsing headers.  Actually do the request now */
        cow_tot_parsed++;
        switch (req->p_method) {
            case M_HEAD:
            case M_GET:
                ret_val = response_get(req);
                break;
            case M_POST:                // not yet
                STATIC_RESPONSE(req->fdp, 501);
                ret_val = -1;
                break;
#ifdef ENABLE_PUT
            case M_PUT:
                PRINT("method is put....\n");
                process_header_end(req);
                ret_val = response_put(req);
 
                PRINT("breaking put\n");
                break;
#endif
            default:
                /* Send back a 503 if we get something we don't recognize */
                PRINT("def...\n");
                STATIC_RESPONSE(req->fdp, 503);
                ret_val = -1;
        }
#ifdef USE_TCPCORK
        /* Flush pending output */
        setsockopt(req->fdp, SOL_TCP, TCP_CORK, &zero, sizeof(zero));
#else
        ap_bflush(req->fdp);
#endif

        /* Any type of error condition means keep-alive can't continue. */
        if (ret_val < 0) {
            /* Error */
            cow_close_socket(req->fdp);
            --cow_cur_conn;
            return -1;
        }

        /*
         * If keep-alive is not active or if we've done our maximum number of
         * requests on this connection, close the connection.
         */
        if ((req->ka_status != KA_ACTIVE) || (--req->ka_count == 0)) {
            cow_close_socket(req->fdp);
            --cow_cur_conn;
            return 0;
        }

        /* Loop back and wait for another request on this socket */
    }
}
 
inline int read_request_ka(msg * req) { 
/* timeout */ 
pth_event_t ev_read; 
 
inline int read_request_ka(msg * req) { 
/* timeout */ 
pth_event_t ev_read; 
    // extend this to handle ka.
    ev_read = pth_event(PTH_EVENT_TIME, pth_timeout(ka_max_dur, 0));

    // read and recv are equivalent, so pick one
    // if ka timeout -> -1  
    /* Clear our buffers and prepare for the next request (if any) */
    req->p_buf_left = MAX_BUF_SIZE - 1; // off 1 to put '\0'
    req->p_buf_head = req->p_buf;
    req->p_header_end = NULL;
    req->p_eof = 0;
 
    req->p_buf_read = 0;
    req->p_entity_body = NULL;

    /*
     * Set the timeout for reading to be the minimum of either the
     * keepalive timeout or the regular socket timeout.
     */
    ev_read = pth_event(PTH_EVENT_TIME,
                        pth_timeout(MIN(cow_rto_s, ka_max_dur), 0));
#ifdef USE_TCPCORK
    /* Try to read another request from the socket; -1 here means timeout */
    req->p_buf_read = 
pth_read_ev(req->fdp, req->p_buf_head, req->p_buf_left, ev_read);
    req->p_buf_read = 
pth_read_ev(req->fdp, req->p_buf_head, req->p_buf_left, ev_read);
 
#else
    req->p_buf_read =
        ap_bread(req->fdp, req->p_buf_head, req->p_buf_left, ev_read);
#endif 
    pth_event_free(ev_read, PTH_FREE_THIS); 
    pth_event_free(ev_read, PTH_FREE_THIS); 
    // 0 is returned iff EOF was read, and it's the only char being read.
    //if( 0 == req->p_buf_read) { return 0; } 
 
    if (0 == req->p_buf_read) {
    if (0 == req->p_buf_read) {
 
        /* 0 is returned iff EOF was read, and it was the only char read */ 
        req->p_eof = 1;
        req->p_eof = 1;
 
        return -1;
    } else if (0 > req->p_buf_read) {
        /* read error, timeout or bad connection */
        return -1;
    }

    req->p_buf_left -= req->p_buf_read;
    req->p_buf_head += req->p_buf_read;
    //req->p_buf_head = (char *)(&req->p_buf_head[req->p_buf_read]);
    req->p_buf_head[0] = '\0';

    /*
     * If the end of the data we've read ends with \r\n\r\n or \n\n then we're
     * done reading the request.
     */
    if (strcmp((req->p_buf_head-4), "\r\n\r\n") == 0 ||
        strcmp((req->p_buf_head-4), "\n\n") == 0) {
        req->p_header_end = req->p_buf_head; 
        return 1;
        return 1;
    }

    if (0 > req->p_buf_read) {
        // read error, possible bad connection.
        return (-1);
    } else {
        /* Still haven't seen the end of the request */
        req->p_header_end = NULL;
        return 0;
    } 
    }

    req->p_buf_left -= req->p_buf_read;
    req->p_buf_head = (char *)(&req->p_buf_head[req->p_buf_read]);
    {
        char *t = req->p_buf_head;
        if (10 == (int)*(t - 1) &&
            13 == (int)*(t - 2) && 10 == (int)*(t - 3) && 13 == (int)*(t - 4)) {
            req->p_header_end = t;
            return 1;
        }
    }
    req->p_buf_head[0] = '\0';
    req->p_header_end = NULL;
    return 0;
 


inline int read_request_more(msg * req) {
    /* timeout */
    pth_event_t ev_read;

    // extend this to handle ka.
    ev_read = pth_event(PTH_EVENT_TIME, pth_timeout(cow_rto_s, cow_rto_u));

    // read and recv are equivalent, so pick one
    // if read timeout -> -1 
    req->p_buf_read =
        //1
        //pth_read_ev (req->fdp, req->p_buf_head, req->p_buf_left, ev_read) ;
        //2
        pth_read(req->fdp, req->p_buf_head, req->p_buf_left);
/****
 * parse_request_line()
 *
 * Parses the first line of an HTTP request.  The request type, URI and
 * protocol version information is all stored in the provided request
 * structure.
 *
 * @param req The HTTP request structure which contains the request buffers
 *            and which the request information should be stored to.
 *
 * @return 0 on success, -1 on failure
 ****/
int parse_request_line(msg* req) { 
    pth_yield(NULL);
    //3
    //read(req->fdp, req->p_buf_head, req->p_buf_left);
    //
    pth_event_free(ev_read, PTH_FREE_THIS);

    // 0 is returned iff EOF was read, and it's the only char being read.
    if (0 == req->p_buf_read) {
        req->p_eof = 1;
        return 1;
    }

    if (0 > req->p_buf_read) {
        // read error, possible bad connection.
        return (-1);
    }

    req->p_buf_left -= req->p_buf_read;
    req->p_buf_head = (char *)(&req->p_buf_head[req->p_buf_read]);
    req->p_buf_head[0] = '\0';
    req->p_header_end = NULL;
    {
        char *t = req->p_buf_head;
        if (10 == (int)*(t - 1) &&
                13 == (int)*(t - 2) && 10 == (int)*(t - 3) && 13 == (int)*(t - 4)) {
            req->p_header_end = t;
            return 1;
        }
    }
    return 0;
}

int parse_request(msg * req) {
    /*
       Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
     */

    int retval = 0;

    if (START_LINE == req->status)      // the first line
        retval = parse_request_line(req);

    if (retval)
        return retval;

    // parse header lines
    retval = parse_header(req);
    if (retval)
        return retval;

    switch (req->p_method) {
    case M_HEAD:
    case M_GET:
        response_get(req);
        break;
    case M_POST:                // not yet
        PRINT("method is post\n");
        response_post(req);
        PRINT("breaking post\n");
    case M_PUT:
        PRINT("method is put....\n");
        process_header_end(req);
        response_put(req);
        PRINT("breaking put\n");
        break;
    default:
        PRINT("def...\n");
        response_default(req->fdp);
        return -1;
    }

    return 0;
}

int parse_request_line(msg * req) {
 
    /* BNF: 

* Request-Line = Method SP Request-URI SP HTTP-Version CRLF 
*/ 
    /* BNF: 

* Request-Line = Method SP Request-URI SP HTTP-Version CRLF 
*/ 
    char *stop, *stop2; 
    char *uri, *stop; 
    char *logline = req->p_buf; 
 
/* BNF: Method */
    char *logline = req->p_buf; 
 
/* BNF: Method */
    if (!memcmp(logline, "GET ", 4)) 
    if (!memcmp(logline, "GET ", 4)) { 
        req->p_method = M_GET;
        req->p_method = M_GET;
    else if (!memcmp(logline, "PUT ", 4)) 
        uri = logline + 3;
 
    } else if (!memcmp(logline, "PUT ", 4)) {
        req->p_method = M_PUT;
        req->p_method = M_PUT;
    else if (!memcmp(logline, "HEAD ", 5)) 
        uri = logline + 3;
 
    } else if (!memcmp(logline, "HEAD ", 5)) {
        req->p_method = M_HEAD;
        req->p_method = M_HEAD;
    else if (!memcmp(logline, "POST ", 5)) 
        uri = logline + 4;
 
    } else if (!memcmp(logline, "POST ", 5)) {
        req->p_method = M_POST;
        req->p_method = M_POST;
    else {
        // bad request OR not implemented
        response_default(req->fdp);
        COW_CLOSE(req->fdp) return -1;
    }

    /* BNF: SP */
    /* Guaranteed to find ' ' since we matched a method above */
    stop = logline + 3;
    if (*stop != ' ') 
        uri = logline + 4;
    } else {
        // bad request or not implemented
        //printf("DEBUG: Service = '%s'\n", logline);
        STATIC_RESPONSE(req->fdp, 501);
        return -1;
    }

    /* Scan to start of non-whitespace (i.e. the URI) */
    while (*(++uri) == ' ')
 
        ;

    /* scan to end of URI */
    stop = uri;
    for (;;) {
        /*
         * End of URI will be a space (if we're using HTTP/1.0 or above) or
         * the null-terminator (if we got an HTTP/0.9 simple request).
         */
        if (*stop == '\0' || *stop == ' ')
            break;

        /*
         * \r should mean end of URI and be followed by \n, but since
         * cow_read_line already stripped trailing \r\n's, this must be
         * a stray (and an error).
         */
        if (*stop == '\r') {
            STATIC_RESPONSE(req->fdp, 400);
            return -1;
        }

        /* Not there yet... */
        ++stop;
        ++stop;
    /* scan to start of non-whitespace */
    while (*(++stop) == ' ') {
        if (stop > req->p_buf_head) {
            if (0 >= req->p_buf_left) {
    }

    /* If the URI is too long, return an error page */
    if (stop - uri > MAX_REQ_URI_LEN) {
        STATIC_RESPONSE(req->fdp, 414); 
                //response_400(req->fdp);
                //response_500(req->fdp);
                return -1;
            }
            --stop;
            if (0 > read_request_more(req))
                return -1;
        }
    }

    stop2 = stop;

    /* BNF: SP */
    /* scan to end of non-whitespace */
    while (*stop2 != '\0' && *stop2 != ' ') {
        ++stop2;
        if (stop2 > req->p_buf_head) {
            if (0 >= req->p_buf_left) {
                //response_500(req->fdp);
                //response_400(req->fdp);
                return -1;
            }
            --stop2;
            if (0 > read_request_more(req))
                return -1;
        }
    }

    if (stop2 - stop > MAX_REQ_URI_LEN) {
        response_414(req->fdp);
 
        return -1; 

        return -1; 

    req->p_uri_begin = stop;
    req->p_uri_end = stop2;

    memcpy(req->p_uri, stop, stop2 - stop);
    /* Record the URI in the request structure */
    req->p_uri_len = stop - uri;
    memcpy(req->p_uri, uri, req->p_uri_len);
    req->p_uri[req->p_uri_len] = '\0'; 
    req->p_uri[stop2 - stop] = '\0';
 
 
/* HTTP-Version */
 
/* HTTP-Version */
    if (*stop2 == ' ') { 
    if (*stop == ' ') { 
        /* if found, we should get an HTTP/x.x */ 
int p1, p2; 
        /* if found, we should get an HTTP/x.x */ 
int p1, p2; 
        if (sscanf(++stop2, "HTTP/%d.%d", &p1, &p2) == 2 && p1 >= 1) { 
        if (sscanf(++stop, "HTTP/%d.%d", &p1, &p2) == 2 && p1 >= 1) { 
            req->hv_major = p1; 
req->hv_minor = p2; 
req->simple = 0;
            req->hv_major = p1; 
req->hv_minor = p2; 
req->simple = 0;
            if (0 == p1 || 0 == p2) 
            if (p1 == 0 || p1+p2 < 2) { 
                req->ka_status = KA_INACTIVE;
                req->ka_status = KA_INACTIVE;
        }
        else {
            // log_error_time();
            // fprintf (stderr, "bogus HTTP version: \"%s\"\n", stop2);
            // 404 bad request (malformed syntax).
            response_400(req->fdp); 
            }
        } else {
#ifdef LOGGING
            fprintf(ELOG, "Malformed request '%s %s'\n",
                    req->p_uri, stop);
#endif
 
            STATIC_RESPONSE(req->fdp, 400);
            return -1; 
}
            return -1; 
}
    }
    else { 
    } else {
        /* No HTTP/x.y present; use HTTP/0.9 */ 
        req->simple = 1; 
req->ka_status = KA_INACTIVE; 

        req->simple = 1; 
req->ka_status = KA_INACTIVE; 

    while (*(++stop2) != '\0') {
    return 0; 
        if (stop2 > req->p_buf_head) {
            if (0 == req->p_buf_left)   // exceeded server capacity.
            {
                //response_500(req->fdp);
                return -1;
            }
            --stop2;
            if (0 > read_request_more(req))
                return -1;
        }

        if ('\r' == *(stop2) && '\n' == (*(1 + stop2))) {
            req->status = ONE_CRLF;
            req->p_pos = stop2 + 1;
            // at this point, we know the request-line can be processed
            // so, return to the caller
            return 0;
        }
    }
    // unreachable
    return -1;                  /* error */
 

 
/* 

 
/* 
Line 447 Line 379
   header fields if all parties in the communication recognize them to 
be request-header fields. Unrecognized header fields are treated as 
entity-header fields. 
   header fields if all parties in the communication recognize them to 
be request-header fields. Unrecognized header fields are treated as 
entity-header fields. 
                          
 
*/ 
*/ 
/*
 * Each option line end w/ \r\n.
 */ 
 
    char c; 
char *value; 
char *line; 
int check_CRLF; 
    char c; 
char *value; 
char *line; 
int check_CRLF; 
    req->header_line = 1 + req->p_pos;

    // process one line at a time.
    // return 0 on success
    // return -1 on error
    // return +1 on incomplete
 
 
    for (;;) {
    for (;;) {
/* 
 * At this point, one \r\n was just parsed.
 * So, another immediat \r\n means we got the end of the header.
 */
        line = req->header_line;

        if (('\r' == line[0]) && ('\n' == line[1])) {
            req->p_entity_body = &line[2];
            req->header_line = &line[2]; 
        line = req->p_buf;

        /*
         * Look for the ":" between the header name and value.  If we don't
         * find it, we'll just ignore this header and continue with the next
         * one.
         */
        value = strchr(line, ':');
        if (NULL == value) 
            return 0;
            return 0;
        }

        value = strchr(line, ':');
        if (NULL == value) {
            response_400(req->fdp);
        
        /*
         * Figure out which header this is; it looks like this code may have
         * been taken from Boa.
         */ 
            return -1;          // illegal header line
/****
          if ((line + strlen (line)) >= req->p_buf_head)
            {
              retval = read_request_more (req);
              if (0>retval)
                return -1;
              else
                continue;       // continue this for loop from the top
            }
          return -1;            // else error in format 
****/
        }
 
        *value++ = '\0'; 
to_upper(line); // header type is case insensitive
        *value++ = '\0'; 
to_upper(line); // header type is case insensitive
        // while((c=*value)&&(c==' '||c=='\t')) // original 

                         
 
        /* Find the start of the value */
        for (;;) {
        for (;;) {
 
            int retval; 
            c = *value; 
 
if ('\0' == c) {
            c = *value; 
 
if ('\0' == c) {
                return -1;      // bad header
/*
              retval = read_request_more (req);
              if (retval)
                {
                  return retval;
                }
                /* Empty header value */
                return 0;
            } else if (c == ' ' || c == '\t') {
                /* Ignore whitespace */
                value++;
            } else {
                break; 
*/
 
            }
            }
            else if (c == ' ' || c == '\t') {
                value++; 
        }
 
        if (!memcmp(line, "HOST", 5)) {
            // TODO

        } else if (!memcmp(line, "IF_MODIFIED_SINCE", 18)
                 && !req->if_modified_since) {
            // TODO
            
        } else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type) {
            // TODO

        } else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length) {
            // TODO

        } else if (!memcmp(line, "CONNECTION", 11) && 
                    ka_max_con && req->ka_status != KA_STOPPED) {
            if (0 == memcmp(value, "close", 5)) {
                req->ka_status = KA_INACTIVE;
            }
            }
            else
                break;
        }
        check_CRLF = 1;

        if (!memcmp(line, "HOST", 5)) {
            //not yet
        }
        else if (!memcmp(line, "IF_MODIFIED_SINCE", 18)
                 && !req->if_modified_since) {
            req->if_modified_since = value;
        }
            // TODO: deal with other "connection" headers

        } else if (!memcmp(line, "REFERER", 8)) {
#ifdef LOGGING
            // TODO
#endif

        } else if (!memcmp (line, "ACCEPT", 7)) {
            // TODO: Honor Accept: headers

        } else if (!memcmp(line, "USER_AGENT", 11)) {
#ifdef LOGGING 
        else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type) {
            req->content_type = value;
        }

        else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length) {
            req->content_length = value;
        }

        else if (!memcmp(line, "CONNECTION", 11)
                 // && ka_max 
                 // && req->keepalive != KA_STOPPED)
                 && ka_max_con && req->ka_status != KA_STOPPED) {
            // not yet
        }

        else if (!memcmp(line, "REFERER", 8)) {
            req->header_referer = value;
        }
/*

      else if (!memcmp (line, "ACCEPT", 7))
        {
          //req->header_referer = value;
          // need to add_accept_header(req,val); -> not yet.
        }
*/

        else if (!memcmp(line, "USER_AGENT", 11)) {
 
            req->header_user_agent = value;
            req->header_user_agent = value;
        }

        else if (req->is_cgi) {
#endif
        }
    } 
            // init value of is_cgi is 0.
            // not yet implemented
            check_CRLF = 0;
        }
        else {
            // not implemented yet...
            // but silently ignore for now...
            //check_CRLF=0;
            //check_CRLF=1;
        }

/*
 * PURPOSE:
 * The body of this if-stmt is to parse the current header line so that
 * 1. get the CRLF at the end of the line (should be there), and
 * 2. make the parsing point (p_pos or header_line) to the beginning of
 *    the next line. (so that if the immediate next chars are \r\n then
 *    finish parsing header at the top of this loop).
 * Note that some categories above just assign the pointer to the appropreate
 * entry of req, so we need to find the end of the line in these cases.
 */
        if (check_CRLF) {
            int flg_cr = 0;

            char *val;
            val = value;
            val++;

            for (;;) {
                if ('\0' == *val) {
                    return -1;
/*
                  retval = read_request_more (req);
                  if (retval)
                    return -1;
                  else
                    continue;
*/
                }
                else if ('\r' == *val)
                    flg_cr = 1;
                else if ('\n' == *val) {
                    if (flg_cr) {
                        // alright, we got \r\n sequence.
                        req->header_line = ++val;
                        break;
                    }
                    else
                        flg_cr = 0;
                }
                else if (flg_cr)
                    flg_cr = 0;

                val++;
            }
        }
    }
    return 0;                   // success
 


/*** simple_parse_*() ***/

int simple_parse_request(msg * req) {

/*
 * HTTP_request_message := request_line request_header
 * 
 * request_line here means the "start-line" 
 * request_header means "(message-header CRLF)"
 */

    int retval = 0;

    if ((retval = simple_parse_request_line(req)))
        return retval;

    // parse header lines 
/*
*/
    retval = simple_parse_header(req);
    if (retval)
        return retval;

    switch (req->p_method) {
    case M_HEAD:
    case M_GET:
// for now, return here.
// fix here -> the caller read_request() will handle... or
// is there any better way?
// return 0;
//printf("(before %d)\n", (int)pth_self());
        response_get(req);
//printf("(after  %d)\n", (int)pth_self());
        break;
        /* post not yet handled. it's put for now... */
        /* diff btwn POST and PUT:
           POST = pass (usu. cgi) the entity body to the uri
           PUT  = server just put the entity body to the uri
         */
    case M_POST:
        PRINT("method is post\n");
        response_post(req);
        PRINT("breaking post\n");
    case M_PUT:
        PRINT("method is put\n");
        process_header_end(req);
        response_put(req);
        PRINT("breaking put\n");
        break;
    default:
        PRINT("def...\n");
        response_default(req->fdp);
        return -1;
    }
    return 0;
}

int simple_parse_request_line(msg* req) {
    /*
     *    Request-Line   = Method SP Request-URI SP HTTP-Version CRLF
     */

    char *stop, *stop2;
    char *logline = req->p_buf;

    /* Method */
    if (!memcmp(logline, "GET ", 4))
        req->p_method = M_GET;
    else if (!memcmp(logline, "PUT ", 4))
        req->p_method = M_PUT;
    else if (!memcmp(logline, "HEAD ", 5))
        req->p_method = M_HEAD;
    else if (!memcmp(logline, "POST ", 5))
        req->p_method = M_POST;
    else {
        response_501(req->fdp);
        return -1;
    }

    /* SP */
    /* Guaranteed to find ' ' since we matched a method above */
    stop = logline + 3;
    if (*stop != ' ')
        ++stop;

    /* scan to start of non-whitespace */
    while (*(++stop) == ' ') {
        if (stop > req->p_buf_head)
            return -1;
        // i.e. bogus header
    }

    stop2 = stop;

    /* SP */
    /* scan to end of non-whitespace */
    while (*stop2 != '\0' && *stop2 != ' ') {
        ++stop2;
        if (stop2 > req->p_buf_head)
            return -1;
    }

    if (stop2 - stop > MAX_REQ_URI_LEN) {
        response_414(req->fdp);
        return -1;
    }

    req->p_uri_begin = stop;
    req->p_uri_end = stop2;
    PRINT1("URI: %s\n", req->p_uri_begin);

    memcpy(req->p_uri, stop, stop2 - stop);
    req->p_uri[stop2 - stop] = '\0';

    /* HTTP-Version */
    if (*stop2 == ' ') {
        /* if found, we should get an HTTP/x.x */
        int p1, p2;

        if (sscanf(++stop2, "HTTP/%d.%d", &p1, &p2) == 2 && p1 >= 1) {
            req->hv_major = p1;
            req->hv_minor = p2;
            req->simple = 0;
            if (0 == p1 || 0 == p2)
                req->ka_status = KA_INACTIVE;
        }
        else {
            // log_error_time();
/* should one of:
          | "412"  ; Section 10.4.13: Precondition Failed
          | "417"  ; Section 10.4.18: Expectation Failed
          | "501"  ; Section 10.5.2: Not Implemented
          | "503"  ; Section 10.5.4: Service Unavailable
          | "505"  ; Section 10.5.6: HTTP Version not supported
*/
            response_501(req->fdp);
            return -1;
        }
    }
    else {
        req->simple = 1;
        req->ka_status = KA_INACTIVE;
    }

    while (*(++stop2) != '\0') {
        if ('\r' == *(stop2) && '\n' == (*(1 + stop2))) {
            req->status = ONE_CRLF;
            req->p_pos = stop2 + 1;
            return 0;
        }
    }

    // should be unreachable because we know \r\n\r\n was found
    return -1;                  /* error */
}

/*
 * Name: process_header_end
 *
 * Description: takes a request and performs some final checking before
 * init_cgi or init_get
 * Returns -1 for error or NPH;  0 for success
 */

int simple_parse_header(msg * req)
{
/*

[70]RFC 2068                        HTTP/1.1                    January 1997


   equivalent to the parameters on a programming language method
   invocation.

          request-header = Accept                   ; Section 14.1
                         | Accept-Charset           ; Section 14.2
                         | Accept-Encoding          ; Section 14.3
                         | Accept-Language          ; Section 14.4
                         | Authorization            ; Section 14.8
                         | From                     ; Section 14.22
                         | Host                     ; Section 14.23
                         | If-Modified-Since        ; Section 14.24
                         | If-Match                 ; Section 14.25
                         | If-None-Match            ; Section 14.26
                         | If-Range                 ; Section 14.27
                         | If-Unmodified-Since      ; Section 14.28
                         | Max-Forwards             ; Section 14.31
                         | Proxy-Authorization      ; Section 14.34
                         | Range                    ; Section 14.36
                         | Referer                  ; Section 14.37
                         | User-Agent               ; Section 14.42

   Request-header field names can be extended reliably only in
   combination with a change in the protocol version. However, new or
   experimental header fields MAY be given the semantics of request-
   header fields if all parties in the communication recognize them to
   be request-header fields.  Unrecognized header fields are treated as
   entity-header fields.

*/

/*
 * Each option line end w/ \r\n.
 */
    char c;
    char *value;
    char *line;
    int check_CRLF;

    req->header_line = 1 + req->p_pos;

    // process one line at a time.
    // return 0 on success
    // return -1 on error
    // return +1 on incomplete

    for (;;) {
/* 
 * At this point, one \r\n was just parsed.
 * So, another immediat \r\n means we got the end of the header.
 */
        line = req->header_line;

        if (('\r' == line[0]) && ('\n' == line[1])) {
            req->p_entity_body = &line[2];
            req->header_line = &line[2];
            return 0;
        }

        value = strchr(line, ':');
        if (NULL == value) {
            return -1;          // illegal header line
        }

        *value++ = '\0';
        to_upper(line);         // header type is case insensitive
        // while((c=*value)&&(c==' '||c=='\t')) // original
        for (;;) {
            c = *value;

            if ('\0' == c) {
                return -1;      // bad header
            }
            else if (c == ' ' || c == '\t') {
                value++;
            }
            else
                break;
        }
        check_CRLF = 1;

        if (!memcmp(line, "HOST", 5)) {
            //not yet
        }
        else if (!memcmp(line, "IF_MODIFIED_SINCE", 18)
                 && !req->if_modified_since) {
            req->if_modified_since = value;
        }

        else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type) {
            req->content_type = value;
        }

        else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length) {
            req->content_length = value;
        }

        else if (!memcmp(line, "CONNECTION", 11)
                 // && ka_max 
                 // && req->keepalive != KA_STOPPED)
                 && ka_max_con && req->ka_status != KA_STOPPED) {
            // not yet
        }

        else if (!memcmp(line, "REFERER", 8)) {
            req->header_referer = value;
        }
/*

      else if (!memcmp (line, "ACCEPT", 7))
        {
          //req->header_referer = value;
          // need to add_accept_header(req,val); -> not yet.
        }
*/

        else if (!memcmp(line, "USER_AGENT", 11)) {
            req->header_user_agent = value;
        }

        else if (req->is_cgi) {
            // init value of is_cgi is 0.
            // not yet implemented
            check_CRLF = 0;
        }
        else {
            // not implemented yet...
            // but silently ignore for now...
            //check_CRLF=0;
            //check_CRLF=1;       // this is default
        }

/*
 * PURPOSE:
 * The body of this if-stmt is to parse the current header line so that
 * 1. get the CRLF at the end of the line (should be there), and
 * 2. make the parsing point (p_pos or header_line) to the beginning of
 *    the next line. (so that if the immediate next chars are \r\n then
 *    finish parsing header at the top of this loop).
 * Note that some categories above just assign the pointer to the appropreate
 * entry of req, so we need to find the end of the line in these cases.
 */
        if (check_CRLF) {
            int flg_cr = 0;

            char *val;
            val = value;
            val++;

            for (;;) {
                if ('\0' == *val) {
                    return -1;
                }
                else if ('\r' == *val)
                    flg_cr = 1;
                else if ('\n' == *val) {
                    if (flg_cr) {
                        // alright, we got \r\n sequence.
                        req->header_line = ++val;
                        break;
                    }
                    else
                        flg_cr = 0;
                }
                else if (flg_cr)
                    flg_cr = 0;

                val++;
            }                   //end of for-loop
        }                       //end of if-stmt
    }                           // end of for-loop
    return 0;                   // success, but unreachable
}
 
 


Legend
Lines deleted from 1.15  
Lines Modified
  Lines added in revision 1.6