コード例 #1
0
ファイル: request.c プロジェクト: ColdFreak/http
/*
 * Handles the request process. It uses the receive_request function
 * and parses the received data filling a request_t data structure.
 *
 * @param thread_id: the thread id handling the request
 * @param sockfd: socket file descriptor to read data from the client
 * @param req: request_t data structure to store the parsed data
 */
int handle_request(int thread_id, int sockfd, request_t *req) {

	char *buffer = NULL;
	char *method = NULL;
	char *query = NULL;
	char *content_length = NULL;

	int start, end, pos, tmp, n;
	int string_length, message_length;
	int received;

	uint8_t i;

	start = 0;
	end = 0;

	pos = 0;
	tmp = 0;
	n = 0;

	string_length = 0;
	message_length = 0;
	received = 0;

	/* allocate first 1024 bytes for the request */
	buffer = malloc(REQUEST_ALLOC_SIZE);
	memset(buffer, 0, REQUEST_ALLOC_SIZE);

	if ((n = receive_request(thread_id, sockfd, &buffer)) < 0) {
		/* There has been an error receiving the client request :( */
		free(buffer);

		return ERROR;

	} else if (n == 0) {

		free(buffer);

		debug(conf.output_level, "[%d] empty request\n", thread_id);

		return ERROR;

	}

	debug(conf.output_level, "[%d] Request:\n%s\n", thread_id, buffer);

	while (strncmp(&buffer[start], "\r\n", 2) != 0) {

		while (strncmp(&buffer[end], "\r\n", 2) != 0) end++;

		if (start == 0) {

			pos = 0;
			tmp = 0;

			/* allocate request. REMEMBER TO FREE request AFTER sending response */
			while (strncmp(&buffer[pos], " ", 1) != 0) pos++;

			method = malloc(pos + 1);
			memset(method, 0, pos + 1);
			strncat(method, buffer, pos);

			for (i = 0; i < 7; i++) {
				if(strncmp(methods[i], method, strlen(method)) == 0) {
					req->method = i;
				}
			}

			paranoid_free_string(method);

			pos++;
			
			tmp = pos;

			while (strncmp(&buffer[pos], " ", 1) != 0) pos++;
			
			req->uri = malloc(pos + 1 - tmp);
			memset(req->uri, 0, pos + 1 - tmp);
			strncat(req->uri, &buffer[tmp], pos - tmp);
			
			req->_mask |= _REQUEST_URI;

			pos++;
			
			tmp = pos;

			while (strncmp(&buffer[pos], "\r\n", 2) != 0) pos++;

			req->version = malloc(pos + 1 - tmp);
			memset(req->version, 0, pos + 1 - tmp);
			strncat(req->version, &buffer[tmp], pos - tmp);

			req->_mask |= _REQUEST_VERSION;

		} else {

			pos = 0;
			tmp = 0;

			/* reallocate header_t struct of request_t */
			if (req->num_headers == 0) {
				req->headers = malloc(sizeof(header_t *));
			} else {
				req->headers = realloc(req->headers, (req->num_headers + 1)*sizeof(header_t *));
			}

			req->headers[req->num_headers] = malloc(sizeof(header_t *));

			/* parse headers */
			while (strncmp(&buffer[start + pos], ":", 1) != 0) pos++;
			req->headers[req->num_headers]->name = malloc(pos++);
			tmp = pos;

			while (strncmp(&buffer[start + pos], "\r\n", 2) != 0) pos++;
			req->headers[req->num_headers]->value = malloc((pos++) - tmp);
			tmp = pos;

			sscanf(&buffer[start], "%[^:]: %[^\r\n]", 
				req->headers[req->num_headers]->name, 
				req->headers[req->num_headers]->value);

			req->num_headers++;

		}

		end += 2;
		start = end;

	}

	/* Look for the query part */
	if (strchr(req->uri, '?') != NULL) {

		query = strchr(req->uri, '?');

		string_length = strlen(query);

		req->query = malloc(string_length + 1);
		memset(req->query, 0, string_length + 1);
		strncat(req->query, query, string_length);

		req->_mask |= _REQUEST_QUERY;

		debug(conf.output_level,
			"[%d] DEBUG: query %s\n",
			thread_id, req->query);

	}

	/* Get the resource requested */
	if (req->_mask & _REQUEST_QUERY) {
		string_length = strlen(req->uri) - strlen(req->query); // Strip query string from uri
	} else {
		string_length = strlen(req->uri);
	}

	req->resource = malloc(string_length + 1);
	memset(req->resource, 0, string_length + 1);
	strncat(req->resource, req->uri, string_length);

	req->_mask |= _REQUEST_RESOURCE;

	string_length = 0;

	/* free buffer */
	free(buffer);

	if (get_request_header(req, "Content-Length", &content_length) != -1) {

		message_length = atoi(content_length);

		if (message_length > REQUEST_MAX_MESSAGE_SIZE) {
			return ERROR;
		}

		buffer = malloc(REQUEST_ALLOC_MESSAGE_SIZE);

		if ((received = receive_message_body(thread_id, sockfd, &buffer, message_length)) < 0) {
			/* There has been an error receiving the message body :( */
			free(buffer);
			free_request(req);
			return ERROR;

		}

		req->message_body = malloc(received + 1);
		memset(req->message_body, 0, received + 1);

		memcpy(req->message_body, buffer, received);
		req->_mask |= _REQUEST_MESSAGE;

		free(buffer);

		debug(conf.output_level, 
			"[%d] DEBUG: message body: %s\n",
			thread_id, req->message_body);

 	}

	return 0;

}
コード例 #2
0
/** @brief Parse and response to request from a client
 *
 *  @return 0 if the connection should be kept alive. -1 if the connection
 *          should be closed.
 */
int http_parse(http_client_t *client) {
    int ret, i;
    char line[MAXBUF];
    char* buf;

    if (client->status == C_IDLE) {  /* A new request, parse request line */
        ret = client_readline(client, line);
        if (strlen(line) == 0) return 0;

        log_msg(L_HTTP_DEBUG, "%s\n", line);

        if (ret == 0) return 0;

        /* The length of a line exceed MAXBUF */
        if (ret < 0) {
            log_error("A line in request is too long");
            return end_request(client, BAD_REQUEST);
        }

        if (client->req != NULL) free(client->req);
        client->req = new_request();

        /* parse request line and store information in client->req */
        if ((ret = parse_request_line(client->req, line)) > 0)
            return end_request(client, ret);

        /* Now start parsing header */
        client->status = C_PHEADER;
    }

    /*
     *  Read request headers. When finish reading request headers of a POST
     *  request without error, client->req->content_length will be set
     *  correspondingly. Thus client->req->content_length == -1 means the
     *  request header section has not ended.
     */
    while (client->status == C_PHEADER && client_readline(client, line) > 0) {
        log_msg(L_HTTP_DEBUG, "%s\n", line);

        if (strlen(line) == 0) {    //Request header ends

            if (client->req->method == M_POST) {
                buf = get_request_header(client->req, "Content-Length");
                if (buf == NULL)
                    return end_request(client, LENGTH_REQUIRED);
                //validate content-length
                if (strlen(buf) == 0) return BAD_REQUEST;
                for (i = 0; i < strlen(buf); ++i)
                    if (buf[i] < '0' || buf[i] >'9') //each char in range ['0', '9']
                        return end_request(client, BAD_REQUEST);

                client->req->content_length = atoi(buf);

                /* Now start receiving body */
                client->status = C_PBODY;
                break;
            }

            if (client->req->method == M_GET) ret = handle_get(client);
            if (client->req->method == M_HEAD) ret = handle_head(client);
            if (ret != 0)
                return end_request(client, ret);
            else {
                /* The client signal a "Connection: Close" */
                if (connection_close(client->req))
                    client->alive = 0;

                return ret;
            }
        }
        ret = parse_header(client->req, line);
        if (ret == -1) {
            log_msg(L_ERROR, "Bad request header format: %s\n", line);
            return end_request(client, BAD_REQUEST);
        }
    }

    /*
     * We've finished reading and parsing request header. Now, see if the body
     * of the request is ready. If so, copy data
     */
    if (client->status == C_PBODY) {
        // Reveive complete body?
        if (client->in->datasize - client->in->pos >= client->req->content_length) {
            /* Let body points to corresponding memory in the input buffer */
            client->req->body = client->in->buf + client->in->pos;
            client->in->pos += client->req->content_length;
            ret = handle_post(client);

            if (ret != 0)
                return end_request(client, ret);
            else {
                /* The client signal a "Connection: Close" */
                if (connection_close(client->req))
                    client->alive = 0;

                return ret;
            }
        }

        /* Body not ready, next time then */
        return 0;
    }

    return 0;
}