Example #1
0
long int mk_method_validate_content_length(const char *body, int body_len)
{
    struct headers_toc toc;
    long int len;
    mk_pointer tmp;

    /* 
     * obs: Table of Content (toc) is created when the full
     * request has arrived, this function cannot be used from
     * mk_http_pending_request().
     */
    mk_request_header_toc_parse(&toc, body, body_len);
    tmp = mk_request_header_get(&toc, 
                                mk_rh_content_length.data,
                                mk_rh_content_length.len);

    if (!tmp.data) {
        int pos_header;
        int pos_crlf;
        char *str_cl;

        /* Pre-parsing mode: Check if content-length was sent */
        pos_header = mk_string_search(body, RH_CONTENT_LENGTH, MK_STR_INSENSITIVE);
        if (pos_header <= 0) {
            return -1;
        }

        pos_crlf = mk_string_search(body + pos_header, MK_IOV_CRLF, MK_STR_SENSITIVE);
        if (pos_crlf <= 0) {
            return -1;
        }

        str_cl = mk_string_copy_substr(body + pos_header + mk_rh_content_length.len + 1,
                                       0, pos_header + pos_crlf);
        len = strtol(str_cl, (char **) NULL, 10);
        mk_mem_free(str_cl);

        return len;
    }

    len = strtol(tmp.data, (char **) NULL, 10);

    return len;
}
Example #2
0
/*
 * Check if the client request still has pending data.
 *
 * Return 0 when all parts of the expected data has arrived or -1 when
 * the connection is on a pending status due to HTTP spec.
 *
 * This function is called from request.c :: mk_handler_read(..)
 */
int mk_http_pending_request(struct client_session *cs)
{
    int n;
    char *end;

    if (cs->body_length >= mk_endblock.len) {
        end = (cs->body + cs->body_length) - mk_endblock.len;
    }
    else {
        return -1;
    }

    /* try to match CRLF at the end of the request */
    if (cs->body_pos_end < 0) {
        if (strncmp(end, mk_endblock.data, mk_endblock.len) == 0) {
            cs->body_pos_end = cs->body_length - mk_endblock.len;
        }
        else if ((n = mk_string_search(cs->body, mk_endblock.data, MK_STR_SENSITIVE)) >= 0 ) {
            cs->body_pos_end = n;
        }
        else {
            return -1;
        }
    }

    if (cs->first_method == MK_HTTP_METHOD_UNKNOWN) {
        cs->first_method = mk_http_method_get(cs->body);
    }

    if (cs->first_method == MK_HTTP_METHOD_POST || cs->first_method == MK_HTTP_METHOD_PUT) {
        if (cs->body_pos_end > 0) {
            int content_length;
            int current;

            current = cs->body_length - cs->body_pos_end - mk_endblock.len;
            content_length = mk_method_validate_content_length(cs->body, current);

            MK_TRACE("HTTP DATA %i/%i", current, content_length);

            if (content_length >= config->max_request_size) {
                return 0;
            }

            /* if first block has ended, we need to verify if exists
             * a previous block end, that will means that the POST
             * method has sent the whole information.
             * just for ref: pipelining is not allowed with POST
             */
            if ((unsigned int) cs->body_pos_end == cs->body_length - mk_endblock.len) {
                /* Content-length is required, if is it not found,
                 * we pass as successful in order to raise the error
                 * later
                 */
                if (content_length <= 0) {
                    cs->status = MK_REQUEST_STATUS_COMPLETED;
                    return 0;
                }
                else {
                    return -1;
                }
            }
            else {
                if (current < content_length) {
                    return -1;
                }
                else {
                    cs->status = MK_REQUEST_STATUS_COMPLETED;
                    return 0;
                }
            }
        }
        else {
            return -1;
        }
    }

    cs->status = MK_REQUEST_STATUS_COMPLETED;
    return 0;
}
Example #3
0
static int mk_request_parse(struct client_session *cs)
{
    int i, end;
    int blocks = 0;
    struct session_request *sr_node;
    struct mk_list *sr_list, *sr_head;

    for (i = 0; i <= cs->body_pos_end; i++) {
        /*
         * Pipelining can just exists in a persistent connection or
         * well known as KeepAlive, so if we are in keepalive mode
         * we should check if we have multiple request in our body buffer
         */
        end = mk_string_search(cs->body + i, mk_endblock.data, MK_STR_SENSITIVE) + i;
        if (end <  0) {
            return -1;
        }

        /* Allocating request block */
        if (blocks == 0) {
            sr_node = &cs->sr_fixed;
            memset(sr_node, '\0', sizeof(struct session_request));
        }
        else {
            sr_node = mk_mem_malloc_z(sizeof(struct session_request));
        }
        mk_request_init(sr_node);

        /* We point the block with a mk_ptr_t */
        sr_node->body.data = cs->body + i;
        sr_node->body.len = end - i;

        /* Method, previous catch in mk_http_pending_request */
        if (i == 0) {
            sr_node->method = cs->first_method;
        }
        else {
            sr_node->method = mk_http_method_get(sr_node->body.data);
        }

        /* Looking for POST data */
        if (sr_node->method == MK_HTTP_METHOD_POST) {
            int offset;
            offset = end + mk_endblock.len;
            sr_node->data = mk_method_get_data(cs->body + offset,
                                               cs->body_length - offset);
        }

        /* Increase index to the end of the current block */
        i = (end + mk_endblock.len) - 1;

        /* Link block */
        mk_list_add(&sr_node->_head, &cs->request_list);

        /* Update counter */
        blocks++;
    }

    /* DEBUG BLOCKS
    struct mk_list *head;
    struct session_request *entry;

    printf("\n*******************\n");
    mk_list_foreach(head, &cs->request_list) {
        entry = mk_list_entry(head, struct session_request, _head);
        mk_ptr_print(entry->body);
        fflush(stdout);
    }
    */

    /* Checking pipelining connection */
    if (blocks > 1) {
        sr_list = &cs->request_list;
        mk_list_foreach(sr_head, sr_list) {
            sr_node = mk_list_entry(sr_head, struct session_request, _head);
            /* Pipelining request must use GET or HEAD methods */
            if (sr_node->method != MK_HTTP_METHOD_GET &&
                sr_node->method != MK_HTTP_METHOD_HEAD) {
                return -1;
            }
        }
Example #4
0
/*
 * Check if the client request still has pending data.
 *
 * Return 0 when all parts of the expected data has arrived or -1 when
 * the connection is on a pending status due to HTTP spec.
 *
 * This function is called from request.c :: mk_handler_read(..)
 */
int mk_http_pending_request(struct client_session *cs)
{
    int n; // ret;
    char *end;
    struct unparsed_method req;
    struct parsed_method rsp;

    if (cs->body_length >= mk_endblock.len) {
        end = (cs->body + cs->body_length) - mk_endblock.len;
    }
    else {
        return -1;
    }

    /* try to match CRLF at the end of the request */
    if (cs->body_pos_end < 0) {
        if (strncmp(end, mk_endblock.data, mk_endblock.len) == 0) {
            cs->body_pos_end = cs->body_length - mk_endblock.len;
        }
        else if ((n = mk_string_search(cs->body, mk_endblock.data, MK_STR_SENSITIVE)) >= 0 ){
            cs->body_pos_end = n;
        }
        else {
            return -1;
        }
    }

    memset(&req, 0, sizeof req);
    if (cs->first_method == MK_HTTP_METHOD_UNKNOWN) {
        /* Prepare message to send to the parser */
        req.flag = 1;
        strncpy(req.req_buf, cs->body, cs->body_length);

        /* Send the actual message to the parser */
        //ret = write(pfd_w, &req, sizeof(req.flag) + cs->body_length);
        //if(ret <= 0){
        //    fprintf(stderr, "Monkey: Write to pipe failed in pre-parsing mode\n");
        //}

        /* Monkey reads parsed request struct from parser */
        //memset(&rsp, 0, sizeof rsp);
        //ret = read(pfd_r, &rsp, sizeof rsp);
        //if(ret <= 0){
        //    fprintf(stderr, "Monkey: Read from pipe failed in pre-parsing mode\n");
        //}

        /* process parsed method */
        cs->first_method = rsp.first_method;
    }

    if (cs->first_method == MK_HTTP_METHOD_POST || cs->first_method == MK_HTTP_METHOD_PUT) {
        if (cs->body_pos_end > 0) {
            int content_length;
            int current;

            if (req.flag != 1)
            {
                /* send the request to the parser */
                req.flag = 1;
                strncpy(req.req_buf, cs->body, cs->body_length);
                //ret = write(pfd_w, &req, sizeof(req.flag) + cs->body_length);
                //if(ret <= 0){
                //    fprintf(stderr, "Monkey: Write to pipe failed in pre-parsing mode\n");
                //}

                /* Monkey reads parsed request struct from parser */
                //memset(&rsp, 0, sizeof rsp);
                //ret = read(pfd_r, &rsp, sizeof rsp);
                //if(ret <= 0){
                //    fprintf(stderr, "Monkey: Read from pipe failed in pre-parsing mode\n");
                //}
            }

            /* process reply from parser */
            content_length = rsp.content_length;

            current = cs->body_length - cs->body_pos_end - mk_endblock.len;
            MK_TRACE("HTTP DATA %i/%i", current, content_length);

            if (content_length >= config->max_request_size) {
                return 0;
            }

            /* if first block has ended, we need to verify if exists
             * a previous block end, that will means that the POST
             * method has sent the whole information.
             * just for ref: pipelining is not allowed with POST
             */
            if ((unsigned int) cs->body_pos_end == cs->body_length - mk_endblock.len) {
                /* Content-length is required, if is it not found,
                 * we pass as successful in order to raise the error
                 * later
                 */
                if (content_length <= 0) {
                    mk_http_status_completed(cs);
                    return 0;
                }
                else {
                    return -1;
                }
            }
            else {
                if (current < content_length) {
                    return -1;
                }
                else {
                    mk_http_status_completed(cs);
                    return 0;
                }
            }
        }
        else {
            return -1;
        }
    }

    mk_http_status_completed(cs);
    return 0;
}