Ejemplo n.º 1
0
static ret_t
do_send_socket (cherokee_socket_t        *sock,
		cherokee_buffer_t        *buffer,
		cherokee_socket_status_t *blocking)
{
	ret_t  ret;
	size_t written = 0;

	ret = cherokee_socket_bufwrite (sock, buffer, &written);
	switch (ret) {
	case ret_ok:
		break;
	case ret_eagain:
		if (written > 0) {
			break;
		}

		TRACE (ENTRIES, "Post write: EAGAIN, wrote nothing of %d\n", buffer->len);
		*blocking = socket_writing;
		return ret_eagain;
	default:
		return ret_error;
	}

	cherokee_buffer_move_to_begin (buffer, written);
	TRACE (ENTRIES, "sent=%d, remaining=%d\n", written, buffer->len);

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

	return ret_ok;
}
Ejemplo n.º 2
0
static ret_t
do_download__read_body (cherokee_downloader_t *downloader, void *param)
{
    ret_t             ret;
    ssize_t           len;
    cherokee_buffer_t tmp = CHEROKEE_BUF_INIT;

    UNUSED(param);

    /* Write down
     */
    len = write (output_fd, downloader->body.buf, downloader->body.len);
    if (len > 0) {
        ret = cherokee_buffer_move_to_begin (&downloader->body, len);
        if (ret != ret_ok) return ret;
    }

    /* Print info
     */
    cherokee_buffer_add_fsize (&tmp, downloader->content_length);
    cherokee_buffer_add_str   (&tmp, " of ");
    cherokee_buffer_add_fsize (&tmp, downloader->info.body_recv);

    if (! quiet) {
        fprintf (stderr, "\rDownloading: %s", tmp.buf);
        fflush(stderr);
    }

    cherokee_buffer_mrproper (&tmp);
    return ret_ok;
}
ret_t
cherokee_handler_proxy_conn_send (cherokee_handler_proxy_conn_t *pconn,
				  cherokee_buffer_t             *buf)
{
	ret_t  ret;
	size_t sent = 0;

	ret = cherokee_socket_bufwrite (&pconn->socket, buf, &sent);
	if (unlikely(ret != ret_ok)) {
		return ret;
	}

	if (sent >= buf->len) {
		cherokee_buffer_clean (buf);
		return ret_ok;
	}

	cherokee_buffer_move_to_begin (buf, sent);
	return ret_eagain;
}
Ejemplo n.º 4
0
static ret_t
reply_100_continue (cherokee_post_t       *post,
		    cherokee_connection_t *conn)
{
	ret_t  ret;
	size_t written;

	ret = cherokee_socket_bufwrite (&conn->socket, &post->read_header_100cont, &written);
	if (ret != ret_ok) {
		TRACE(ENTRIES, "Could not send a '100 Continue' response. Error=500.\n");
		return ret;
	}

	if (written >= post->read_header_100cont.len) {
		TRACE(ENTRIES, "Sent a '100 Continue' response.\n");
		return ret_ok;
	}

	TRACE(ENTRIES, "Sent partial '100 Continue' response: %d bytes\n", written);
	cherokee_buffer_move_to_begin (&post->read_header_100cont, written);

	return ret_eagain;
}
Ejemplo n.º 5
0
static ret_t
parse (cherokee_handler_ssi_t *hdl,
       cherokee_buffer_t      *in,
       cherokee_buffer_t      *out)
{
	ret_t              ret;
	char              *p, *q;
	char              *begin;
	int                re;
	cuint_t            len;
	operations_t       op;
	path_type_t        path;
	struct stat        info;
	cherokee_boolean_t ignore;
	cherokee_buffer_t  key     = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  val     = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  pair    = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  fpath   = CHEROKEE_BUF_INIT;

	q = in->buf;

	while (true) {
		begin = q;

		/* Check the end
		 */
		if (q >= in->buf + in->len)
			break;

		/* Find next SSI tag
		 */
		p = strstr (q, "<!--#");
		if (p == NULL) {
			cherokee_buffer_add (out, begin, (in->buf + in->len) - begin);
			ret = ret_ok;
			goto out;
		}

		q = strstr (p + 5, "-->");
		if (q == NULL) {
			ret = ret_error;
			goto out;
		}

		len = q - p;
		len -= 5;

		cherokee_buffer_clean (&key);
		cherokee_buffer_add (&key, p+5, len);
		cherokee_buffer_trim (&key);

		q += 3;
		TRACE(ENTRIES, "Found key '%s'\n", key.buf);

		/* Add the previous chunk
		 */
		cherokee_buffer_add (out, begin, p - begin);

		/* Check element
		 */
		op     = op_none;
		ignore = false;

		if (strncmp (key.buf, "include", 7) == 0) {
			op  = op_include;
			len = 7;
		} else if (strncmp (key.buf, "fsize", 5) == 0) {
			op  = op_size;
			len = 5;
		} else if (strncmp (key.buf, "flastmod", 8) == 0) {
			op  = op_lastmod;
			len = 8;
		} else {
			LOG_ERROR (CHEROKEE_ERROR_HANDLER_SSI_PROPERTY, key.buf);
		}

		/* Deeper parsing
		 */
		path = path_none;

		switch (op) {
		case op_size:
		case op_include:
		case op_lastmod:
			/* Read a property key
			 */
			cherokee_buffer_move_to_begin (&key, len);
			cherokee_buffer_trim (&key);

			cherokee_buffer_clean (&pair);
			get_pair (&key, &pair);

			cherokee_buffer_drop_ending (&key, pair.len);
			cherokee_buffer_trim (&key);

			/* Parse the property
			 */
			if (strncmp (pair.buf, "file=", 5) == 0) {
				path = path_file;
				len  = 5;
			} else if (strncmp (pair.buf, "virtual=", 8) == 0) {
				path = path_virtual;
				len  = 8;
			}

			cherokee_buffer_clean (&val);
			get_val (pair.buf + len, &val);

			cherokee_buffer_clean (&fpath);

			switch (path) {
			case path_file:
				cherokee_buffer_add_buffer (&fpath, &hdl->dir);
				cherokee_buffer_add_char   (&fpath, '/');
				cherokee_buffer_add_buffer (&fpath, &val);

				TRACE(ENTRIES, "Path: file '%s'\n", fpath.buf);
				break;
			case path_virtual:
				cherokee_buffer_add_buffer (&fpath, &HANDLER_VSRV(hdl)->root);
				cherokee_buffer_add_char   (&fpath, '/');
				cherokee_buffer_add_buffer (&fpath, &val);

				TRACE(ENTRIES, "Path: virtual '%s'\n", fpath.buf);
				break;
			default:
				ignore = true;
				SHOULDNT_HAPPEN;
			}

			/* Path security check: ensure that the file
			 * to include is inside the document root.
			 */
			if (! cherokee_buffer_is_empty (&fpath)) {
				cherokee_path_short (&fpath);

				if (fpath.len < HANDLER_VSRV(hdl)->root.len) {
					ignore = true;

				}  else {
					re = strncmp (fpath.buf,
					              HANDLER_VSRV(hdl)->root.buf,
					              HANDLER_VSRV(hdl)->root.len);
					if (re != 0) {
						ignore = true;
					}
				}
			}

			/* Perform the operation
			 */
			if (! ignore) {
				switch (op) {
				case op_include: {
					cherokee_buffer_t file_content = CHEROKEE_BUF_INIT;

					ret = cherokee_buffer_read_file (&file_content, fpath.buf);
					if (unlikely (ret != ret_ok)) {
						cherokee_buffer_mrproper (&file_content);
						ret = ret_error;
						goto out;
					}

					TRACE(ENTRIES, "Including file '%s'\n", fpath.buf);

					ret = parse (hdl, &file_content, out);
					if (unlikely (ret != ret_ok)) {
						cherokee_buffer_mrproper (&file_content);
						ret = ret_error;
						goto out;
					}

					cherokee_buffer_mrproper (&file_content);
					break;
				}

				case op_size:
					TRACE(ENTRIES, "Including file size '%s'\n", fpath.buf);
					re = cherokee_stat (fpath.buf, &info);
					if (re >=0) {
						cherokee_buffer_add_ullong10 (out, info.st_size);
					}
					break;

				case op_lastmod:
					TRACE(ENTRIES, "Including file modification date '%s'\n", fpath.buf);
					re = cherokee_stat (fpath.buf, &info);
					if (re >= 0) {
						struct tm *ltime;
						struct tm  ltime_buf;
						char       tmp[50];

						ltime = cherokee_localtime (&info.st_mtime, &ltime_buf);
						if (ltime != NULL) {
							strftime (tmp, sizeof(tmp), "%d-%b-%Y %H:%M", ltime);
							cherokee_buffer_add (out, tmp, strlen(tmp));
						}
					}
					break;
				default:
					SHOULDNT_HAPPEN;
				}
			} /* !ignore */

			break;
		default:
			SHOULDNT_HAPPEN;
		} /* switch(op) */
	} /* while */

	ret = ret_ok;

out:
	cherokee_buffer_mrproper (&key);
	cherokee_buffer_mrproper (&val);
	cherokee_buffer_mrproper (&pair);
	cherokee_buffer_mrproper (&fpath);

	return ret;
}
/* Methods implementation
 */
static ret_t
process_package (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf)
{
	FCGI_Header *header;
	cuint_t      len;
	char        *data;
	cuint_t      type;
	cuint_t      id;
	cuint_t      padding;

	/* Is there enough information?
	 */
	if (inbuf->len < sizeof(FCGI_Header))
		return ret_ok;

	/* At least there is a header
	 */
	header = (FCGI_Header *)inbuf->buf;

	if (header->version != 1) {
		cherokee_buffer_print_debug (inbuf, -1);
		LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_VERSION);
		return ret_error;
	}

	if (header->type != FCGI_STDERR &&
	    header->type != FCGI_STDOUT &&
	    header->type != FCGI_END_REQUEST) {
		cherokee_buffer_print_debug (inbuf, -1);
		LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_PARSING);
		return ret_error;
	}

	/* Read the header
	 */
	type    =  header->type;
	padding =  header->paddingLength;
	id      = (header->requestIdB0     | (header->requestIdB1 << 8));
	len     = (header->contentLengthB0 | (header->contentLengthB1 << 8));
	data    = inbuf->buf +  FCGI_HEADER_LEN;

/*	printf ("have %d, hdr=%d exp_len=%d pad=%d\n", inbuf->len, FCGI_HEADER_LEN, len, padding); */

	/* Is the package complete?
	 */
	if (len + padding > inbuf->len - FCGI_HEADER_LEN) {
/*		printf ("Incomplete: %d < %d\n", len + padding, inbuf->len - FCGI_HEADER_LEN); */
		return ret_ok;
	}

	/* It has received the full package content
	 */
	switch (type) {
	case FCGI_STDERR:
/*		printf ("READ:STDERR (%d): %s", len, data?data:""); */

		LOG_ERROR (CHEROKEE_ERROR_HANDLER_FCGI_STDERR, data);

		/* Debug mode */
		if (SOURCE_INT(hdl->src_ref)->debug) {
			PRINT_MSG ("%.*s\n", len, data);
		}

		break;

	case FCGI_STDOUT:
/*		printf ("READ:STDOUT eof=%d: %d", HDL_CGI_BASE(hdl)->got_eof, len); */
		cherokee_buffer_add (outbuf, data, len);
		break;

	case FCGI_END_REQUEST:
/*		printf ("READ:END"); */
		HDL_CGI_BASE(hdl)->got_eof = true;
		break;

	default:
		SHOULDNT_HAPPEN;
	}

	cherokee_buffer_move_to_begin (inbuf, len + FCGI_HEADER_LEN + padding);
/*	printf ("- FCGI left %d\n", inbuf->len); */
	return ret_eagain;
}
Ejemplo n.º 7
0
ret_t
cherokee_logger_writer_flush (cherokee_logger_writer_t *writer,
                              cherokee_boolean_t        locked)
{
	int   re;
	ret_t ret = ret_ok;

	/* The internal buffer might be empty
	 */
	if (cherokee_buffer_is_empty (&writer->buffer)) {
		return ret_ok;
	}

	if (!locked) {
		CHEROKEE_MUTEX_LOCK (&PRIV(writer)->mutex);
	}

	/* If not, do the proper thing
	 */
	switch (writer->type) {
	case cherokee_logger_writer_stderr:
		/* In this case we ignore errors.
		 */
		re = fwrite (writer->buffer.buf, 1, writer->buffer.len, stderr);
		if (re != (size_t) writer->buffer.len) {
			ret = ret_error;
		}

		/* Cleanup the log buffer even if there is an error,
		 * because it's safer to go on anyway.
		 */
		cherokee_buffer_clean (&writer->buffer);
		break;

	case cherokee_logger_writer_pipe:
	case cherokee_logger_writer_file:
	{
		ssize_t nwr = 0;
		size_t  buflen = writer->buffer.len;

		/* If there is at least 1 page to write then round
		 * down the length to speed up write(s).
		 */
		if (buflen > LOGGER_BUF_PAGESIZE) {
			buflen &= ~LOGGER_BUF_PAGESIZE;
		}

		do {
			nwr = write (writer->fd, writer->buffer.buf, buflen);
		} while (nwr == -1 && errno == EINTR);

		if (nwr <= 0) {
			/* If an error occured in blocking write, then
			 * cleanup the log buffer now because we don't
			 * want to let it grow too much.
			 */
			cherokee_buffer_clean (&writer->buffer);
			ret = ret_error;
			goto out;
		}

		/* OK, something has been written.
		 */
		cherokee_buffer_move_to_begin (&writer->buffer, nwr);
		if (! cherokee_buffer_is_empty (&writer->buffer)) {
			ret = ret_eagain;
		}
		break;
	}
	case cherokee_logger_writer_syslog:
		/* Write to syslog the whole log buffer, then cleanup
		 * it in any case.
		 */
		ret = cherokee_syslog (LOG_INFO, &writer->buffer);
		cherokee_buffer_clean (&writer->buffer);
		break;

	default:
		SHOULDNT_HAPPEN;
		ret = ret_error;
	}

out:
	if (! locked) {
		CHEROKEE_MUTEX_UNLOCK (&PRIV(writer)->mutex);
	}
	return ret;
}
Ejemplo n.º 8
0
ret_t
cherokee_post_send_to_fd (cherokee_post_t          *post,
			  cherokee_socket_t        *sock_in,
			  int                       fd_out,
			  cherokee_buffer_t        *tmp,
			  cherokee_socket_status_t *blocking,
			  cherokee_boolean_t       *did_IO)
{
	ret_t              ret;
	int                r;
	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. Has %d bytes to send\n", buffer->len);

		if (! cherokee_buffer_is_empty (buffer)) {
			r = write (fd_out, buffer->buf, buffer->len);
			if (r < 0) {
				if (errno == EAGAIN) {
					*blocking = socket_writing;
					return ret_eagain;
				}

				TRACE(ENTRIES, "errno %d: %s\n", errno, strerror(errno));
				return ret_error;

			} else if (r == 0) {
				return ret_eagain;
			}

			cherokee_buffer_move_to_begin (buffer, r);

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

		/* Next iteration
		 */
		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;
}
Ejemplo n.º 9
0
static ret_t
process_chunk (cherokee_post_t   *post,
	       cherokee_buffer_t *in,
	       cherokee_buffer_t *out)
{
	char    *p;
	char    *begin;
	char    *end;
        ssize_t  content_size;

        TRACE (ENTRIES, "Post in-buffer len=%d\n", in->len);

	p     = in->buf;
	begin = in->buf;

        while (true) {
                end = in->buf + in->len;

                /* Iterate through the number
		 */
                while ((p < end) &&
                       (((*p >= '0') && (*p <= '9')) ||
                        ((*p >= 'a') && (*p <= 'f')) ||
                        ((*p >= 'A') && (*p <= 'F'))))
                        p++;

                if (unlikely (p+2 > end)) {
                        return ret_ok;
		}

                /* Check the CRLF after the length
		 */
                if (p[0] != CHR_CR) {
                        return ret_error;
		}
                if (p[1] != CHR_LF) {
                        return ret_error;
		}

		p += 2;

                /* Read the length
		 */
                content_size = (size_t) strtoul (begin, NULL, 16);
                if (unlikely (content_size < 0)) {
                        return ret_error;
		}

                /* Check if there's enough info
		 */
                if (content_size == 0) {
                        post->chunked.last = true;

		} else if (p + content_size + 2 > end) {
                        TRACE (ENTRIES, "Unfinished chunk(len="FMT_OFFSET"), has=%d, out->len="FMT_OFFSET"\n",
                               content_size, (int)(end-p), out->len);
			break;
                }

		/* Last block check
		 */
                if (post->chunked.last) {
                        TRACE(ENTRIES, "Last chunk: %s\n", "exiting");

			if (post->chunked.retransmit) {
				cherokee_buffer_add_str (out, "0" CRLF);
			}
			begin = p;
			break;
		}

		/* Move the information
		 */
		if (post->chunked.retransmit) {
			cherokee_buffer_add (out, begin, (p + content_size + 2) - begin);
		} else {
			cherokee_buffer_add (out, p, content_size);
		}

                TRACE (ENTRIES, "Processing chunk len=%d\n", content_size);

                /* Next iteration
		 */
                begin = p + content_size + 2;
		p = begin;
	}

	/* Clean up in-buffer
	 */
	if (begin != in->buf) {
		cherokee_buffer_move_to_begin (in, begin - in->buf);
	}

	/* Very unlikely, but still possible
	 */
	if (! cherokee_buffer_is_empty(in)) {
		TRACE (ENTRIES, "There are %d left-over bytes in the post buffer -> incoming header", in->len);
/* 		cherokee_buffer_add_buffer (&conn->incoming_header, in); */
/* 		cherokee_buffer_clean (in); */
	}

	TRACE (ENTRIES, "Un-chunked buffer len=%d\n", out->len);
	return ret_ok;
}
Ejemplo n.º 10
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;
}