Index: uspace/app/download/main.c
===================================================================
--- uspace/app/download/main.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
+++ uspace/app/download/main.c	(revision 408424e4d6ecbd4f4fe51e827379f230a7e6618e)
@@ -171,5 +171,5 @@
 	
 	http_response_t *response = NULL;
-	rc = http_receive_response(http, &response);
+	rc = http_receive_response(&http->recv_buffer, &response);
 	if (rc != EOK) {
 		fprintf(stderr, "Failed receiving response: %s\n", str_error(rc));
@@ -192,5 +192,5 @@
 		
 		int body_size;
-		while ((body_size = http_receive_body(http, buf, buf_size)) > 0) {
+		while ((body_size = recv_buffer(&http->recv_buffer, buf, buf_size)) > 0) {
 			fwrite(buf, 1, body_size, stdout);
 		}
Index: uspace/lib/http/include/http/http.h
===================================================================
--- uspace/lib/http/include/http/http.h	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
+++ uspace/lib/http/include/http/http.h	(revision 408424e4d6ecbd4f4fe51e827379f230a7e6618e)
@@ -124,8 +124,7 @@
 extern int http_request_format(http_request_t *, char **, size_t *);
 extern int http_send_request(http_t *, http_request_t *);
-extern int http_parse_status(const char *, http_version_t *, uint16_t *,
+extern int http_receive_status(receive_buffer_t *, http_version_t *, uint16_t *,
     char **);
-extern int http_receive_response(http_t *, http_response_t **);
-extern int http_receive_body(http_t *, void *, size_t);
+extern int http_receive_response(receive_buffer_t *, http_response_t **);
 extern void http_response_destroy(http_response_t *);
 extern int http_close(http_t *);
Index: uspace/lib/http/include/http/receive-buffer.h
===================================================================
--- uspace/lib/http/include/http/receive-buffer.h	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
+++ uspace/lib/http/include/http/receive-buffer.h	(revision 408424e4d6ecbd4f4fe51e827379f230a7e6618e)
@@ -65,4 +65,6 @@
 } receive_buffer_mark_t;
 
+typedef bool (*char_class_func_t)(char);
+
 extern int recv_buffer_init(receive_buffer_t *, size_t, receive_func_t, void *);
 extern int recv_buffer_init_const(receive_buffer_t *, void *, size_t);
@@ -79,8 +81,8 @@
 extern ssize_t recv_buffer(receive_buffer_t *, char *, size_t);
 extern ssize_t recv_discard(receive_buffer_t *, char);
+extern ssize_t recv_discard_str(receive_buffer_t *, const char *);
+extern ssize_t recv_while(receive_buffer_t *, char_class_func_t);
 extern ssize_t recv_eol(receive_buffer_t *);
 extern ssize_t recv_line(receive_buffer_t *, char *, size_t);
-
-
 
 #endif
Index: uspace/lib/http/src/receive-buffer.c
===================================================================
--- uspace/lib/http/src/receive-buffer.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
+++ uspace/lib/http/src/receive-buffer.c	(revision 408424e4d6ecbd4f4fe51e827379f230a7e6618e)
@@ -210,4 +210,45 @@
 }
 
+/** Receive a prefix of constant string discard and return number of bytes read
+ * @return number of characters discarded or negative error code
+ */
+ssize_t recv_discard_str(receive_buffer_t *rb, const char *discard)
+{
+	size_t discarded = 0;
+	while (*discard) {
+		ssize_t rc = recv_discard(rb, *discard);
+		if (rc < 0)
+			return rc;
+		if (rc == 0)
+			break;
+		discarded++;
+		discard++;
+	}
+	return discarded;
+}
+
+ssize_t recv_while(receive_buffer_t *rb, char_class_func_t class)
+{
+	size_t received = 0;
+	
+	while (true) {
+		char c = 0;
+		int rc = recv_char(rb, &c, false);
+		if (rc != EOK)
+			return rc;
+		
+		if (!class(c))
+			break;
+		
+		rc = recv_char(rb, &c, true);
+		if (rc != EOK)
+			return rc;
+		
+		received++;
+	}
+	
+	return received;
+}
+
 /** Receive an end of line, either CR, LF, CRLF or LFCR
  *
Index: uspace/lib/http/src/response.c
===================================================================
--- uspace/lib/http/src/response.c	(revision 4d4f656ffc62186811fa02970d77df9e60512a39)
+++ uspace/lib/http/src/response.c	(revision 408424e4d6ecbd4f4fe51e827379f230a7e6618e)
@@ -42,5 +42,72 @@
 #include <http/errno.h>
 
-int http_parse_status(const char *line, http_version_t *out_version,
+static bool is_digit(char c)
+{
+	return (c >= '0' && c <= '9');
+}
+
+static int receive_number(receive_buffer_t *rb, char **str)
+{
+	receive_buffer_mark_t start;
+	receive_buffer_mark_t end;
+	
+	recv_mark(rb, &start);
+	int rc = recv_while(rb, is_digit);
+	if (rc < 0) {
+		recv_unmark(rb, &start);
+		return rc;
+	}
+	recv_mark(rb, &end);
+	
+	rc = recv_cut_str(rb, &start, &end, str);
+	recv_unmark(rb, &start);
+	recv_unmark(rb, &end);
+	return rc;
+}
+
+static int receive_uint8_t(receive_buffer_t *rb, uint8_t *out_value)
+{
+	char *str = NULL;
+	int rc = receive_number(rb, &str);
+	
+	if (rc != EOK)
+		return rc;
+	
+	rc = str_uint8_t(str, NULL, 10, true, out_value);
+	free(str);
+	
+	return rc;
+}
+
+static int receive_uint16_t(receive_buffer_t *rb, uint16_t *out_value)
+{
+	char *str = NULL;
+	int rc = receive_number(rb, &str);
+	
+	if (rc != EOK)
+		return rc;
+	
+	rc = str_uint16_t(str, NULL, 10, true, out_value);
+	free(str);
+	
+	return rc;
+}
+
+static int expect(receive_buffer_t *rb, const char *expect)
+{
+	int rc = recv_discard_str(rb, expect);
+	if (rc < 0)
+		return rc;
+	if ((size_t) rc < str_length(expect))
+		return HTTP_EPARSE;
+	return EOK;
+}
+
+static bool is_not_newline(char c)
+{
+	return (c != '\n' && c != '\r');
+}
+
+int http_receive_status(receive_buffer_t *rb, http_version_t *out_version,
     uint16_t *out_status, char **out_message)
 {
@@ -49,37 +116,62 @@
 	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++;
+	int rc = expect(rb, "HTTP/");
+	if (rc != EOK)
+		return rc;
+	
+	rc = receive_uint8_t(rb, &version.major);
+	if (rc != EOK)
+		return rc;
+	
+	rc = expect(rb, ".");
+	if (rc != EOK)
+		return rc;
+	
+	rc = receive_uint8_t(rb, &version.minor);
+	if (rc != EOK)
+		return rc;
+	
+	rc = expect(rb, " ");
+	if (rc != EOK)
+		return rc;
+	
+	rc = receive_uint16_t(rb, &status);
+	if (rc != EOK)
+		return rc;
+	
+	rc = expect(rb, " ");
+	if (rc != EOK)
+		return rc;
+	
+	receive_buffer_mark_t msg_start;
+	recv_mark(rb, &msg_start);
+	
+	rc = recv_while(rb, is_not_newline);
+	if (rc < 0) {
+		recv_unmark(rb, &msg_start);
+		return rc;
+	}
+	
+	receive_buffer_mark_t msg_end;
+	recv_mark(rb, &msg_end);
 	
 	if (out_message) {
-		message = str_dup(pos);
-		if (message == NULL)
-			return ENOMEM;
+		rc = recv_cut_str(rb, &msg_start, &msg_end, &message);
+		if (rc != EOK) {
+			recv_unmark(rb, &msg_start);
+			recv_unmark(rb, &msg_end);
+			return rc;
+		}
+	}
+	
+	recv_unmark(rb, &msg_start);
+	recv_unmark(rb, &msg_end);
+	
+	rc = recv_eol(rb);
+	if (rc == 0)
+		rc = HTTP_EPARSE;
+	if (rc < 0) {
+		free(message);
+		return rc;
 	}
 	
@@ -93,5 +185,5 @@
 }
 
-int http_receive_response(http_t *http, http_response_t **out_response)
+int http_receive_response(receive_buffer_t *rb, http_response_t **out_response)
 {
 	http_response_t *resp = malloc(sizeof(http_response_t));
@@ -101,24 +193,14 @@
 	http_headers_init(&resp->headers);
 	
-	char *line = malloc(http->buffer_size);
-	if (line == NULL) {
-		free(resp);
-		return ENOMEM;
-	}
-	
-	int rc = recv_line(&http->recv_buffer, line, http->buffer_size);
-	if (rc < 0)
+	int rc = http_receive_status(rb, &resp->version, &resp->status,
+	    &resp->message);
+	if (rc != EOK)
 		goto error;
 	
-	rc = http_parse_status(line, &resp->version, &resp->status,
-	    &resp->message);
+	rc = http_headers_receive(rb, &resp->headers);
 	if (rc != EOK)
 		goto error;
 	
-	rc = http_headers_receive(&http->recv_buffer, &resp->headers);
-	if (rc != EOK)
-		goto error;
-	
-	rc = recv_eol(&http->recv_buffer);
+	rc = recv_eol(rb);
 	if (rc == 0)
 		rc = HTTP_EPARSE;
@@ -130,12 +212,6 @@
 	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->recv_buffer, buf, buf_size);
 }
 
