Send over the HTTP status code in the ViewHostMsg_FrameNavigate message coming in from the renderer. 

A failed HTTP navigation like a 404 response to a request is followed by two responses. The first one which is associated with the failed response. This does not send over any information about the failure to the browser and thus appears as a normal navigation.The second response is for the actual 404 page being loaded. 

For network errors the browser does get notified via RenderView::DidFailProvisionalLoadWithError. However due to a prototype mismatch the corresponding function in WebContents is never invoked.

Added a new automation message AutomationMsg_NavigationFailed, which carries information about failed navigations to automation clients.The changes to the navigation controller include sending over the http status code and the URL to observers.

The ExternalTabContainer also subscribes to the FAIL_PROVISIONAL_LOAD_WITH_ERROR notification, so it can inform clients about errors. We also ignore the next NAV_ENTRY_COMMITTED notification after an error due to the reasons mentioned above.


Review URL: http://codereview.chromium.org/21495

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10023 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc
index 8491011..59dd51d 100644
--- a/chrome/browser/external_tab_container.cc
+++ b/chrome/browser/external_tab_container.cc
@@ -8,6 +8,7 @@
 #include "base/win_util.h"
 #include "chrome/browser/automation/automation_provider.h"
 #include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents/provisional_load_details.h"
 #include "chrome/browser/tab_contents/tab_contents.h"
 #include "chrome/browser/views/tab_contents_container_view.h"
 #include "chrome/browser/tab_contents/web_contents.h"
@@ -29,7 +30,8 @@
       tab_contents_(NULL),
       external_accel_table_(NULL),
       external_accel_entry_count_(0),
-      tab_contents_container_(NULL) {
+      tab_contents_container_(NULL),
+      ignore_next_load_notification_(false) {
 }
 
 ExternalTabContainer::~ExternalTabContainer() {
@@ -95,6 +97,8 @@
   DCHECK(controller);
   registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
                  Source<NavigationController>(controller));
+  registrar_.Add(this, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
+                 Source<NavigationController>(controller));
   NotificationService::current()->Notify(
       NotificationType::EXTERNAL_TAB_CREATED,
       Source<NavigationController>(controller),
@@ -251,21 +255,48 @@
 void ExternalTabContainer::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
+  static const int kHttpClientErrorStart = 400;
+  static const int kHttpServerErrorEnd = 510;
+
   switch (type.value) {
     case NotificationType::NAV_ENTRY_COMMITTED:
+      if (ignore_next_load_notification_) {
+        ignore_next_load_notification_ = false;
+        return;
+      }
+
       if (automation_) {
         const NavigationController::LoadCommittedDetails* commit =
             Details<NavigationController::LoadCommittedDetails>(details).ptr();
 
-        // When the previous entry index is invalid, it will be -1, which will
-        // still make the computation come out right (navigating to the 0th
-        // entry will be +1).
-        automation_->Send(new AutomationMsg_DidNavigate(
-            0, commit->type,
-            commit->previous_entry_index -
-                tab_contents_->controller()->GetLastCommittedEntryIndex()));
+        if (commit->http_status_code >= kHttpClientErrorStart && 
+            commit->http_status_code <= kHttpServerErrorEnd) {
+          automation_->Send(new AutomationMsg_NavigationFailed(
+              0, commit->http_status_code, commit->entry->url()));
+
+          ignore_next_load_notification_ = true;
+        } else {
+          // When the previous entry index is invalid, it will be -1, which
+          // will still make the computation come out right (navigating to the
+          // 0th entry will be +1).
+          automation_->Send(new AutomationMsg_DidNavigate(
+              0, commit->type,
+              commit->previous_entry_index -
+                  tab_contents_->controller()->GetLastCommittedEntryIndex()));
+        }
       }
       break;
+    case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: {
+      if (automation_) {
+        const ProvisionalLoadDetails* load_details =
+            Details<ProvisionalLoadDetails>(details).ptr();
+        automation_->Send(new AutomationMsg_NavigationFailed(
+            0, load_details->error_code(), load_details->url()));
+
+        ignore_next_load_notification_ = true;
+      }
+      break;
+    }
     default:
       NOTREACHED();
   }