Index: uspace/lib/http/Makefile
===================================================================
--- uspace/lib/http/Makefile	(revision d7b7f5e312adb3acb6e7c2044551454dfd1e4019)
+++ uspace/lib/http/Makefile	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
@@ -34,5 +34,8 @@
 
 SOURCES = \
-	http.c
+	http.c \
+	headers.c \
+	request.c \
+	response.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/http/headers.c
===================================================================
--- uspace/lib/http/headers.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
+++ uspace/lib/http/headers.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
@@ -0,0 +1,126 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include "http.h"
+
+#define HTTP_HEADER_LINE "%s: %s\r\n"
+
+static char *cut_str(const char *start, const char *end)
+{
+	size_t size = end - start;
+	return str_ndup(start, size);
+}
+
+http_header_t *http_header_create(const char *name, const char *value)
+{
+	char *dname = str_dup(name);
+	if (dname == NULL)
+		return NULL;
+	
+	char *dvalue = str_dup(value);
+	if (dvalue == NULL) {
+		free(dname);
+		return NULL;
+	}
+
+	return http_header_create_no_copy(dname, dvalue);
+}
+
+http_header_t *http_header_create_no_copy(char *name, char *value)
+{
+	http_header_t *header = malloc(sizeof(http_header_t));
+	if (header == NULL)
+		return NULL;
+	
+	link_initialize(&header->link);
+	header->name = name;
+	header->value = value;
+	
+	return header;
+}
+
+void http_header_destroy(http_header_t *header)
+{
+	free(header->name);
+	free(header->value);
+	free(header);
+}
+
+ssize_t http_encode_header(char *buf, size_t buf_size, http_header_t *header)
+{
+	/* TODO properly split long header values */
+	if (buf == NULL) {
+		return printf_size(HTTP_HEADER_LINE, header->name, header->value);
+	}
+	else {
+		return snprintf(buf, buf_size,
+		    HTTP_HEADER_LINE, header->name, header->value);
+	}
+}
+
+int http_parse_header(const char *line, char **out_name, char **out_value)
+{
+	const char *pos = line;
+	while (*pos != 0 && *pos != ':') pos++;
+	if (*pos != ':')
+		return EINVAL;
+	
+	char *name = cut_str(line, pos);
+	if (name == NULL)
+		return ENOMEM;
+	
+	pos++;
+	
+	while (*pos == ' ') pos++;
+	
+	char *value = str_dup(pos);
+	if (value == NULL) {
+		free(name);
+		return ENOMEM;
+	}
+	
+	*out_name = name;
+	*out_value = value;
+	
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/http/http.c
===================================================================
--- uspace/lib/http/http.c	(revision d7b7f5e312adb3acb6e7c2044551454dfd1e4019)
+++ uspace/lib/http/http.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
@@ -44,15 +44,5 @@
 #include "http.h"
 
-#define HTTP_METHOD_LINE "%s %s HTTP/1.1\r\n"
-#define HTTP_HEADER_LINE "%s: %s\r\n"
-#define HTTP_REQUEST_LINE "\r\n"
-
-static char *cut_str(const char *start, const char *end)
-{
-	size_t size = end - start;
-	return str_ndup(start, size);
-}
-
-static void recv_reset(http_t *http)
+void recv_reset(http_t *http)
 {
 	http->recv_buffer_in = 0;
@@ -61,5 +51,5 @@
 
 /** Receive one character (with buffering) */
-static int recv_char(http_t *http, char *c, bool consume)
+int recv_char(http_t *http, char *c, bool consume)
 {
 	if (http->recv_buffer_out == http->recv_buffer_in) {
@@ -79,5 +69,5 @@
 }
 
-static ssize_t recv_buffer(http_t *http, char *buf, size_t buf_size)
+ssize_t recv_buffer(http_t *http, char *buf, size_t buf_size)
 {
 	/* Flush any buffered data*/
@@ -93,5 +83,5 @@
 
 /** Receive a character and if it is c, discard it from input buffer */
-static int recv_discard(http_t *http, char discard)
+int recv_discard(http_t *http, char discard)
 {
 	char c = 0;
@@ -105,5 +95,5 @@
 
 /* Receive a single line */
-static ssize_t recv_line(http_t *http, char *line, size_t size)
+ssize_t recv_line(http_t *http, char *line, size_t size)
 {
 	size_t written = 0;
@@ -198,319 +188,4 @@
 }
 
-http_header_t *http_header_create(const char *name, const char *value)
-{
-	char *dname = str_dup(name);
-	if (dname == NULL)
-		return NULL;
-	
-	char *dvalue = str_dup(value);
-	if (dvalue == NULL) {
-		free(dname);
-		return NULL;
-	}
-
-	return http_header_create_no_copy(dname, dvalue);
-}
-
-http_header_t *http_header_create_no_copy(char *name, char *value)
-{
-	http_header_t *header = malloc(sizeof(http_header_t));
-	if (header == NULL)
-		return NULL;
-	
-	link_initialize(&header->link);
-	header->name = name;
-	header->value = value;
-	
-	return header;
-}
-
-void http_header_destroy(http_header_t *header)
-{
-	free(header->name);
-	free(header->value);
-	free(header);
-}
-
-http_request_t *http_request_create(const char *method, const char *path)
-{
-	http_request_t *req = malloc(sizeof(http_request_t));
-	if (req == NULL)
-		return NULL;
-	
-	req->method = str_dup(method);
-	if (req->method == NULL) {
-		free(req);
-		return NULL;
-	}
-	
-	req->path = str_dup(path);
-	if (req->path == NULL) {
-		free(req->method);
-		free(req);
-		return NULL;
-	}
-	
-	list_initialize(&req->headers);
-	
-	return req;
-}
-
-void http_request_destroy(http_request_t *req)
-{
-	free(req->method);
-	free(req->path);
-	link_t *link = req->headers.head.next;
-	while (link != &req->headers.head) {
-		link_t *next = link->next;
-		http_header_t *header = list_get_instance(link, http_header_t, link);
-		http_header_destroy(header);
-		link = next;
-	}
-	free(req);
-}
-
-static ssize_t http_encode_method(char *buf, size_t buf_size,
-    const char *method, const char *path)
-{
-	if (buf == NULL) {
-		return printf_size(HTTP_METHOD_LINE, method, path);
-	}
-	else {
-		return snprintf(buf, buf_size, HTTP_METHOD_LINE, method, path);
-	}
-}
-
-static ssize_t http_encode_header(char *buf, size_t buf_size,
-    http_header_t *header)
-{
-	/* TODO properly split long header values */
-	if (buf == NULL) {
-		return printf_size(HTTP_HEADER_LINE, header->name, header->value);
-	}
-	else {
-		return snprintf(buf, buf_size,
-		    HTTP_HEADER_LINE, header->name, header->value);
-	}
-}
-
-int http_request_format(http_request_t *req, char **out_buf,
-    size_t *out_buf_size)
-{
-	/* Compute the size of the request */
-	ssize_t meth_size = http_encode_method(NULL, 0, req->method, req->path);
-	if (meth_size < 0)
-		return meth_size;
-	size_t size = meth_size;
-	
-	list_foreach(req->headers, link, http_header_t, header) {
-		ssize_t header_size = http_encode_header(NULL, 0, header);
-		if (header_size < 0)
-			return header_size;
-		size += header_size;
-	}
-	size += str_length(HTTP_REQUEST_LINE);
-	
-	char *buf = malloc(size);
-	if (buf == NULL)
-		return ENOMEM;
-	
-	char *pos = buf;
-	size_t pos_size = size;
-	ssize_t written = http_encode_method(pos, pos_size, req->method, req->path);
-	if (written < 0) {
-		free(buf);
-		return written;
-	}
-	pos += written;
-	pos_size -= written;
-	
-	list_foreach(req->headers, link, http_header_t, header) {
-		written = http_encode_header(pos, pos_size, header);
-		if (written < 0) {
-			free(buf);
-			return written;
-		}
-		pos += written;
-		pos_size -= written;
-	}
-	
-	size_t rlsize = str_size(HTTP_REQUEST_LINE);
-	memcpy(pos, HTTP_REQUEST_LINE, rlsize);
-	pos_size -= rlsize;
-	assert(pos_size == 0);
-	
-	*out_buf = buf;
-	*out_buf_size = size;
-	return EOK;
-}
-
-int http_send_request(http_t *http, http_request_t *req)
-{
-	char *buf;
-	size_t buf_size;
-	
-	int rc = http_request_format(req, &buf, &buf_size);
-	if (rc != EOK)
-		return rc;
-	
-	rc = send(http->conn_sd, buf, buf_size, 0);
-	free(buf);
-	
-	return rc;
-}
-
-int http_parse_status(const char *line, http_version_t *out_version,
-    uint16_t *out_status, char **out_message)
-{
-	http_version_t version;
-	uint16_t status;
-	char *message = NULL;
-	
-	if (!str_test_prefix(line, "HTTP/"))
-		return EINVAL;
-	
-	const char *pos_version = line + 5;
-	const char *pos = pos_version;
-	
-	int rc = str_uint8_t(pos_version, &pos, 10, false, &version.major);
-	if (rc != EOK)
-		return rc;
-	if (*pos != '.')
-		return EINVAL;
-	pos++;
-	
-	pos_version = pos;
-	rc = str_uint8_t(pos_version, &pos, 10, false, &version.minor);
-	if (rc != EOK)
-		return rc;
-	if (*pos != ' ')
-		return EINVAL;
-	pos++;
-	
-	const char *pos_status = pos;
-	rc = str_uint16_t(pos_status, &pos, 10, false, &status);
-	if (rc != EOK)
-		return rc;
-	if (*pos != ' ')
-		return EINVAL;
-	pos++;
-	
-	if (out_message) {
-		message = str_dup(pos);
-		if (message == NULL)
-			return ENOMEM;
-	}
-	
-	if (out_version)
-		*out_version = version;
-	if (out_status)
-		*out_status = status;
-	if (out_message)
-		*out_message = message;
-	return EOK;
-}
-
-int http_parse_header(const char *line, char **out_name, char **out_value)
-{
-	const char *pos = line;
-	while (*pos != 0 && *pos != ':') pos++;
-	if (*pos != ':')
-		return EINVAL;
-	
-	char *name = cut_str(line, pos);
-	if (name == NULL)
-		return ENOMEM;
-	
-	pos++;
-	
-	while (*pos == ' ') pos++;
-	
-	char *value = str_dup(pos);
-	if (value == NULL) {
-		free(name);
-		return ENOMEM;
-	}
-	
-	*out_name = name;
-	*out_value = value;
-	
-	return EOK;
-}
-
-int http_receive_response(http_t *http, http_response_t **out_response)
-{
-	http_response_t *resp = malloc(sizeof(http_response_t));
-	if (resp == NULL)
-		return ENOMEM;
-	memset(resp, 0, sizeof(http_response_t));
-	list_initialize(&resp->headers);
-	
-	char *line = malloc(http->buffer_size);
-	if (line == NULL) {
-		free(resp);
-		return ENOMEM;
-	}
-	
-	int rc = recv_line(http, line, http->buffer_size);
-	if (rc < 0)
-		goto error;
-	
-	rc = http_parse_status(line, &resp->version, &resp->status,
-	    &resp->message);
-	if (rc != EOK)
-		goto error;
-	
-	while (true) {
-		rc = recv_line(http, line, http->buffer_size);
-		if (rc < 0)
-			goto error;
-		if (*line == 0)
-			break;
-		
-		char *name = NULL;
-		char *value = NULL;
-		rc = http_parse_header(line, &name, &value);
-		if (rc != EOK)
-			goto error;
-		
-		http_header_t *header = http_header_create_no_copy(name, value);
-		if (header == NULL) {
-			free(name);
-			free(value);
-			rc = ENOMEM;
-			goto error;
-		}
-		
-		list_append(&header->link, &resp->headers);
-	}
-	
-	*out_response = resp;
-	
-	return EOK;
-error:
-	free(line);
-	http_response_destroy(resp);
-	return rc;
-}
-
-int http_receive_body(http_t *http, void *buf, size_t buf_size)
-{
-	return recv_buffer(http, buf, buf_size);
-}
-
-void http_response_destroy(http_response_t *resp)
-{
-	free(resp->message);
-	link_t *link = resp->headers.head.next;
-	while (link != &resp->headers.head) {
-		link_t *next = link->next;
-		http_header_t *header = list_get_instance(link, http_header_t, link);
-		http_header_destroy(header);
-		link = next;
-	}
-	free(resp);
-}
-
 int http_close(http_t *http)
 {
Index: uspace/lib/http/http.h
===================================================================
--- uspace/lib/http/http.h	(revision d7b7f5e312adb3acb6e7c2044551454dfd1e4019)
+++ uspace/lib/http/http.h	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
@@ -91,4 +91,5 @@
     char **);
 extern int http_parse_header(const char *, char **, char **);
+ssize_t http_encode_header(char *, size_t, http_header_t *);
 extern int http_receive_response(http_t *, http_response_t **);
 extern int http_receive_body(http_t *, void *, size_t);
@@ -97,4 +98,10 @@
 extern void http_destroy(http_t *);
 
+extern void recv_reset(http_t *);
+extern int recv_char(http_t *, char *, bool);
+extern ssize_t recv_buffer(http_t *, char *, size_t);
+extern int recv_discard(http_t *, char);
+extern ssize_t recv_line(http_t *, char *, size_t);
+
 #endif
 
Index: uspace/lib/http/request.c
===================================================================
--- uspace/lib/http/request.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
+++ uspace/lib/http/request.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
@@ -0,0 +1,164 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include <net/socket.h>
+
+#include "http.h"
+
+#define HTTP_METHOD_LINE "%s %s HTTP/1.1\r\n"
+#define HTTP_REQUEST_LINE "\r\n"
+
+http_request_t *http_request_create(const char *method, const char *path)
+{
+	http_request_t *req = malloc(sizeof(http_request_t));
+	if (req == NULL)
+		return NULL;
+	
+	req->method = str_dup(method);
+	if (req->method == NULL) {
+		free(req);
+		return NULL;
+	}
+	
+	req->path = str_dup(path);
+	if (req->path == NULL) {
+		free(req->method);
+		free(req);
+		return NULL;
+	}
+	
+	list_initialize(&req->headers);
+	
+	return req;
+}
+
+void http_request_destroy(http_request_t *req)
+{
+	free(req->method);
+	free(req->path);
+	link_t *link = req->headers.head.next;
+	while (link != &req->headers.head) {
+		link_t *next = link->next;
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		http_header_destroy(header);
+		link = next;
+	}
+	free(req);
+}
+
+static ssize_t http_encode_method(char *buf, size_t buf_size,
+    const char *method, const char *path)
+{
+	if (buf == NULL) {
+		return printf_size(HTTP_METHOD_LINE, method, path);
+	}
+	else {
+		return snprintf(buf, buf_size, HTTP_METHOD_LINE, method, path);
+	}
+}
+
+int http_request_format(http_request_t *req, char **out_buf,
+    size_t *out_buf_size)
+{
+	/* Compute the size of the request */
+	ssize_t meth_size = http_encode_method(NULL, 0, req->method, req->path);
+	if (meth_size < 0)
+		return meth_size;
+	size_t size = meth_size;
+	
+	list_foreach(req->headers, link, http_header_t, header) {
+		ssize_t header_size = http_encode_header(NULL, 0, header);
+		if (header_size < 0)
+			return header_size;
+		size += header_size;
+	}
+	size += str_length(HTTP_REQUEST_LINE);
+	
+	char *buf = malloc(size);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	char *pos = buf;
+	size_t pos_size = size;
+	ssize_t written = http_encode_method(pos, pos_size, req->method, req->path);
+	if (written < 0) {
+		free(buf);
+		return written;
+	}
+	pos += written;
+	pos_size -= written;
+	
+	list_foreach(req->headers, link, http_header_t, header) {
+		written = http_encode_header(pos, pos_size, header);
+		if (written < 0) {
+			free(buf);
+			return written;
+		}
+		pos += written;
+		pos_size -= written;
+	}
+	
+	size_t rlsize = str_size(HTTP_REQUEST_LINE);
+	memcpy(pos, HTTP_REQUEST_LINE, rlsize);
+	pos_size -= rlsize;
+	assert(pos_size == 0);
+	
+	*out_buf = buf;
+	*out_buf_size = size;
+	return EOK;
+}
+
+int http_send_request(http_t *http, http_request_t *req)
+{
+	char *buf;
+	size_t buf_size;
+	
+	int rc = http_request_format(req, &buf, &buf_size);
+	if (rc != EOK)
+		return rc;
+	
+	rc = send(http->conn_sd, buf, buf_size, 0);
+	free(buf);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/http/response.c
===================================================================
--- uspace/lib/http/response.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
+++ uspace/lib/http/response.c	(revision f9a28312911b00b866d97c0f8c9ab3ea4555edaf)
@@ -0,0 +1,169 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include "http.h"
+
+int http_parse_status(const char *line, http_version_t *out_version,
+    uint16_t *out_status, char **out_message)
+{
+	http_version_t version;
+	uint16_t status;
+	char *message = NULL;
+	
+	if (!str_test_prefix(line, "HTTP/"))
+		return EINVAL;
+	
+	const char *pos_version = line + 5;
+	const char *pos = pos_version;
+	
+	int rc = str_uint8_t(pos_version, &pos, 10, false, &version.major);
+	if (rc != EOK)
+		return rc;
+	if (*pos != '.')
+		return EINVAL;
+	pos++;
+	
+	pos_version = pos;
+	rc = str_uint8_t(pos_version, &pos, 10, false, &version.minor);
+	if (rc != EOK)
+		return rc;
+	if (*pos != ' ')
+		return EINVAL;
+	pos++;
+	
+	const char *pos_status = pos;
+	rc = str_uint16_t(pos_status, &pos, 10, false, &status);
+	if (rc != EOK)
+		return rc;
+	if (*pos != ' ')
+		return EINVAL;
+	pos++;
+	
+	if (out_message) {
+		message = str_dup(pos);
+		if (message == NULL)
+			return ENOMEM;
+	}
+	
+	if (out_version)
+		*out_version = version;
+	if (out_status)
+		*out_status = status;
+	if (out_message)
+		*out_message = message;
+	return EOK;
+}
+
+int http_receive_response(http_t *http, http_response_t **out_response)
+{
+	http_response_t *resp = malloc(sizeof(http_response_t));
+	if (resp == NULL)
+		return ENOMEM;
+	memset(resp, 0, sizeof(http_response_t));
+	list_initialize(&resp->headers);
+	
+	char *line = malloc(http->buffer_size);
+	if (line == NULL) {
+		free(resp);
+		return ENOMEM;
+	}
+	
+	int rc = recv_line(http, line, http->buffer_size);
+	if (rc < 0)
+		goto error;
+	
+	rc = http_parse_status(line, &resp->version, &resp->status,
+	    &resp->message);
+	if (rc != EOK)
+		goto error;
+	
+	while (true) {
+		rc = recv_line(http, line, http->buffer_size);
+		if (rc < 0)
+			goto error;
+		if (*line == 0)
+			break;
+		
+		char *name = NULL;
+		char *value = NULL;
+		rc = http_parse_header(line, &name, &value);
+		if (rc != EOK)
+			goto error;
+		
+		http_header_t *header = http_header_create_no_copy(name, value);
+		if (header == NULL) {
+			free(name);
+			free(value);
+			rc = ENOMEM;
+			goto error;
+		}
+		
+		list_append(&header->link, &resp->headers);
+	}
+	
+	*out_response = resp;
+	
+	return EOK;
+error:
+	free(line);
+	http_response_destroy(resp);
+	return rc;
+}
+
+int http_receive_body(http_t *http, void *buf, size_t buf_size)
+{
+	return recv_buffer(http, buf, buf_size);
+}
+
+void http_response_destroy(http_response_t *resp)
+{
+	free(resp->message);
+	link_t *link = resp->headers.head.next;
+	while (link != &resp->headers.head) {
+		link_t *next = link->next;
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		http_header_destroy(header);
+		link = next;
+	}
+	free(resp);
+}
+
+/** @}
+ */
