示例#1
0
文件: post.c 项目: Daniel15/webserver
static ret_t
do_read_chunked (cherokee_post_t   *post,
		 cherokee_socket_t *sock_in,
		 cherokee_buffer_t *buffer)
{
	ret_t ret;

	/* Try to read
	 */
	ret = do_read_plain (post, sock_in, &post->chunked.buffer, POST_READ_SIZE);
	switch(ret) {
	case ret_ok:
		break;
	case ret_eagain:
		return ret_eagain;
	default:
		RET_UNKNOWN(ret);
		return ret_error;
	}

	/* Process the buffer
	 */
	ret = process_chunk (post, &post->chunked.buffer, buffer);
	if (unlikely (ret != ret_ok)) {
		return ret_error;
	}

	if (post->chunked.last) {
		cherokee_buffer_mrproper (&post->chunked.buffer);
	}

	return ret_ok;
}
示例#2
0
static ret_t
read_from_cgi (cherokee_handler_cgi_base_t *cgi_base, cherokee_buffer_t *buffer)
{
	ret_t                   ret;
 	size_t                  read_ = 0;
	cherokee_handler_cgi_t *cgi   = HDL_CGI(cgi_base);

	/* Sanity check: pipe() accessed
	 */
	if (unlikely (cgi->pipeInput < 0))
		return ret_eof;

	/* Read the data from the pipe:
	 */
	ret = cherokee_buffer_read_from_fd (buffer, cgi->pipeInput, 4096, &read_);

	TRACE (ENTRIES, "read... ret=%d %d\n", ret, read_);

	switch (ret) {
	case ret_eagain:
		cherokee_thread_deactive_to_polling (HANDLER_THREAD(cgi),
						     HANDLER_CONN(cgi), cgi->pipeInput,
						     FDPOLL_MODE_READ, false);
		return ret_eagain;

	case ret_ok:
		TRACE (ENTRIES, "%d bytes read\n", read_);
		return ret_ok;

	case ret_eof:
	case ret_error:
		cgi_base->got_eof = true;
		return ret;

	default:
		RET_UNKNOWN(ret);
	}

	SHOULDNT_HAPPEN;
	return ret_error;
}
static ret_t
read_from_fcgi (cherokee_handler_cgi_base_t *cgi, cherokee_buffer_t *buffer)
{
	ret_t                    ret;
	size_t                   read = 0;
	cherokee_handler_fcgi_t *fcgi = HDL_FCGI(cgi);

	ret = cherokee_socket_bufread (&fcgi->socket, &fcgi->write_buffer, DEFAULT_READ_SIZE, &read);

	switch (ret) {
	case ret_eagain:
		ret = cherokee_thread_deactive_to_polling (HANDLER_THREAD(cgi), HANDLER_CONN(cgi),
							   fcgi->socket.socket, FDPOLL_MODE_READ,
							   false);
		if (unlikely (ret != ret_ok)) {
			cgi->got_eof = true;
			return ret_error;
		}
		return ret_eagain;

	case ret_ok:
		ret = process_buffer (fcgi, &fcgi->write_buffer, buffer);
		TRACE (ENTRIES, "%d bytes read, buffer.len %d\n", read, buffer->len);

		if ((ret == ret_ok) && cgi->got_eof && (buffer->len > 0)) {
			return ret_eof_have_data;
		}
		return ret;

	case ret_eof:
	case ret_error:
		cgi->got_eof = true;
		return ret;

	default:
		RET_UNKNOWN(ret);
	}

	SHOULDNT_HAPPEN;
	return ret_error;
}
示例#4
0
static ret_t
match (cherokee_rule_t         *rule,
       cherokee_connection_t   *conn,
       cherokee_config_entry_t *ret_conf)
{
	ret_t ret;

	/* Call match() in the subrule and invert the result
	 */
	ret = cherokee_rule_match (RULE_NOT(rule)->right, conn, ret_conf);
	switch (ret) {
	case ret_ok:
		return ret_not_found;
	case ret_not_found:
		return ret_ok;
	case ret_error:
		return ret_error;
	default:
		RET_UNKNOWN(ret);
		return ret_error;
	}
}
示例#5
0
/* WARNING: all parameters MUST be valid,
 *          NULL pointers lead to a crash.
 */
ret_t
cherokee_socket_read (cherokee_socket_t *socket,
                      char              *buf,
                      int                buf_size,
                      size_t            *pcnt_read)
{
	ret_t   ret;
	int     err;
	ssize_t len;

	*pcnt_read = 0;

	/* There must be something to read, otherwise behaviour is undefined
	 * and as we don't want this case, we have to enforce assertions.
	 */
	return_if_fail (buf != NULL && buf_size > 0, ret_error);

	if (unlikely (socket->status == socket_closed)) {
		TRACE(ENTRIES, "Reading a closed socket: fd=%d (TLS=%d)\n", SOCKET_FD(socket), (socket->is_tls == TLS));
		return ret_eof;
	}

	if (likely (socket->is_tls != TLS)) {
		/* Plain read
		 */
		do {
			len = recv (SOCKET_FD(socket), buf, buf_size, 0);
		} while ((len < 0) && (errno == EINTR));

		if (likely (len > 0)) {
			*pcnt_read = len;
			return ret_ok;
		}

		if (len == 0) {
			socket->status = socket_closed;
			return ret_eof;
		}

		/* Error handling
		 */
		err = SOCK_ERRNO();

		TRACE(ENTRIES",read", "Socket read error fd=%d: '%s'\n",
		      SOCKET_FD(socket), strerror(errno));

		switch (err) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
		case EWOULDBLOCK:
#endif
		case EAGAIN:
			return ret_eagain;

		case EPIPE:
#ifdef ENOTCONN
		case ENOTCONN:
#endif
		case ECONNRESET:
			socket->status = socket_closed;
		case ETIMEDOUT:
		case EHOSTUNREACH:
			return ret_error;
		}

		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_SOCKET_READ, SOCKET_FD(socket));
		return ret_error;

	} else if (socket->cryptor != NULL) {
		ret = cherokee_cryptor_socket_read (socket->cryptor,
		                                    buf, buf_size, pcnt_read);
		switch (ret) {
		case ret_ok:
		case ret_error:
		case ret_eagain:
			return ret;
		case ret_eof:
			socket->status = socket_closed;
			return ret_eof;
		default:
			RET_UNKNOWN(ret);
			return ret;
		}
	}

	return ret_error;
}
示例#6
0
/* WARNING: all parameters MUST be valid,
 *          NULL pointers lead to a crash.
 */
ret_t
cherokee_socket_write (cherokee_socket_t *socket,
                       const char        *buf,
                       int                buf_len,
                       size_t            *pcnt_written)
{
	ret_t   ret;
	int     err;
	ssize_t len;

	*pcnt_written = 0;

	/* There must be something to send, otherwise behaviour is undefined
	 * and as we don't want this case, we have to enforce assertions.
	 */
	return_if_fail (buf != NULL && buf_len > 0, ret_error);

	if (likely (socket->is_tls != TLS)) {
		do {
			len = send (SOCKET_FD(socket), buf, buf_len, 0);
		} while ((len < 0) && (errno == EINTR));

		if (likely (len > 0) ) {
			/* Return n. of bytes sent.
			 */
			*pcnt_written = len;
			return ret_ok;
		}

		if (len == 0) {
			/* Very strange, socket is ready but nothing
			 * has been written, retry later.
			 */
			return ret_eagain;
		}

		/* Error handling
		 */
		err = SOCK_ERRNO();

		switch (err) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
		case EWOULDBLOCK:
#endif
		case EAGAIN:
			return ret_eagain;

		case EPIPE:
		case ECONNRESET:
#ifdef ENOTCONN
		case ENOTCONN:
#endif
			socket->status = socket_closed;
		case ETIMEDOUT:
		case EHOSTUNREACH:
			return ret_error;
		}

		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_SOCKET_WRITE, SOCKET_FD(socket));

		return ret_error;

	} else if (socket->cryptor != NULL) {
		ret = cherokee_cryptor_socket_write (socket->cryptor,
		                                     (char *)buf, buf_len, pcnt_written);
		switch (ret) {
		case ret_ok:
		case ret_error:
		case ret_eagain:
			return ret;
		case ret_eof:
			socket->status = socket_closed;
			return ret_eof;
		default:
			RET_UNKNOWN(ret);
			return ret;
		}
	}

	return ret_error;
}
ret_t
cherokee_handler_proxy_conn_recv_headers (cherokee_handler_proxy_conn_t *pconn,
					  cherokee_buffer_t             *body,
					  cherokee_boolean_t             flexible)
{
	ret_t    ret;
	char    *end;
	cuint_t  sep_len;
	size_t   size     = 0;

	/* Read
	 */
	ret = cherokee_socket_bufread (&pconn->socket,
				       &pconn->header_in_raw,
				       DEFAULT_RECV_SIZE, &size);
	switch (ret) {
	case ret_ok:
		break;
	case ret_eof:
	case ret_error:
		return ret;
	case ret_eagain:
		if (cherokee_buffer_is_empty (&pconn->header_in_raw)) {
			return ret_eagain;
		}
		break;
	default:
		RET_UNKNOWN(ret);
	}

	/* Look for the end of header
	 */
	ret = cherokee_find_header_end (&pconn->header_in_raw, &end, &sep_len);
	switch (ret) {
	case ret_ok:
		break;
	case ret_not_found:
		return ret_eagain;
	default:
		/* Did not success
		 */
		if (! flexible) {
			goto error;
		}

		/* Plan B!
		 */
		TRACE (ENTRIES, "Header end not found. Being more flexible about malformed headers\n");

		ret = find_header_end_flexible (&pconn->header_in_raw, &end, &sep_len);
		switch (ret) {
		case ret_ok:
			break;
		case ret_not_found:
			return ret_eagain;
		default:
			goto error;
		}
	}

	/* Copy the body if there is any
	 */
	size = (pconn->header_in_raw.buf + pconn->header_in_raw.len) - (end + sep_len);

	cherokee_buffer_add (body, end+sep_len, size);
	cherokee_buffer_drop_ending (&pconn->header_in_raw, size);

	return ret_ok;

error:
	LOG_ERROR (CHEROKEE_ERROR_PROXY_HEADER_PARSE,
		   pconn->header_in_raw.len,
		   pconn->header_in_raw.buf);

	return ret_error;
}
示例#8
0
文件: post.c 项目: Daniel15/webserver
ret_t
cherokee_post_send_to_socket (cherokee_post_t          *post,
			      cherokee_socket_t        *sock_in,
			      cherokee_socket_t        *sock_out,
			      cherokee_buffer_t        *tmp,
			      cherokee_socket_status_t *blocking,
			      cherokee_boolean_t       *did_IO)
{
	ret_t              ret;
	cherokee_buffer_t *buffer = tmp ? tmp : &post->send.buffer;

	switch (post->send.phase) {
	case cherokee_post_send_phase_read:
		TRACE (ENTRIES, "Post send, phase: %s\n", "read");

		/* Read from the client
		 */
		ret = cherokee_post_read (post, sock_in, buffer);
		switch (ret) {
		case ret_ok:
			break;
		case ret_eagain:
			*blocking = socket_reading;
			return ret_eagain;
		default:
			return ret;
		}

		/* Did something, increase timeout
		 */
		*did_IO = true;

		/* Write it
		 */
		TRACE (ENTRIES, "Post buffer.len %d\n", buffer->len);
		post->send.phase = cherokee_post_send_phase_write;

	case cherokee_post_send_phase_write:
		TRACE (ENTRIES, "Post send, phase: write. Buffered: %d bytes\n", buffer->len);

		if (! cherokee_buffer_is_empty (buffer)) {
			ret = do_send_socket (sock_out, buffer, blocking);
			switch (ret) {
                        case ret_ok:
                                break;
                        case ret_eagain:
                                return ret_eagain;
                        case ret_eof:
                        case ret_error:
                                return ret_error;
                        default:
				RET_UNKNOWN(ret);
				return ret_error;
                        }

			/* Did something, increase timeout
			 */
			*did_IO = true;
		}

		if (! cherokee_buffer_is_empty (buffer)) {
			return ret_eagain;
		}

		if (! cherokee_post_read_finished (post)) {
			post->send.phase = cherokee_post_send_phase_read;
			return ret_eagain;
		}

		TRACE (ENTRIES, "Post send: %s\n", "finished");

		cherokee_buffer_mrproper (&post->send.buffer);
		return ret_ok;

	default:
		SHOULDNT_HAPPEN;
	}

	return ret_error;
}
示例#9
0
ret_t
cherokee_downloader_step (cherokee_downloader_t *downloader,
                          cherokee_buffer_t     *ext_tmp1,
                          cherokee_buffer_t     *ext_tmp2)
{
	ret_t              ret;
	cherokee_buffer_t *tmp1;
	cherokee_buffer_t *tmp2;

	/* Set the temporary buffers
	 */
	tmp1 = (ext_tmp1) ? ext_tmp1 : &downloader->tmp1;
	tmp2 = (ext_tmp2) ? ext_tmp2 : &downloader->tmp2;

	TRACE (ENTRIES, "phase=%d\n", downloader->phase);

	/* Process it
	 */
	switch (downloader->phase) {
	case downloader_phase_init: {
		cherokee_request_header_t *req = &downloader->request;

		TRACE(ENTRIES, "Phase %s\n", "init");

		/* Maybe add the post info
		 */
		if (! cherokee_buffer_is_empty (&downloader->post)) {
			req->method   = http_post;
			req->post_len = downloader->post.len;
		}

		/* Build the request header
		 */
		ret = cherokee_request_header_build_string (req, &downloader->request_header, tmp1, tmp2);
		if (unlikely(ret < ret_ok))
			return ret;

		/* Deal with the connection
		 */
		if (! is_connected (downloader)) {
			ret = cherokee_downloader_connect (downloader);
			if (ret < ret_ok) return ret;
		}

		/* Everything is ok, go ahead!
		 */
		downloader->phase = downloader_phase_send_headers;
	}
	case downloader_phase_send_headers:
		TRACE(ENTRIES, "Phase %s\n", "send_headers");

		ret = downloader_send_buffer (downloader, &downloader->request_header);
		if (unlikely(ret != ret_ok))
			return ret;

		BIT_SET (downloader->status, downloader_status_headers_sent);
		downloader->phase = downloader_phase_send_post;

	case downloader_phase_send_post:
		TRACE(ENTRIES, "Phase %s\n", "send_post");

		if (! cherokee_buffer_is_empty (&downloader->post)) {
			size_t written = 0;

			ret = cherokee_socket_bufwrite (&downloader->socket, &downloader->post, &written);
			if (ret != ret_ok) {
				return ret;
			}

			cherokee_buffer_move_to_begin (&downloader->post, written);
			if (! cherokee_buffer_is_empty (&downloader->post)) {
				return ret_eagain;
			}
		}

		BIT_SET (downloader->status, downloader_status_post_sent);
		downloader->phase = downloader_phase_read_headers;
		break;

	case downloader_phase_read_headers:
		TRACE(ENTRIES, "Phase %s\n", "read_headers");

		ret = downloader_header_read (downloader, tmp1, tmp2);
		if (unlikely(ret != ret_ok))
			return ret;

		/* We have the header parsed, continue..
		 */
		BIT_SET (downloader->status, downloader_status_headers_received);
		downloader->phase = downloader_phase_step;

		/* Does it read the full reply in the first received chunk?
		 */
		if (downloader->info.body_recv >= downloader->content_length) {
			BIT_SET (downloader->status, downloader_status_data_available);
			BIT_SET (downloader->status, downloader_status_finished);
			return ret_eof_have_data;
		}

	case downloader_phase_step:
		TRACE(ENTRIES, "Phase %s\n", "step");

		ret = downloader_step (downloader);
		switch (ret) {
		case ret_error:
			break;
		case ret_ok:
			BIT_SET (downloader->status, downloader_status_data_available);
			break;
		case ret_eof_have_data:
			BIT_SET (downloader->status, downloader_status_data_available);
			BIT_SET (downloader->status, downloader_status_finished);
			break;
		case ret_eof:
			BIT_UNSET (downloader->status, downloader_status_data_available);
			BIT_SET   (downloader->status, downloader_status_finished);
			break;
		case ret_eagain:
			BIT_UNSET (downloader->status, downloader_status_data_available);
			break;
		default:
			RET_UNKNOWN(ret);
		}
		return ret;

	case downloader_phase_finished:
		TRACE(ENTRIES, "Phase %s\n", "finished");

		BIT_SET   (downloader->status, downloader_status_finished);
		BIT_UNSET (downloader->status, downloader_status_data_available);
		return ret_ok;

	default:
		SHOULDNT_HAPPEN;
		break;
	}

	return ret_ok;
}
示例#10
0
static ret_t
downloader_header_read (cherokee_downloader_t *downloader,
                        cherokee_buffer_t     *tmp1,
                        cherokee_buffer_t     *tmp2)
{
	ret_t               ret;
	cuint_t             len;
	size_t              read_      = 0;
	cherokee_socket_t  *sock       = &downloader->socket;
	cherokee_http_t     error_code = http_bad_request;

	UNUSED(tmp2);

	ret = cherokee_socket_bufread (sock, &downloader->reply_header, DEFAULT_RECV_SIZE, &read_);
	switch (ret) {
	case ret_eof:
		return ret_eof;

	case ret_eagain:
		return ret_eagain;

	case ret_ok:
		/* Count
		 */
		downloader->info.headers_recv += read_;

		/* Check the header. Is it complete?
		 */
		ret = cherokee_header_has_header (downloader->header, &downloader->reply_header, 0);
		switch (ret) {
		case ret_ok:
			break;
		case ret_not_found:
			/* It needs to read more headers ...
			 */
			return ret_eagain;
		default:
			/* Too many initial CRLF
			 */
			return ret_error;
		}

		/* Parse the header
		 */
		ret = cherokee_header_parse (downloader->header,
		                             &downloader->reply_header,
		                             &error_code);
		if (unlikely (ret != ret_ok)) return ret_error;

		/* Look for the length, it will need to drop out the header from the buffer
		 */
		cherokee_header_get_length (downloader->header, &len);

		/* Maybe it has some body
		 */
		if (downloader->reply_header.len > len) {
			uint32_t body_chunk;

			/* Skip the CRLF separator and copy the body
			 */
			len += 2;
			body_chunk = downloader->reply_header.len - len;

			downloader->info.body_recv += body_chunk;
			cherokee_buffer_add (&downloader->body, downloader->reply_header.buf + len, body_chunk);

			cherokee_buffer_drop_ending (&downloader->reply_header, body_chunk);
		}

		/* Try to read the "Content-Length" response header
		 */
		ret = cherokee_header_has_known (downloader->header, header_content_length);
		if (ret == ret_ok) {
			cherokee_buffer_clean (tmp1);
			ret = cherokee_header_copy_known (downloader->header, header_content_length, tmp1);
			if (ret == ret_ok) {
				ret = cherokee_atou (tmp1->buf, &downloader->content_length);
#ifdef TRACE_ENABLED
				if (ret == ret_ok) {
					TRACE (ENTRIES, "Known length: %d bytes\n", downloader->content_length);
				} else {
					TRACE (ENTRIES, "Could not parse Content-Length\n");
				}
#endif
			}
		}

		return ret_ok;

	case ret_error:
		/* Opsss.. something has failed
		 */
		return ret_error;

	default:
		RET_UNKNOWN (ret);
		return ret;
	}

	return ret_error;
}