Пример #1
0
int mk_conn_read(int socket)
{
    int ret;
    int status;
    struct mk_http_session *cs;
    struct mk_http_request *sr;
    struct sched_list_node *sched;

    MK_TRACE("[FD %i] Connection Handler / read", socket);

    /* Plugin hook */
    ret = mk_plugin_event_read(socket);

    switch (ret) {
    case MK_PLUGIN_RET_EVENT_OWNED:
        return MK_PLUGIN_RET_CONTINUE;
    case MK_PLUGIN_RET_EVENT_CLOSE:
        return -1;
    case MK_PLUGIN_RET_EVENT_CONTINUE:
        break; /* just return controller to invoker */
    }

    sched = mk_sched_get_thread_conf();
    cs = mk_http_session_get(socket);
    if (!cs) {
        /* Check if is this a new connection for the Scheduler */
        if (!mk_sched_get_connection(sched, socket)) {
            MK_TRACE("[FD %i] Registering new connection");
            if (mk_sched_register_client(socket, sched) == -1) {
                MK_TRACE("[FD %i] Close requested", socket);
                return -1;
            }
            /*
             * New connections are not registered yet into the
             * events loop, we need to do it manually:
             */
            mk_event_add(sched->loop, socket, MK_EVENT_READ, NULL);
            return 0;
        }

        /* Create session for the client */
        MK_TRACE("[FD %i] Create session", socket);
        cs = mk_http_session_create(socket, sched);
        if (!cs) {
            return -1;
        }
    }

    /* Invoke the read handler, on this case we only support HTTP (for now :) */
    ret = mk_http_handler_read(socket, cs);
    if (ret > 0) {
        if (mk_list_is_empty(&cs->request_list) == 0) {
            /* Add the first entry */
            sr = &cs->sr_fixed;
            mk_list_add(&sr->_head, &cs->request_list);
            mk_http_request_init(cs, sr);
        }
        else {
            sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head);
        }

        status = mk_http_parser(sr, &cs->parser,
                                cs->body, cs->body_length);
        if (status == MK_HTTP_PARSER_OK) {
            MK_TRACE("[FD %i] HTTP_PARSER_OK", socket);
            mk_http_status_completed(cs);
            mk_event_add(sched->loop, socket, MK_EVENT_WRITE, NULL);
        }
        else if (status == MK_HTTP_PARSER_ERROR) {
            mk_http_session_remove(socket);
            MK_TRACE("[FD %i] HTTP_PARSER_ERROR", socket);
            return -1;
        }
        else {
            MK_TRACE("[FD %i] HTTP_PARSER_PENDING", socket);
        }
    }

    if (ret == -EAGAIN) {
        return 1;
    }

    return ret;
}
Пример #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; // 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;
}