OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome_frame/chrome_frame_automation.h" | 5 #include "chrome_frame/chrome_frame_automation.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/file_version_info.h" | 10 #include "base/file_version_info.h" |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 parent_window_(NULL), | 401 parent_window_(NULL), |
402 automation_server_(NULL), | 402 automation_server_(NULL), |
403 automation_server_id_(NULL), | 403 automation_server_id_(NULL), |
404 ui_thread_id_(NULL), | 404 ui_thread_id_(NULL), |
405 init_state_(UNINITIALIZED), | 405 init_state_(UNINITIALIZED), |
406 use_chrome_network_(false), | 406 use_chrome_network_(false), |
407 proxy_factory_(g_proxy_factory.get()), | 407 proxy_factory_(g_proxy_factory.get()), |
408 handle_top_level_requests_(false), | 408 handle_top_level_requests_(false), |
409 tab_handle_(-1), | 409 tab_handle_(-1), |
410 external_tab_cookie_(NULL), | 410 external_tab_cookie_(NULL), |
| 411 url_fetcher_(NULL), |
411 navigate_after_initialization_(false) { | 412 navigate_after_initialization_(false) { |
412 } | 413 } |
413 | 414 |
414 ChromeFrameAutomationClient::~ChromeFrameAutomationClient() { | 415 ChromeFrameAutomationClient::~ChromeFrameAutomationClient() { |
415 // Uninitialize must be called prior to the destructor | 416 // Uninitialize must be called prior to the destructor |
416 DCHECK(automation_server_ == NULL); | 417 DCHECK(automation_server_ == NULL); |
417 } | 418 } |
418 | 419 |
419 bool ChromeFrameAutomationClient::Initialize( | 420 bool ChromeFrameAutomationClient::Initialize( |
420 ChromeFrameDelegate* chrome_frame_delegate, | 421 ChromeFrameDelegate* chrome_frame_delegate, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 // 1) Make ReleaseAutomationServer blocking call (wait until thread exits) | 487 // 1) Make ReleaseAutomationServer blocking call (wait until thread exits) |
487 // 2) Behave like a COM object i.e. increase module lock count. | 488 // 2) Behave like a COM object i.e. increase module lock count. |
488 // Otherwise the DLL may get unloaded while we have running threads. | 489 // Otherwise the DLL may get unloaded while we have running threads. |
489 // Unfortunately in NPAPI case we cannot increase module lock count, hence | 490 // Unfortunately in NPAPI case we cannot increase module lock count, hence |
490 // we stick with blocking/waiting | 491 // we stick with blocking/waiting |
491 if (tab_.get()) { | 492 if (tab_.get()) { |
492 tab_->RemoveObserver(this); | 493 tab_->RemoveObserver(this); |
493 tab_ = NULL; // scoped_refptr::Release | 494 tab_ = NULL; // scoped_refptr::Release |
494 } | 495 } |
495 | 496 |
496 // Clean up any outstanding requests | 497 if (url_fetcher_) { |
497 CleanupRequests(); | 498 // Clean up any outstanding requests |
| 499 url_fetcher_->StopAllRequests(); |
| 500 } |
498 | 501 |
499 // Wait for the background thread to exit. | 502 // Wait for the background thread to exit. |
500 ReleaseAutomationServer(); | 503 ReleaseAutomationServer(); |
501 | 504 |
502 // We must destroy the window, since if there are pending tasks | 505 // We must destroy the window, since if there are pending tasks |
503 // window procedure may be invoked after DLL is unloaded. | 506 // window procedure may be invoked after DLL is unloaded. |
504 // Unfortunately pending tasks are leaked. | 507 // Unfortunately pending tasks are leaked. |
505 if (m_hWnd) | 508 if (m_hWnd) |
506 DestroyWindow(); | 509 DestroyWindow(); |
507 | 510 |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
843 chrome_frame_delegate_->OnAutomationServerLaunchFailed(result, version); | 846 chrome_frame_delegate_->OnAutomationServerLaunchFailed(result, version); |
844 } | 847 } |
845 } | 848 } |
846 } | 849 } |
847 | 850 |
848 // This is invoked in channel's background thread. | 851 // This is invoked in channel's background thread. |
849 // Cannot call any method of the activex/npapi here since they are STA | 852 // Cannot call any method of the activex/npapi here since they are STA |
850 // kind of beings. | 853 // kind of beings. |
851 // By default we marshal the IPC message to the main/GUI thread and from there | 854 // By default we marshal the IPC message to the main/GUI thread and from there |
852 // we safely invoke chrome_frame_delegate_->OnMessageReceived(msg). | 855 // we safely invoke chrome_frame_delegate_->OnMessageReceived(msg). |
| 856 |
| 857 |
| 858 bool ChromeFrameAutomationClient::ProcessUrlRequestMessage(TabProxy* tab, |
| 859 const IPC::Message& msg, bool ui_thread) { |
| 860 // Either directly call appropriate url_fetcher function |
| 861 // or postpone call to the UI thread. |
| 862 bool invoke = ui_thread || thread_safe_url_fetcher_; |
| 863 uint16 msg_type = msg.type(); |
| 864 switch (msg_type) { |
| 865 default: |
| 866 return false; |
| 867 |
| 868 case AutomationMsg_RequestStart::ID: |
| 869 if (invoke) |
| 870 AutomationMsg_RequestStart::Dispatch(&msg, url_fetcher_, |
| 871 &PluginUrlRequestManager::StartUrlRequest); |
| 872 break; |
| 873 |
| 874 case AutomationMsg_RequestRead::ID: |
| 875 if (invoke) |
| 876 AutomationMsg_RequestRead::Dispatch(&msg, url_fetcher_, |
| 877 &PluginUrlRequestManager::ReadUrlRequest); |
| 878 break; |
| 879 |
| 880 case AutomationMsg_RequestEnd::ID: |
| 881 if (invoke) |
| 882 AutomationMsg_RequestEnd::Dispatch(&msg, url_fetcher_, |
| 883 &PluginUrlRequestManager::EndUrlRequest); |
| 884 break; |
| 885 } |
| 886 |
| 887 if (!invoke) { |
| 888 PostTask(FROM_HERE, NewRunnableMethod(this, |
| 889 &ChromeFrameAutomationClient::ProcessUrlRequestMessage, |
| 890 tab, msg, true)); |
| 891 } |
| 892 |
| 893 return true; |
| 894 } |
| 895 |
853 void ChromeFrameAutomationClient::OnMessageReceived(TabProxy* tab, | 896 void ChromeFrameAutomationClient::OnMessageReceived(TabProxy* tab, |
854 const IPC::Message& msg) { | 897 const IPC::Message& msg) { |
855 DCHECK(tab == tab_.get()); | 898 DCHECK(tab == tab_.get()); |
856 | 899 |
| 900 // Quickly process network related messages. |
| 901 if (url_fetcher_ && ProcessUrlRequestMessage(tab, msg, false)) |
| 902 return; |
| 903 |
857 // Early check to avoid needless marshaling | 904 // Early check to avoid needless marshaling |
858 if (chrome_frame_delegate_ == NULL) | 905 if (chrome_frame_delegate_ == NULL) |
859 return; | 906 return; |
860 | 907 |
861 CallDelegate(FROM_HERE, NewRunnableMethod(chrome_frame_delegate_, | 908 CallDelegate(FROM_HERE, NewRunnableMethod(chrome_frame_delegate_, |
862 &ChromeFrameDelegate::OnMessageReceived, msg)); | 909 &ChromeFrameDelegate::OnMessageReceived, msg)); |
863 } | 910 } |
864 | 911 |
865 void ChromeFrameAutomationClient::ReportNavigationError( | 912 void ChromeFrameAutomationClient::ReportNavigationError( |
866 AutomationMsg_NavigationResponseValues error_code, | 913 AutomationMsg_NavigationResponseValues error_code, |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 window_dc, print_bounds.left, print_bounds.top, | 1038 window_dc, print_bounds.left, print_bounds.top, |
992 SRCCOPY); | 1039 SRCCOPY); |
993 | 1040 |
994 ::ReleaseDC(tab_window_, window_dc); | 1041 ::ReleaseDC(tab_window_, window_dc); |
995 } | 1042 } |
996 | 1043 |
997 void ChromeFrameAutomationClient::PrintTab() { | 1044 void ChromeFrameAutomationClient::PrintTab() { |
998 tab_->PrintAsync(); | 1045 tab_->PrintAsync(); |
999 } | 1046 } |
1000 | 1047 |
1001 // IPC:Message::Sender implementation | |
1002 bool ChromeFrameAutomationClient::Send(IPC::Message* msg) { | |
1003 if (automation_server_) { | |
1004 return automation_server_->Send(msg); | |
1005 } | |
1006 return false; | |
1007 } | |
1008 | |
1009 bool ChromeFrameAutomationClient::AddRequest(PluginUrlRequest* request) { | |
1010 DCHECK_EQ(PlatformThread::CurrentId(), ui_thread_id_); | |
1011 | |
1012 if (!request) { | |
1013 NOTREACHED(); | |
1014 return false; | |
1015 } | |
1016 | |
1017 #ifndef NDEBUG | |
1018 RequestMap::const_iterator it = request_map_.find(request->id()); | |
1019 scoped_refptr<PluginUrlRequest> other(request_map_.end() == it ? | |
1020 NULL : (*it).second); | |
1021 DCHECK(other.get() == NULL); | |
1022 #endif | |
1023 request_map_[request->id()] = request; | |
1024 return true; | |
1025 } | |
1026 | |
1027 bool ChromeFrameAutomationClient::ReadRequest( | |
1028 int request_id, int bytes_to_read) { | |
1029 bool result = false; | |
1030 PluginUrlRequest* request = LookupRequest(request_id); | |
1031 if (request) | |
1032 result = request->Read(bytes_to_read); | |
1033 | |
1034 return result; | |
1035 } | |
1036 | |
1037 void ChromeFrameAutomationClient::RemoveRequest(PluginUrlRequest* request) { | |
1038 DCHECK_EQ(PlatformThread::CurrentId(), ui_thread_id_); | |
1039 | |
1040 // We check if the request pointer passed in is actually present in the map | |
1041 // before going ahead and deleting it. This avoids the issue where we would | |
1042 // incorrectly delete a different request with the same request id. | |
1043 if (IsValidRequest(request)) { | |
1044 request_map_.erase(request->id()); | |
1045 } | |
1046 } | |
1047 | |
1048 void ChromeFrameAutomationClient::RemoveRequest(int request_id, bool abort) { | |
1049 DCHECK_EQ(PlatformThread::CurrentId(), ui_thread_id_); | |
1050 PluginUrlRequest* request = LookupRequest(request_id); | |
1051 if (request) { | |
1052 if (abort) { | |
1053 // The request object will get removed asynchronously. | |
1054 request->Stop(); | |
1055 } else { | |
1056 request_map_.erase(request_id); | |
1057 } | |
1058 } | |
1059 } | |
1060 | |
1061 PluginUrlRequest* ChromeFrameAutomationClient::LookupRequest( | |
1062 int request_id) const { | |
1063 DCHECK_EQ(PlatformThread::CurrentId(), ui_thread_id_); | |
1064 PluginUrlRequest* request = NULL; | |
1065 RequestMap::const_iterator it = request_map_.find(request_id); | |
1066 if (request_map_.end() != it) | |
1067 request = (*it).second; | |
1068 return request; | |
1069 } | |
1070 | |
1071 bool ChromeFrameAutomationClient::IsValidRequest( | |
1072 PluginUrlRequest* request) const { | |
1073 DCHECK_EQ(PlatformThread::CurrentId(), ui_thread_id_); | |
1074 bool is_valid = false; | |
1075 // if request is invalid then request->id() won't work | |
1076 // hence perform reverse map lookup for validity of the | |
1077 // request pointer. | |
1078 if (request) { | |
1079 for (RequestMap::const_iterator it = request_map_.begin(); | |
1080 it != request_map_.end(); it++) { | |
1081 if (request == (*it).second) { | |
1082 is_valid = true; | |
1083 break; | |
1084 } | |
1085 } | |
1086 } | |
1087 | |
1088 return is_valid; | |
1089 } | |
1090 | |
1091 void ChromeFrameAutomationClient::CleanupRequests() { | |
1092 DCHECK_EQ(PlatformThread::CurrentId(), ui_thread_id_); | |
1093 | |
1094 std::vector<scoped_refptr<PluginUrlRequest> > request_list; | |
1095 // We copy the pending requests into a temporary vector as the Stop | |
1096 // function in the request could also try to delete the request from | |
1097 // the request map and the iterator could end up being invalid. | |
1098 RequestMap::iterator index = request_map_.begin(); | |
1099 while (index != request_map_.end()) { | |
1100 PluginUrlRequest* request = (*index).second; | |
1101 DCHECK(request != NULL); | |
1102 request_list.push_back(request); | |
1103 index++; | |
1104 } | |
1105 request_map_.clear(); | |
1106 | |
1107 for (unsigned int index = 0; index < request_list.size(); ++index) { | |
1108 request_list[index]->Stop(); | |
1109 } | |
1110 } | |
1111 | |
1112 bool ChromeFrameAutomationClient::Reinitialize( | 1048 bool ChromeFrameAutomationClient::Reinitialize( |
1113 ChromeFrameDelegate* delegate) { | 1049 ChromeFrameDelegate* delegate, |
| 1050 PluginUrlRequestManager* url_fetcher) { |
1114 if (!tab_.get() || !::IsWindow(chrome_window_)) { | 1051 if (!tab_.get() || !::IsWindow(chrome_window_)) { |
1115 NOTREACHED(); | 1052 NOTREACHED(); |
1116 DLOG(WARNING) << "ChromeFrameAutomationClient instance reused " | 1053 DLOG(WARNING) << "ChromeFrameAutomationClient instance reused " |
1117 << "with invalid tab"; | 1054 << "with invalid tab"; |
1118 return false; | 1055 return false; |
1119 } | 1056 } |
1120 | 1057 |
1121 if (!delegate) { | 1058 if (!delegate) { |
1122 NOTREACHED(); | 1059 NOTREACHED(); |
1123 return false; | 1060 return false; |
1124 } | 1061 } |
1125 | 1062 |
1126 CleanupRequests(); | 1063 url_fetcher_->StopAllRequests(); |
1127 chrome_frame_delegate_ = delegate; | 1064 chrome_frame_delegate_ = delegate; |
| 1065 SetUrlFetcher(url_fetcher); |
1128 SetParentWindow(NULL); | 1066 SetParentWindow(NULL); |
1129 return true; | 1067 return true; |
1130 } | 1068 } |
1131 | 1069 |
1132 void ChromeFrameAutomationClient::AttachExternalTab( | 1070 void ChromeFrameAutomationClient::AttachExternalTab( |
1133 intptr_t external_tab_cookie) { | 1071 intptr_t external_tab_cookie) { |
1134 DCHECK_EQ(static_cast<TabProxy*>(NULL), tab_.get()); | 1072 DCHECK_EQ(static_cast<TabProxy*>(NULL), tab_.get()); |
1135 DCHECK_EQ(-1, tab_handle_); | 1073 DCHECK_EQ(-1, tab_handle_); |
1136 | 1074 |
1137 external_tab_cookie_ = external_tab_cookie; | 1075 external_tab_cookie_ = external_tab_cookie; |
1138 } | 1076 } |
1139 | 1077 |
1140 void ChromeFrameAutomationClient::SetPageFontSize( | 1078 void ChromeFrameAutomationClient::SetPageFontSize( |
1141 enum AutomationPageFontSize font_size) { | 1079 enum AutomationPageFontSize font_size) { |
1142 if (font_size < SMALLEST_FONT || | 1080 if (font_size < SMALLEST_FONT || |
1143 font_size > LARGEST_FONT) { | 1081 font_size > LARGEST_FONT) { |
1144 NOTREACHED() << "Invalid font size specified : " | 1082 NOTREACHED() << "Invalid font size specified : " |
1145 << font_size; | 1083 << font_size; |
1146 return; | 1084 return; |
1147 } | 1085 } |
1148 | 1086 |
1149 Send(new AutomationMsg_SetPageFontSize(0, tab_handle_, font_size)); | 1087 automation_server_->Send( |
| 1088 new AutomationMsg_SetPageFontSize(0, tab_handle_, font_size)); |
1150 } | 1089 } |
1151 | 1090 |
| 1091 |
| 1092 ////////////////////////////////////////////////////////////////////////// |
| 1093 // PluginUrlRequestDelegate implementation. |
| 1094 // Forward network related responses to Chrome. |
| 1095 |
| 1096 void ChromeFrameAutomationClient::OnResponseStarted(int request_id, |
| 1097 const char* mime_type, const char* headers, int size, |
| 1098 base::Time last_modified, const std::string& peristent_cookies, |
| 1099 const std::string& redirect_url, int redirect_status) { |
| 1100 const IPC::AutomationURLResponse response = { |
| 1101 mime_type, |
| 1102 headers ? headers : "", |
| 1103 size, |
| 1104 last_modified, |
| 1105 peristent_cookies, |
| 1106 redirect_url, |
| 1107 redirect_status |
| 1108 }; |
| 1109 |
| 1110 automation_server_->Send(new AutomationMsg_RequestStarted(0, |
| 1111 tab_->handle(), request_id, response)); |
| 1112 } |
| 1113 |
| 1114 void ChromeFrameAutomationClient::OnReadComplete(int request_id, |
| 1115 const void* buffer, int len) { |
| 1116 std::string data(reinterpret_cast<const char*>(buffer), len); |
| 1117 automation_server_->Send(new AutomationMsg_RequestData(0, tab_->handle(), |
| 1118 request_id, data)); |
| 1119 } |
| 1120 |
| 1121 void ChromeFrameAutomationClient::OnResponseEnd(int request_id, |
| 1122 const URLRequestStatus& status) { |
| 1123 automation_server_->Send(new AutomationMsg_RequestEnd(0, tab_->handle(), |
| 1124 request_id, status)); |
| 1125 } |
| 1126 |
OLD | NEW |