Index: uspace/app/download/main.c
===================================================================
--- uspace/app/download/main.c	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
+++ uspace/app/download/main.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
@@ -135,19 +135,17 @@
 	}
 	
-	http_header_t *header_host = http_header_create("Host", uri->host);
-	if (header_host == NULL) {
-		fprintf(stderr, "Failed creating Host header\n");
-		uri_destroy(uri);
-		return 3;
-	}
-	list_append(&header_host->link, &req->headers);
-	
-	http_header_t *header_ua = http_header_create("User-Agent", USER_AGENT);
-	if (header_ua == NULL) {
-		fprintf(stderr, "Failed creating User-Agent header\n");
-		uri_destroy(uri);
-		return 3;
-	}
-	list_append(&header_ua->link, &req->headers);
+	int rc = http_headers_append(&req->headers, "Host", uri->host);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed setting Host header: %s\n", str_error(rc));
+		uri_destroy(uri);
+		return rc;
+	}
+	
+	rc = http_headers_append(&req->headers, "User-Agent", USER_AGENT);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed creating User-Agent header: %s\n", str_error(rc));
+		uri_destroy(uri);
+		return rc;
+	}
 	
 	http_t *http = http_create(uri->host, port);
@@ -158,5 +156,5 @@
 	}
 	
-	int rc = http_connect(http);
+	rc = http_connect(http);
 	if (rc != EOK) {
 		fprintf(stderr, "Failed connecting: %s\n", str_error(rc));
Index: uspace/lib/http/include/http/errno.h
===================================================================
--- uspace/lib/http/include/http/errno.h	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
+++ uspace/lib/http/include/http/errno.h	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
@@ -0,0 +1,48 @@
+/*
+ * 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
+ */
+
+#ifndef HTTP_ERRNO_H_
+#define HTTP_ERRNO_H_
+
+#include <errno.h>
+
+#define HTTP_EMULTIPLE_HEADERS -20001
+#define HTTP_EMISSING_HEADER -20002
+#define HTTP_EPARSE -20003
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/http/include/http/http.h
===================================================================
--- uspace/lib/http/include/http/http.h	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
+++ uspace/lib/http/include/http/http.h	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
@@ -67,7 +67,11 @@
 
 typedef struct {
+	list_t list;
+} http_headers_t;
+
+typedef struct {
 	char *method;
 	char *path;
-	list_t headers;
+	http_headers_t headers;
 } http_request_t;
 
@@ -76,5 +80,5 @@
 	uint16_t status;
 	char *message;
-	list_t headers;
+	http_headers_t headers;
 } http_response_t;
 
@@ -88,6 +92,31 @@
 extern int http_header_receive(receive_buffer_t *, http_header_t *);
 extern void http_header_normalize_value(char *);
+extern bool http_header_name_match(const char *, const char *);
 ssize_t http_header_encode(http_header_t *, char *, size_t);
 extern void http_header_destroy(http_header_t *);
+
+extern void http_headers_init(http_headers_t *);
+extern int http_headers_find_single(http_headers_t *, const char *,
+    http_header_t **);
+extern int http_headers_append(http_headers_t *, const char *, const char *);
+extern int http_headers_set(http_headers_t *, const char *, const char *);
+extern int http_headers_get(http_headers_t *, const char *, char **);
+extern int http_headers_receive(receive_buffer_t *, http_headers_t *);
+extern void http_headers_clear(http_headers_t *);
+
+#define http_headers_foreach(headers, iter) \
+    list_foreach((headers).list, link, http_header_t, (iter))
+
+static inline void http_headers_remove(http_headers_t *headers,
+    http_header_t *header)
+{
+	list_remove(&header->link);
+}
+
+static inline void http_headers_append_header(http_headers_t *headers,
+    http_header_t *header)
+{
+	list_append(&header->link, &headers->list);
+}
 
 extern http_request_t *http_request_create(const char *, const char *);
Index: uspace/lib/http/src/headers.c
===================================================================
--- uspace/lib/http/src/headers.c	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
+++ uspace/lib/http/src/headers.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
@@ -41,4 +41,5 @@
 #include <http/http.h>
 #include <http/ctype.h>
+#include <http/errno.h>
 
 #define HTTP_HEADER_LINE "%s: %s\r\n"
@@ -204,5 +205,4 @@
 	int rc = http_header_receive_name(rb, &name);
 	if (rc != EOK) {
-		printf("Failed receiving header name\n");
 		return rc;
 	}
@@ -247,4 +247,135 @@
 }
 
+/** Test if two header names are equivalent
+ *
+ */
+bool http_header_name_match(const char *name_a, const char *name_b)
+{
+	return stricmp(name_a, name_b) == 0;
+}
+
+void http_headers_init(http_headers_t *headers) {
+	list_initialize(&headers->list);
+}
+
+int http_headers_find_single(http_headers_t *headers, const char *name,
+    http_header_t **out_header)
+{
+	http_header_t *found = NULL;
+	http_headers_foreach(*headers, header) {
+		if (!http_header_name_match(header->name, name))
+			continue;
+		
+		if (found == NULL) {
+			found = header;
+		}
+		else {
+			return HTTP_EMULTIPLE_HEADERS;
+		}
+	}
+	
+	if (found == NULL)
+		return HTTP_EMISSING_HEADER;
+	
+	*out_header = found;
+	return EOK;
+}
+
+int http_headers_append(http_headers_t *headers, const char *name,
+    const char *value)
+{
+	http_header_t *header = http_header_create(name, value);
+	if (header == NULL)
+		return ENOMEM;
+	
+	http_headers_append_header(headers, header);
+	return EOK;
+}
+
+int http_headers_set(http_headers_t *headers, const char *name,
+    const char *value)
+{
+	http_header_t *header = NULL;
+	int rc = http_headers_find_single(headers, name, &header);
+	if (rc != EOK && rc != HTTP_EMISSING_HEADER)
+		return rc;
+	
+	if (rc == HTTP_EMISSING_HEADER)
+		return http_headers_append(headers, name, value);
+	
+	char *new_value = str_dup(value);
+	if (new_value == NULL)
+		return ENOMEM;
+	
+	free(header->value);
+	header->value = new_value;
+	return EOK;
+}
+
+int http_headers_get(http_headers_t *headers, const char *name, char **value)
+{
+	http_header_t *header = NULL;
+	int rc = http_headers_find_single(headers, name, &header);
+	if (rc != EOK)
+		return rc;
+	
+	*value = header->value;
+	return EOK;
+}
+
+int http_headers_receive(receive_buffer_t *rb, http_headers_t *headers)
+{
+	int rc = EOK;
+	unsigned added = 0;
+	
+	while (true) {
+		char c = 0;
+		rc = recv_char(rb, &c, false);
+		if (rc != EOK)
+			goto error;
+		
+		if (c == '\n' || c == '\r')
+			break;
+		
+		http_header_t *header = malloc(sizeof(http_header_t));
+		if (header == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+		http_header_init(header);
+		
+		rc = http_header_receive(rb, header);
+		if (rc != EOK) {
+			free(header);
+			goto error;
+		}
+		
+		http_headers_append_header(headers, header);
+		added++;
+	}
+	
+	return EOK;
+error:
+	while (added-- > 0) {
+		link_t *link = list_last(&headers->list);
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		http_headers_remove(headers, header);
+		http_header_destroy(header);
+	}
+	return rc;
+}
+
+void http_headers_clear(http_headers_t *headers)
+{
+	link_t *link = list_first(&headers->list);
+	while (link != NULL) {
+		link_t *next = list_next(link, &headers->list);
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		list_remove(link);
+		http_header_destroy(header);
+		link = next;
+	}
+}
+
 /** @}
  */
Index: uspace/lib/http/src/request.c
===================================================================
--- uspace/lib/http/src/request.c	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
+++ uspace/lib/http/src/request.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
@@ -65,5 +65,5 @@
 	}
 	
-	list_initialize(&req->headers);
+	http_headers_init(&req->headers);
 	
 	return req;
@@ -74,11 +74,5 @@
 	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;
-	}
+	http_headers_clear(&req->headers);
 	free(req);
 }
@@ -104,5 +98,5 @@
 	size_t size = meth_size;
 	
-	list_foreach(req->headers, link, http_header_t, header) {
+	http_headers_foreach(req->headers, header) {
 		ssize_t header_size = http_header_encode(header, NULL, 0);
 		if (header_size < 0)
@@ -126,5 +120,5 @@
 	pos_size -= written;
 	
-	list_foreach(req->headers, link, http_header_t, header) {
+	http_headers_foreach(req->headers, header) {
 		written = http_header_encode(header, pos, pos_size);
 		if (written < 0) {
Index: uspace/lib/http/src/response.c
===================================================================
--- uspace/lib/http/src/response.c	(revision b623b68e159f4973ecd11ab5fb53eca272b74c6d)
+++ uspace/lib/http/src/response.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
@@ -40,4 +40,5 @@
 
 #include <http/http.h>
+#include <http/errno.h>
 
 int http_parse_status(const char *line, http_version_t *out_version,
@@ -98,5 +99,5 @@
 		return ENOMEM;
 	memset(resp, 0, sizeof(http_response_t));
-	list_initialize(&resp->headers);
+	http_headers_init(&resp->headers);
 	
 	char *line = malloc(http->buffer_size);
@@ -115,28 +116,13 @@
 		goto error;
 	
-	while (true) {
-		rc = recv_eol(&http->recv_buffer);
-		if (rc < 0)
-			goto error;
-		
-		/* Empty line ends header part */
-		if (rc > 0)
-			break;
-		
-		http_header_t *header = malloc(sizeof(http_header_t));
-		if (header == NULL) {
-			rc = ENOMEM;
-			goto error;
-		}
-		http_header_init(header);
-		
-		rc = http_header_receive(&http->recv_buffer, header);
-		if (rc != EOK) {
-			free(header);
-			goto error;
-		}
-		
-		list_append(&header->link, &resp->headers);
-	}
+	rc = http_headers_receive(&http->recv_buffer, &resp->headers);
+	if (rc != EOK)
+		goto error;
+	
+	rc = recv_eol(&http->recv_buffer);
+	if (rc == 0)
+		rc = HTTP_EPARSE;
+	if (rc < 0)
+		goto error;
 	
 	*out_response = resp;
@@ -157,11 +143,5 @@
 {
 	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;
-	}
+	http_headers_clear(&resp->headers);
 	free(resp);
 }
