diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c
index 61bc5ca..83b9c99 100644
--- a/libsoup/soup-message-queue.c
+++ b/libsoup/soup-message-queue.c
@@ -97,6 +97,7 @@ soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg,
 	item->callback = callback;
 	item->callback_data = user_data;
 	item->cancellable = g_cancellable_new ();
+	item->redirection_count = 0;
 
 	g_signal_connect (msg, "restarted",
 			  G_CALLBACK (queue_message_restarted), item);
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index b7bc5d1..ca423b3 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -34,6 +34,8 @@ struct SoupMessageQueueItem {
 	guint resolving_proxy_addr : 1;
 	guint resolved_proxy_addr  : 1;
 
+	guint redirection_count;
+
 	/*< private >*/
 	guint removed              : 1;
 	guint ref_count            : 29;
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index b8d79a2..73200c6 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -904,14 +904,23 @@ auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
 static void
 redirect_handler (SoupMessage *msg, gpointer user_data)
 {
-	SoupSession *session = user_data;
+	SoupMessageQueueItem *item = user_data;
+	SoupSession *session;
 	const char *new_loc;
 	SoupURI *new_uri;
 
+	session = item->session;
+
 	new_loc = soup_message_headers_get_one (msg->response_headers,
 						"Location");
 	g_return_if_fail (new_loc != NULL);
 
+	if (item->redirection_count >= SOUP_MAX_REDIRECTION_COUNT) {
+		soup_session_cancel_message (session, msg, SOUP_STATUS_TOO_MANY_REDIRECTS);
+		return;
+	}
+	item->redirection_count++;
+
 	if (msg->status_code == SOUP_STATUS_SEE_OTHER ||
 	    (msg->status_code == SOUP_STATUS_FOUND &&
 	     !SOUP_METHOD_IS_SAFE (msg->method)) ||
@@ -1322,7 +1331,7 @@ queue_message (SoupSession *session, SoupMessage *msg,
 	if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT)) {
 		soup_message_add_header_handler (
 			msg, "got_body", "Location",
-			G_CALLBACK (redirect_handler), session);
+			G_CALLBACK (redirect_handler), item);
 	}
 
 	g_signal_emit (session, signals[REQUEST_QUEUED], 0, msg);
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index 6080008..efb4ffc 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -71,6 +71,8 @@ GType soup_session_get_type (void);
 #define SOUP_SESSION_ADD_FEATURE_BY_TYPE    "add-feature-by-type"
 #define SOUP_SESSION_REMOVE_FEATURE_BY_TYPE "remove-feature-by-type"
 
+#define SOUP_MAX_REDIRECTION_COUNT 20
+
 GMainContext   *soup_session_get_async_context(SoupSession           *session);
 
 void            soup_session_queue_message    (SoupSession           *session,
diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c
index 11422ac..ce52772 100644
--- a/libsoup/soup-status.c
+++ b/libsoup/soup-status.c
@@ -78,6 +78,7 @@
  * closed the connection unexpectedly
  * @SOUP_STATUS_MALFORMED: Malformed data (usually a programmer error)
  * @SOUP_STATUS_TRY_AGAIN: Formerly used internally. Now unused.
+ * @SOUP_STATUS_TOO_MANY_REDIRECTS: There were too many redirections
  * @SOUP_STATUS_CONTINUE: 100 Continue (HTTP)
  * @SOUP_STATUS_SWITCHING_PROTOCOLS: 101 Switching Protocols (HTTP)
  * @SOUP_STATUS_PROCESSING: 102 Processing (WebDAV)
@@ -185,6 +186,7 @@ static const struct {
 #endif
 	{ SOUP_STATUS_IO_ERROR,                   "Connection terminated unexpectedly" },
 	{ SOUP_STATUS_MALFORMED,                  "Message Corrupt" },
+	{ SOUP_STATUS_TOO_MANY_REDIRECTS,         "Too many redirects" },
 
 	/* Informational */
 	{ SOUP_STATUS_CONTINUE,                   "Continue" },
diff --git a/libsoup/soup-status.h b/libsoup/soup-status.h
index 66e9f1c..0d8b74f 100644
--- a/libsoup/soup-status.h
+++ b/libsoup/soup-status.h
@@ -32,6 +32,7 @@ typedef enum {
 	SOUP_STATUS_IO_ERROR,
 	SOUP_STATUS_MALFORMED,
 	SOUP_STATUS_TRY_AGAIN,
+	SOUP_STATUS_TOO_MANY_REDIRECTS,
 
 	/* HTTP Status Codes */
 	SOUP_STATUS_CONTINUE                        = 100,
