Index: uspace/lib/http/src/receive-buffer.c
===================================================================
--- uspace/lib/http/src/receive-buffer.c	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
+++ uspace/lib/http/src/receive-buffer.c	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2012 Jiri Svoboda
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdlib.h>
+#include <str.h>
+#include <errno.h>
+#include <macros.h>
+#include <adt/list.h>
+
+#include <http/receive-buffer.h>
+
+int recv_buffer_init(receive_buffer_t *rb, size_t buffer_size,
+    receive_func_t receive, void *client_data)
+{
+	rb->receive = receive;
+	rb->client_data = client_data;
+	
+	rb->in = 0;
+	rb->out = 0;
+	rb->size = buffer_size;
+	
+	list_initialize(&rb->marks);
+	
+	rb->buffer = malloc(buffer_size);
+	if (rb->buffer == NULL)
+		return ENOMEM;
+	return EOK;
+}
+
+static ssize_t dummy_receive(void *unused, void *buf, size_t buf_size)
+{
+	return 0;
+}
+
+int recv_buffer_init_const(receive_buffer_t *rb, void *buf, size_t size)
+{
+	int rc = recv_buffer_init(rb, size, dummy_receive, NULL);
+	if (rc != EOK)
+		return rc;
+	
+	memcpy(rb->buffer, buf, size);
+	rb->in = size;
+	return EOK;
+}
+
+void recv_buffer_fini(receive_buffer_t *rb)
+{
+	free(rb->buffer);
+}
+
+void recv_reset(receive_buffer_t *rb)
+{
+	rb->in = 0;
+	rb->out = 0;
+}
+
+void recv_mark(receive_buffer_t *rb, receive_buffer_mark_t *mark)
+{
+	link_initialize(&mark->link);
+	list_append(&mark->link, &rb->marks);
+	recv_mark_update(rb, mark);
+}
+
+void recv_unmark(receive_buffer_t *rb, receive_buffer_mark_t *mark)
+{
+	list_remove(&mark->link);
+}
+
+void recv_mark_update(receive_buffer_t *rb, receive_buffer_mark_t *mark)
+{
+	mark->offset = rb->out;
+}
+
+int recv_cut(receive_buffer_t *rb, receive_buffer_mark_t *a, receive_buffer_mark_t *b, void **out_buf, size_t *out_size)
+{
+	if (a->offset > b->offset)
+		return EINVAL;
+	
+	size_t size = b->offset - a->offset;
+	void *buf = malloc(size);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	memcpy(buf, rb->buffer + a->offset, size);
+	*out_buf = buf;
+	*out_size = size;
+	return EOK;
+}
+
+int recv_cut_str(receive_buffer_t *rb, receive_buffer_mark_t *a, receive_buffer_mark_t *b, char **out_buf)
+{
+	if (a->offset > b->offset)
+		return EINVAL;
+	
+	size_t size = b->offset - a->offset;
+	char *buf = malloc(size + 1);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	memcpy(buf, rb->buffer + a->offset, size);
+	buf[size] = 0;
+	for (size_t i = 0; i < size; i++) {
+		if (buf[i] == 0) {
+			free(buf);
+			return EIO;
+		}
+	}
+	*out_buf = buf;
+	return EOK;
+}
+
+
+/** Receive one character (with buffering) */
+int recv_char(receive_buffer_t *rb, char *c, bool consume)
+{
+	if (rb->out == rb->in) {
+		size_t free = rb->size - rb->in;
+		if (free == 0) {
+			size_t min_mark = rb->size;
+			list_foreach(rb->marks, link, receive_buffer_mark_t, mark) {
+				min_mark = min(min_mark, mark->offset);
+			}
+			
+			if (min_mark == 0)
+				return ELIMIT;
+			
+			size_t new_in = rb->in - min_mark;
+			memmove(rb->buffer, rb->buffer + min_mark, new_in);
+			rb->out = rb->in = new_in;
+			free = rb->size - rb->in;
+			list_foreach(rb->marks, link, receive_buffer_mark_t, mark) {
+				mark->offset -= min_mark;
+			}
+		}
+		
+		ssize_t rc = rb->receive(rb->client_data, rb->buffer + rb->in, free);
+		if (rc <= 0)
+			return rc;
+		
+		rb->in = rc;
+	}
+	
+	*c = rb->buffer[rb->out];
+	if (consume)
+		rb->out++;
+	return EOK;
+}
+
+ssize_t recv_buffer(receive_buffer_t *rb, char *buf, size_t buf_size)
+{
+	/* Flush any buffered data*/
+	if (rb->out != rb->in) {
+		size_t size = min(rb->in - rb->out, buf_size);
+		memcpy(buf, rb->buffer + rb->out, size);
+		rb->out += size;
+		return size;
+	}
+	
+	return rb->receive(rb->client_data, buf, buf_size);
+}
+
+/** Receive a character and if it is c, discard it from input buffer
+ * @return number of characters discarded (0 or 1) or negative error code
+ */
+ssize_t recv_discard(receive_buffer_t *rb, char discard)
+{
+	char c = 0;
+	int rc = recv_char(rb, &c, false);
+	if (rc != EOK)
+		return rc;
+	if (c != discard)
+		return 0;
+	rc = recv_char(rb, &c, true);
+	if (rc != EOK)
+		return rc;
+	return 1;
+}
+
+/** Receive an end of line, either CR, LF, CRLF or LFCR
+ *
+ * @return number of bytes read (0 if no newline is present in the stream)
+ *         or negative error code
+ */
+ssize_t recv_eol(receive_buffer_t *rb)
+{
+	char c = 0;
+	int rc = recv_char(rb, &c, false);
+	if (rc != EOK)
+		return rc;
+	
+	if (c != '\r' && c != '\n')
+		return 0;
+	
+	rc = recv_char(rb, &c, true);
+	if (rc != EOK)
+		return rc;
+	
+	ssize_t rc2 = recv_discard(rb, (c == '\r' ? '\n' : '\r'));
+	if (rc2 < 0)
+		return rc2;
+	
+	return 1 + rc2;
+}
+
+/* Receive a single line */
+ssize_t recv_line(receive_buffer_t *rb, char *line, size_t size)
+{
+	size_t written = 0;
+	
+	while (written < size) {
+		char c = 0;
+		int rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+		if (c == '\n') {
+			recv_discard(rb, '\r');
+			line[written++] = 0;
+			return written;
+		}
+		else if (c == '\r') {
+			recv_discard(rb, '\n');
+			line[written++] = 0;
+			return written;
+		}
+		line[written++] = c;
+	}
+	
+	return ELIMIT;
+}
+
+/** @}
+ */
