diff options
Diffstat (limited to 'chrome')
71 files changed, 7732 insertions, 223 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc index 3d43dbb..1cff5ee 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -21,9 +21,9 @@ #include "chrome/browser/controller.h" #include "chrome/browser/drag_utils.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/url_fixer_upper.h" #include "chrome/browser/user_metrics.h" #include "chrome/browser/views/location_bar_view.h" diff --git a/chrome/browser/autocomplete/autocomplete_popup.cc b/chrome/browser/autocomplete/autocomplete_popup.cc index d2437a3..23535c3 100644 --- a/chrome/browser/autocomplete/autocomplete_popup.cc +++ b/chrome/browser/autocomplete/autocomplete_popup.cc @@ -13,8 +13,8 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/net/dns_global.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/views/location_bar_view.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/l10n_util.h" diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc index defb656..9f0eb3e 100644 --- a/chrome/browser/autocomplete/keyword_provider.cc +++ b/chrome/browser/autocomplete/keyword_provider.cc @@ -8,8 +8,8 @@ #include "base/string_util.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/common/l10n_util.h" #include "net/base/escape.h" #include "net/base/net_util.h" diff --git a/chrome/browser/autocomplete/keyword_provider_unittest.cc b/chrome/browser/autocomplete/keyword_provider_unittest.cc index a650701..e82e8d6 100644 --- a/chrome/browser/autocomplete/keyword_provider_unittest.cc +++ b/chrome/browser/autocomplete/keyword_provider_unittest.cc @@ -4,8 +4,8 @@ #include "base/message_loop.h" #include "chrome/browser/autocomplete/keyword_provider.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc index d302b30..cd25d13 100644 --- a/chrome/browser/autocomplete/search_provider.cc +++ b/chrome/browser/autocomplete/search_provider.cc @@ -9,7 +9,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/google_util.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/url_fixer_upper.h" #include "chrome/common/json_value_serializer.h" #include "chrome/common/l10n_util.h" diff --git a/chrome/browser/autocomplete/search_provider.h b/chrome/browser/autocomplete/search_provider.h index 687ea07..8fe402f 100644 --- a/chrome/browser/autocomplete/search_provider.h +++ b/chrome/browser/autocomplete/search_provider.h @@ -17,7 +17,7 @@ #include "chrome/browser/autocomplete/autocomplete.h" #include "chrome/browser/history/history.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/browser/url_fetcher.h" class Profile; diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index 0eb3d4b..e937d99 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -115,15 +115,15 @@ if not env.Bit('mac'): 'safe_browsing/safe_browsing_database_bloom.cc', 'safe_browsing/safe_browsing_database_impl.cc', 'safe_browsing/safe_browsing_util.cc', - 'search_engines/template_url.cc', - 'search_engines/template_url_model.cc', - 'search_engines/template_url_parser.cc', 'session_startup_pref.cc', 'sessions/session_command.cc', 'sessions/session_id.cc', 'spellcheck_worditerator.cc', 'spellchecker.cc', 'ssl_error_info.cc', + 'template_url.cc', + 'template_url_model.cc', + 'template_url_parser.cc', 'url_fetcher.cc', 'url_fetcher_protect.cc', 'user_metrics.cc', @@ -259,8 +259,6 @@ if env.Bit('windows'): 'safe_browsing/safe_browsing_blocking_page.cc', 'safe_browsing/safe_browsing_service.cc', 'sandbox_policy.cc', - 'search_engines/template_url_fetcher.cc', - 'search_engines/template_url_prepopulate_data.cc', 'sessions/base_session_service.cc', 'sessions/session_backend.cc', 'sessions/session_restore.cc', @@ -293,6 +291,8 @@ if env.Bit('windows'): 'tabs/tab_strip_model_order_controller.cc', 'task_manager.cc', 'task_manager_resource_providers.cc', + 'template_url_fetcher.cc', + 'template_url_prepopulate_data.cc', 'toolbar_model.cc', 'url_fixer_upper.cc', 'user_data_manager.cc', diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index cd93d66..0fca784 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -602,6 +602,46 @@ > </File> <File + RelativePath=".\template_url.cc" + > + </File> + <File + RelativePath=".\template_url.h" + > + </File> + <File + RelativePath=".\template_url_fetcher.cc" + > + </File> + <File + RelativePath=".\template_url_fetcher.h" + > + </File> + <File + RelativePath=".\template_url_model.cc" + > + </File> + <File + RelativePath=".\template_url_model.h" + > + </File> + <File + RelativePath=".\template_url_parser.cc" + > + </File> + <File + RelativePath=".\template_url_parser.h" + > + </File> + <File + RelativePath=".\template_url_prepopulate_data.cc" + > + </File> + <File + RelativePath=".\template_url_prepopulate_data.h" + > + </File> + <File RelativePath=".\url_fetcher.cc" > </File> @@ -2510,140 +2550,6 @@ > </File> </Filter> - <Filter - Name="Search Engines" - > - <File - RelativePath=".\search_engines\template_url.cc" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - </File> - <File - RelativePath=".\search_engines\template_url.h" - > - </File> - <File - RelativePath=".\search_engines\template_url_fetcher.cc" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - </File> - <File - RelativePath=".\search_engines\template_url_fetcher.h" - > - </File> - <File - RelativePath=".\search_engines\template_url_model.cc" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - </File> - <File - RelativePath=".\search_engines\template_url_model.h" - > - </File> - <File - RelativePath=".\search_engines\template_url_parser.cc" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - </File> - <File - RelativePath=".\search_engines\template_url_parser.h" - > - </File> - <File - RelativePath=".\search_engines\template_url_prepopulate_data.cc" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - ObjectFile="$(IntDir)\$(InputName)1.obj" - XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" - /> - </FileConfiguration> - </File> - <File - RelativePath=".\search_engines\template_url_prepopulate_data.h" - > - </File> - </Filter> <File RelativePath=".\browser_trial.cc" > diff --git a/chrome/browser/browser_prefs.cc b/chrome/browser/browser_prefs.cc index 4f83bac..abbf875 100644 --- a/chrome/browser/browser_prefs.cc +++ b/chrome/browser/browser_prefs.cc @@ -19,7 +19,7 @@ #include "chrome/browser/ssl_manager.h" #include "chrome/browser/tabs/tab_strip_model.h" #include "chrome/browser/task_manager.h" -#include "chrome/browser/search_engines/template_url_prepopulate_data.h" +#include "chrome/browser/template_url_prepopulate_data.h" #include "chrome/browser/views/bookmark_bar_view.h" #include "chrome/browser/views/bookmark_manager_view.h" #include "chrome/browser/views/bookmark_table_view.h" diff --git a/chrome/browser/browsing_data_remover.cc b/chrome/browser/browsing_data_remover.cc index e9140b2..86f8e98 100644 --- a/chrome/browser/browsing_data_remover.cc +++ b/chrome/browser/browsing_data_remover.cc @@ -8,9 +8,9 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/tab_restore_service.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/user_metrics.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index 7bb7d9f..9b7107a 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -18,7 +18,7 @@ #include "chrome/browser/render_view_host.h" #include "chrome/browser/sessions/session_types.h" #include "chrome/browser/tab_contents/navigation_entry.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/browser/user_data_manager.h" #include "chrome/browser/user_metrics.h" #include "chrome/browser/views/keyword_editor_view.h" diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h index a8391e8..8f700b2 100644 --- a/chrome/browser/dom_ui/new_tab_ui.h +++ b/chrome/browser/dom_ui/new_tab_ui.h @@ -9,8 +9,8 @@ #include "chrome/browser/dom_ui/dom_ui_host.h" #include "chrome/browser/dom_ui/chrome_url_data_manager.h" #include "chrome/browser/history/history.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/sessions/tab_restore_service.h" +#include "chrome/browser/template_url_model.h" class GURL; class Profile; diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h index 0e5a492..dcd5518 100644 --- a/chrome/browser/history/history.h +++ b/chrome/browser/history/history.h @@ -20,7 +20,7 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/history/history_notifications.h" #include "chrome/browser/history/history_types.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/common/notification_service.h" #include "chrome/common/page_transition_types.h" #include "chrome/common/ref_counted_util.h" diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h index 20aeb78..745c7e3 100644 --- a/chrome/browser/history/url_database.h +++ b/chrome/browser/history/url_database.h @@ -7,7 +7,7 @@ #include "base/basictypes.h" #include "chrome/browser/history/history_types.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" // Temporary until DBCloseScoper moves elsewhere. #include "chrome/common/sqlite_compiled_statement.h" diff --git a/chrome/browser/importer/firefox2_importer.cc b/chrome/browser/importer/firefox2_importer.cc index b2f61c1..bbc4e6f 100644 --- a/chrome/browser/importer/firefox2_importer.cc +++ b/chrome/browser/importer/firefox2_importer.cc @@ -11,8 +11,8 @@ #include "base/values.h" #include "chrome/browser/importer/firefox_importer_utils.h" #include "chrome/browser/importer/mork_reader.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_parser.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_parser.h" #include "chrome/common/l10n_util.h" #include "chrome/common/time_format.h" #include "generated_resources.h" diff --git a/chrome/browser/importer/firefox_importer_utils.cc b/chrome/browser/importer/firefox_importer_utils.cc index 023fcf9..719ebcc 100644 --- a/chrome/browser/importer/firefox_importer_utils.cc +++ b/chrome/browser/importer/firefox_importer_utils.cc @@ -13,9 +13,9 @@ #include "base/string_util.h" #include "base/sys_string_conversions.h" #include "base/time.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" -#include "chrome/browser/search_engines/template_url_parser.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" +#include "chrome/browser/template_url_parser.h" #include "chrome/common/win_util.h" #include "googleurl/src/gurl.h" #include "net/base/base64.h" diff --git a/chrome/browser/importer/ie_importer.cc b/chrome/browser/importer/ie_importer.cc index d362739..55bed64 100644 --- a/chrome/browser/importer/ie_importer.cc +++ b/chrome/browser/importer/ie_importer.cc @@ -19,7 +19,7 @@ #include "base/win_util.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/password_manager/ie7_password.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/common/l10n_util.h" #include "chrome/common/time_format.h" #include "chrome/common/win_util.h" diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc index 52a035d..dcc1438 100644 --- a/chrome/browser/importer/importer.cc +++ b/chrome/browser/importer/importer.cc @@ -21,7 +21,7 @@ #include "chrome/browser/importer/firefox_profile_lock.h" #include "chrome/browser/importer/ie_importer.h" #include "chrome/browser/importer/toolbar_importer.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/shell_integration.h" #include "chrome/browser/views/importer_lock_view.h" #include "chrome/browser/webdata/web_data_service.h" diff --git a/chrome/browser/importer/importer.h b/chrome/browser/importer/importer.h index e169eb7..df13150 100644 --- a/chrome/browser/importer/importer.h +++ b/chrome/browser/importer/importer.h @@ -19,7 +19,7 @@ #include "chrome/browser/password_manager/ie7_password.h" #endif #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/common/notification_service.h" #include "googleurl/src/gurl.h" #include "webkit/glue/password_form.h" diff --git a/chrome/browser/metrics_service.cc b/chrome/browser/metrics_service.cc index bb2ba62..7909a0b 100644 --- a/chrome/browser/metrics_service.cc +++ b/chrome/browser/metrics_service.cc @@ -173,8 +173,8 @@ #include "chrome/browser/plugin_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/render_process_host.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/libxml_utils.h" #include "chrome/common/pref_names.h" diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 7d3a947..a849bf1 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -23,12 +23,12 @@ #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/profile_manager.h" #include "chrome/browser/render_process_host.h" -#include "chrome/browser/search_engines/template_url_fetcher.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/tab_restore_service.h" #include "chrome/browser/spellchecker.h" #include "chrome/browser/tab_contents/navigation_controller.h" +#include "chrome/browser/template_url_fetcher.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/visitedlink_master.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/chrome_constants.h" diff --git a/chrome/browser/render_view_context_menu.cc b/chrome/browser/render_view_context_menu.cc index 311ba27..83082b4 100644 --- a/chrome/browser/render_view_context_menu.cc +++ b/chrome/browser/render_view_context_menu.cc @@ -8,8 +8,8 @@ #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/spellchecker.h" +#include "chrome/browser/template_url_model.h" #include "chrome/common/l10n_util.h" #include "webkit/glue/context_node_types.h" diff --git a/chrome/browser/render_view_context_menu_controller.cc b/chrome/browser/render_view_context_menu_controller.cc index bdb34e7..7a75577 100644 --- a/chrome/browser/render_view_context_menu_controller.cc +++ b/chrome/browser/render_view_context_menu_controller.cc @@ -18,7 +18,7 @@ #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/save_package.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/views/page_info_window.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/navigation_entry.h" diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc index 6434fb1..d65f180 100644 --- a/chrome/browser/rlz/rlz.cc +++ b/chrome/browser/rlz/rlz.cc @@ -19,7 +19,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/profile.h" #include "chrome/browser/profile_manager.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/env_vars.h" #include "chrome/common/notification_service.h" diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url.h +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_fetcher.cc b/chrome/browser/search_engines/template_url_fetcher.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_fetcher.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_fetcher.h b/chrome/browser/search_engines/template_url_fetcher.h deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_fetcher.h +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_model.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_model.h b/chrome/browser/search_engines/template_url_model.h deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_model.h +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_model_unittest.cc b/chrome/browser/search_engines/template_url_model_unittest.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_model_unittest.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_parser.cc b/chrome/browser/search_engines/template_url_parser.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_parser.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_parser.h b/chrome/browser/search_engines/template_url_parser.h deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_parser.h +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_parser_unittest.cc b/chrome/browser/search_engines/template_url_parser_unittest.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_parser_unittest.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_prepopulate_data.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.h b/chrome/browser/search_engines/template_url_prepopulate_data.h deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_prepopulate_data.h +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc +++ /dev/null diff --git a/chrome/browser/search_engines/template_url_unittest.cc b/chrome/browser/search_engines/template_url_unittest.cc deleted file mode 100644 index e69de29..0000000 --- a/chrome/browser/search_engines/template_url_unittest.cc +++ /dev/null diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc index 6c6ec47..77faa55 100644 --- a/chrome/browser/tab_contents/web_contents.cc +++ b/chrome/browser/tab_contents/web_contents.cc @@ -30,11 +30,11 @@ #include "chrome/browser/printing/print_job.h" #include "chrome/browser/render_view_host.h" #include "chrome/browser/render_widget_host_view_win.h" // TODO(brettw) delete me. -#include "chrome/browser/search_engines/template_url_fetcher.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/web_contents_view.h" #include "chrome/browser/tab_contents/web_contents_view_win.h" +#include "chrome/browser/template_url_fetcher.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/views/hung_renderer_view.h" // TODO(brettw) delete me. #include "chrome/common/chrome_switches.h" #include "chrome/common/l10n_util.h" diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc index 3b0c4bb..2e42a64 100644 --- a/chrome/browser/tabs/tab_strip_model.cc +++ b/chrome/browser/tabs/tab_strip_model.cc @@ -533,7 +533,7 @@ bool TabStripModel::InternalCloseTabContentsAt(int index, // them. Once they have fired, we'll get a message back saying whether // to proceed closing the page or not, which sends us back to this method // with the HasUnloadListener bit cleared. - WebContents* web_contents = detached_contents->AsWebContents(); + WebContents* web_contents = GetContentsAt(index)->AsWebContents(); // If we hit this code path, the tab had better be a WebContents tab. DCHECK(web_contents); web_contents->render_view_host()->FirePageBeforeUnload(); diff --git a/chrome/browser/template_url.cc b/chrome/browser/template_url.cc new file mode 100644 index 0000000..844ec54 --- /dev/null +++ b/chrome/browser/template_url.cc @@ -0,0 +1,558 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/template_url.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/rlz/rlz.h" +#include "chrome/browser/google_url_tracker.h" +#include "chrome/browser/template_url_model.h" +#include "chrome/common/gfx/favicon_size.h" +#include "chrome/common/l10n_util.h" +#include "net/base/escape.h" + +// The TemplateURLRef has any number of terms that need to be replaced. Each of +// the terms is enclosed in braces. If the character preceeding the final +// brace is a ?, it indicates the term is optional and can be replaced with +// an empty string. +static const wchar_t kStartParameter = '{'; +static const wchar_t kEndParameter = '}'; +static const wchar_t kOptional = '?'; + +// Known parameters found in the URL. +static const wchar_t kSearchTermsParameter[] = L"searchTerms"; +static const wchar_t kSearchTermsParameterFull[] = L"{searchTerms}"; +static const wchar_t kCountParameter[] = L"count"; +static const wchar_t kStartIndexParameter[] = L"startIndex"; +static const wchar_t kStartPageParameter[] = L"startPage"; +static const wchar_t kLanguageParameter[] = L"language"; +static const wchar_t kInputEncodingParameter[] = L"inputEncoding"; +static const wchar_t kOutputEncodingParameter[] = L"outputEncoding"; + +static const wchar_t kGoogleAcceptedSuggestionParameter[] = + L"google:acceptedSuggestion"; +// Host/Domain Google searches are relative to. +static const wchar_t kGoogleBaseURLParameter[] = L"google:baseURL"; +static const wchar_t kGoogleBaseURLParameterFull[] = L"{google:baseURL}"; +// Like google:baseURL, but for the Search Suggest capability. +static const wchar_t kGoogleBaseSuggestURLParameter[] = + L"google:baseSuggestURL"; +static const wchar_t kGoogleBaseSuggestURLParameterFull[] = + L"{google:baseSuggestURL}"; +static const wchar_t kGoogleOriginalQueryForSuggestionParameter[] = + L"google:originalQueryForSuggestion"; +static const wchar_t kGoogleRLZParameter[] = L"google:RLZ"; +// Same as kSearchTermsParameter, with no escaping. +static const wchar_t kGoogleUnescapedSearchTermsParameter[] = + L"google:unescapedSearchTerms"; +static const wchar_t kGoogleUnescapedSearchTermsParameterFull[] = + L"{google:unescapedSearchTerms}"; + +// Display value for kSearchTermsParameter. +static const wchar_t kDisplaySearchTerms[] = L"%s"; + +// Display value for kGoogleUnescapedSearchTermsParameter. +static const wchar_t kDisplayUnescapedSearchTerms[] = L"%S"; + +// Used if the count parameter is not optional. Indicates we want 10 search +// results. +static const wchar_t kDefaultCount[] = L"10"; + +// Used if the parameter kOutputEncodingParameter is required. +static const wchar_t kOutputEncodingType[] = L"UTF-8"; + +// static +std::wstring* TemplateURLRef::google_base_url_ = NULL; + +TemplateURLRef::TemplateURLRef() { + Set(std::wstring(), 0, 0); +} + +void TemplateURLRef::Set(const std::wstring& url, + int index_offset, + int page_offset) { + url_ = url; + index_offset_ = index_offset; + page_offset_ = page_offset; + InvalidateCachedValues(); +} + +bool TemplateURLRef::ParseParameter(size_t start, + size_t end, + std::wstring* url, + Replacements* replacements) const { + DCHECK(start != std::string::npos && + end != std::string::npos && end > start); + size_t length = end - start - 1; + bool optional = false; + if ((*url)[end - 1] == kOptional) { + optional = true; + length--; + } + std::wstring parameter(url->substr(start + 1, length)); + // Remove the parameter from the string. + url->erase(start, end - start + 1); + if (parameter == kSearchTermsParameter) { + replacements->push_back(Replacement(SEARCH_TERMS, static_cast<int>(start))); + } else if (parameter == kCountParameter) { + if (!optional) + url->insert(start, kDefaultCount); + } else if (parameter == kStartIndexParameter) { + if (!optional) { + url->insert(start, IntToWString(index_offset_)); + } + } else if (parameter == kStartPageParameter) { + if (!optional) { + url->insert(start, IntToWString(page_offset_)); + } + } else if (parameter == kLanguageParameter) { + replacements->push_back(Replacement(LANGUAGE, static_cast<int>(start))); + } else if (parameter == kInputEncodingParameter) { + replacements->push_back(Replacement(ENCODING, static_cast<int>(start))); + } else if (parameter == kOutputEncodingParameter) { + if (!optional) + url->insert(start, kOutputEncodingType); + } else if (parameter == kGoogleAcceptedSuggestionParameter) { + replacements->push_back(Replacement(GOOGLE_ACCEPTED_SUGGESTION, + static_cast<int>(start))); + } else if (parameter == kGoogleBaseURLParameter) { + replacements->push_back(Replacement(GOOGLE_BASE_URL, + static_cast<int>(start))); + } else if (parameter == kGoogleBaseSuggestURLParameter) { + replacements->push_back(Replacement(GOOGLE_BASE_SUGGEST_URL, + static_cast<int>(start))); + } else if (parameter == kGoogleOriginalQueryForSuggestionParameter) { + replacements->push_back(Replacement(GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION, + static_cast<int>(start))); + } else if (parameter == kGoogleRLZParameter) { + replacements->push_back(Replacement(GOOGLE_RLZ, static_cast<int>(start))); + } else if (parameter == kGoogleUnescapedSearchTermsParameter) { + replacements->push_back(Replacement(GOOGLE_UNESCAPED_SEARCH_TERMS, + static_cast<int>(start))); + } else if (!optional) { + // Unknown required parameter. No idea what to replace this with, + // so fail. + return false; + } + return true; +} + +std::wstring TemplateURLRef::ParseURL(const std::wstring& url, + Replacements* replacements, + bool* valid) const { + *valid = false; + std::wstring parsed_url = url; + for (size_t last = 0; last != std::string::npos; ) { + last = parsed_url.find(kStartParameter, last); + if (last != std::string::npos) { + size_t endTemplate = parsed_url.find(kEndParameter, last); + if (endTemplate != std::string::npos) { + if (!ParseParameter(last, endTemplate, &parsed_url, replacements)) { + // Not a valid parameter, return. + return std::wstring(); + } + // ParseParamter erases from the string, as such we don't need + // to update last. + } else { + // Open brace without a closing brace, return. + return std::wstring(); + } + } + } + *valid = true; + return parsed_url; +} + +void TemplateURLRef::ParseIfNecessary() const { + if (!parsed_) { + parsed_ = true; + parsed_url_ = ParseURL(url_, &replacements_, &valid_); + supports_replacements_ = false; + if (valid_) { + bool has_only_one_search_term = false; + for (Replacements::const_iterator i = replacements_.begin(); + i != replacements_.end(); ++i) { + if ((i->type == SEARCH_TERMS) || + (i->type == GOOGLE_UNESCAPED_SEARCH_TERMS)) { + if (has_only_one_search_term) { + has_only_one_search_term = false; + break; + } + has_only_one_search_term = true; + supports_replacements_ = true; + } + } + // Only parse the host/key if there is one search term. Technically there + // could be more than one term, but it's uncommon; so we punt. + if (has_only_one_search_term) + ParseHostAndSearchTermKey(); + } + } +} + +void TemplateURLRef::ParseHostAndSearchTermKey() const { + std::wstring url_string = url_; + ReplaceSubstringsAfterOffset(&url_string, 0, kGoogleBaseURLParameterFull, + GoogleBaseURLValue()); + ReplaceSubstringsAfterOffset(&url_string, 0, + kGoogleBaseSuggestURLParameterFull, + GoogleBaseSuggestURLValue()); + + GURL url(WideToUTF8(url_string)); + if (!url.is_valid()) + return; + + std::string query_string = url.query(); + if (query_string.empty()) + return; + + url_parse::Component query, key, value; + query.len = static_cast<int>(query_string.size()); + while (url_parse::ExtractQueryKeyValue(query_string.c_str(), &query, &key, + &value)) { + if (key.is_nonempty() && value.is_nonempty()) { + std::string value_string = query_string.substr(value.begin, value.len); + if (value_string.find(WideToASCII(kSearchTermsParameterFull), 0) != + std::string::npos || + value_string.find( + WideToASCII(kGoogleUnescapedSearchTermsParameterFull), 0) != + std::string::npos) { + search_term_key_ = query_string.substr(key.begin, key.len); + host_ = url.host(); + path_ = url.path(); + break; + } + } + } +} + +GURL TemplateURLRef::ReplaceSearchTerms( + const TemplateURL& host, + const std::wstring& terms, + int accepted_suggestion, + const std::wstring& original_query_for_suggestion) const { + ParseIfNecessary(); + if (!valid_) + return GURL(); + + if (replacements_.empty()) + return GURL(WideToUTF8(parsed_url_)); + + // Encode the search terms so that we know the encoding. + const std::vector<std::string>& encodings = host.input_encodings(); + std::wstring encoded_terms; + std::wstring encoded_original_query; + std::wstring input_encoding; + for (size_t i = 0; i < encodings.size(); ++i) { + if (EscapeQueryParamValue(terms, encodings[i].c_str(), &encoded_terms)) { + if (!original_query_for_suggestion.empty()) { + EscapeQueryParamValue(original_query_for_suggestion, + encodings[i].c_str(), &encoded_original_query); + } + input_encoding = ASCIIToWide(encodings[i]); + break; + } + } + if (input_encoding.empty()) { + encoded_terms = EscapeQueryParamValueUTF8(terms); + if (!original_query_for_suggestion.empty()) { + encoded_original_query = + EscapeQueryParamValueUTF8(original_query_for_suggestion); + } + input_encoding = L"UTF-8"; + } + + std::wstring url = parsed_url_; + + // replacements_ is ordered in ascending order, as such we need to iterate + // from the back. + for (Replacements::reverse_iterator i = replacements_.rbegin(); + i != replacements_.rend(); ++i) { + switch (i->type) { + case ENCODING: + url.insert(i->index, input_encoding); + break; + + case GOOGLE_ACCEPTED_SUGGESTION: + if (accepted_suggestion == NO_SUGGESTION_CHOSEN) + url.insert(i->index, L"aq=f&"); + else if (accepted_suggestion != NO_SUGGESTIONS_AVAILABLE) + url.insert(i->index, StringPrintf(L"aq=%d&", accepted_suggestion)); + break; + + case GOOGLE_BASE_URL: + url.insert(i->index, GoogleBaseURLValue()); + break; + + case GOOGLE_BASE_SUGGEST_URL: + url.insert(i->index, GoogleBaseSuggestURLValue()); + break; + + case GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION: + if (accepted_suggestion >= 0) + url.insert(i->index, L"oq=" + encoded_original_query + L"&"); + break; + + case GOOGLE_RLZ: { + std::wstring rlz_string; + RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz_string); + if (!rlz_string.empty()) { + rlz_string = L"rlz=" + rlz_string + L"&"; + url.insert(i->index, rlz_string); + } + break; + } + + case GOOGLE_UNESCAPED_SEARCH_TERMS: { + std::string unescaped_terms; + WideToCodepage(terms, WideToASCII(input_encoding).c_str(), + OnStringUtilConversionError::SKIP, &unescaped_terms); + url.insert(i->index, std::wstring(unescaped_terms.begin(), + unescaped_terms.end())); + break; + } + + case LANGUAGE: + url.insert(i->index, g_browser_process->GetApplicationLocale()); + break; + + case SEARCH_TERMS: + url.insert(i->index, encoded_terms); + break; + + default: + NOTREACHED(); + break; + } + } + + return GURL(WideToUTF8(url)); +} + +bool TemplateURLRef::SupportsReplacement() const { + ParseIfNecessary(); + return valid_ && supports_replacements_; +} + +bool TemplateURLRef::IsValid() const { + ParseIfNecessary(); + return valid_; +} + +std::wstring TemplateURLRef::DisplayURL() const { + ParseIfNecessary(); + if (!valid_) + return url_; // If we're not valid, don't escape anything. + + if (replacements_.empty()) + return url_; // Nothing to replace, return the url. + + std::wstring result = url_; + ReplaceSubstringsAfterOffset(&result, 0, kSearchTermsParameterFull, + kDisplaySearchTerms); + + ReplaceSubstringsAfterOffset(&result, 0, + kGoogleUnescapedSearchTermsParameterFull, + kDisplayUnescapedSearchTerms); + + return result; +} + +// static +std::wstring TemplateURLRef::DisplayURLToURLRef( + const std::wstring& display_url) { + std::wstring result = display_url; + ReplaceSubstringsAfterOffset(&result, 0, kDisplaySearchTerms, + kSearchTermsParameterFull); + ReplaceSubstringsAfterOffset(&result, 0, kDisplayUnescapedSearchTerms, + kGoogleUnescapedSearchTermsParameterFull); + return result; +} + +const std::string& TemplateURLRef::GetHost() const { + ParseIfNecessary(); + return host_; +} + +const std::string& TemplateURLRef::GetPath() const { + ParseIfNecessary(); + return path_; +} + +const std::string& TemplateURLRef::GetSearchTermKey() const { + ParseIfNecessary(); + return search_term_key_; +} + +std::wstring TemplateURLRef::SearchTermToWide(const TemplateURL& host, + const std::string& term) const { + const std::vector<std::string>& encodings = host.input_encodings(); + std::wstring result; + + std::string unescaped = + UnescapeURLComponent(term, UnescapeRule::REPLACE_PLUS_WITH_SPACE); + for (size_t i = 0; i < encodings.size(); ++i) { + if (CodepageToWide(unescaped, encodings[i].c_str(), + OnStringUtilConversionError::FAIL, &result)) + return result; + } + + // Always fall back on UTF-8 if it works. + if (CodepageToWide(unescaped, "UTF-8", + OnStringUtilConversionError::FAIL, &result)) + return result; + + // When nothing worked, just use the escaped text. We have no idea what the + // encoding is. We need to substitute spaces for pluses ourselves since we're + // not sending it through an unescaper. + result = UTF8ToWide(term); + std::replace(result.begin(), result.end(), '+', ' '); + return result; +} + +bool TemplateURLRef::HasGoogleBaseURLs() const { + ParseIfNecessary(); + for (size_t i = 0; i < replacements_.size(); ++i) { + if ((replacements_[i].type == GOOGLE_BASE_URL) || + (replacements_[i].type == GOOGLE_BASE_SUGGEST_URL)) + return true; + } + return false; +} + +void TemplateURLRef::InvalidateCachedValues() const { + supports_replacements_ = valid_ = parsed_ = false; + host_.clear(); + path_.clear(); + search_term_key_.clear(); + replacements_.clear(); +} + +// Returns the value to use for replacements of type GOOGLE_BASE_URL. +// static +std::wstring TemplateURLRef::GoogleBaseURLValue() { + return google_base_url_ ? + (*google_base_url_) : UTF8ToWide(GoogleURLTracker::GoogleURL().spec()); +} + +// Returns the value to use for replacements of type GOOGLE_BASE_SUGGEST_URL. +// static +std::wstring TemplateURLRef::GoogleBaseSuggestURLValue() { + // The suggest base URL we want at the end is something like + // "http://clients1.google.TLD/complete/". The key bit we want from the + // original Google base URL is the TLD. + + // Start with the Google base URL. + const GURL base_url(google_base_url_ ? + GURL(WideToUTF8(*google_base_url_)) : GoogleURLTracker::GoogleURL()); + DCHECK(base_url.is_valid()); + + // Change "www." to "clients1." in the hostname. If no "www." was found, just + // prepend "clients1.". + const std::string base_host(base_url.host()); + GURL::Replacements repl; + const std::string suggest_host("clients1." + + (base_host.compare(0, 4, "www.") ? base_host : base_host.substr(4))); + repl.SetHostStr(suggest_host); + + // Replace any existing path with "/complete/". + static const std::string suggest_path("/complete/"); + repl.SetPathStr(suggest_path); + + // Clear the query and ref. + repl.ClearQuery(); + repl.ClearRef(); + return UTF8ToWide(base_url.ReplaceComponents(repl).spec()); +} + +// TemplateURL ---------------------------------------------------------------- + +// static +GURL TemplateURL::GenerateFaviconURL(const GURL& url) { + DCHECK(url.is_valid()); + GURL::Replacements rep; + + const char favicon_path[] = "/favicon.ico"; + int favicon_path_len = arraysize(favicon_path) - 1; + + rep.SetPath(favicon_path, url_parse::Component(0, favicon_path_len)); + rep.ClearUsername(); + rep.ClearPassword(); + rep.ClearQuery(); + rep.ClearRef(); + return url.ReplaceComponents(rep); +} + +void TemplateURL::SetSuggestionsURL(const std::wstring& suggestions_url, + int index_offset, + int page_offset) { + suggestions_url_.Set(suggestions_url, index_offset, page_offset); +} + +void TemplateURL::SetURL(const std::wstring& url, + int index_offset, + int page_offset) { + url_.Set(url, index_offset, page_offset); +} + +void TemplateURL::set_keyword(const std::wstring& keyword) { + // Case sensitive keyword matching is confusing. As such, we force all + // keywords to be lower case. + keyword_ = l10n_util::ToLower(keyword); + autogenerate_keyword_ = false; +} + +const std::wstring& TemplateURL::keyword() const { + if (autogenerate_keyword_ && keyword_.empty()) { + // Generate a keyword and cache it. + keyword_ = TemplateURLModel::GenerateKeyword( + TemplateURLModel::GenerateSearchURL(this).GetWithEmptyPath(), true); + } + return keyword_; +} + +bool TemplateURL::ShowInDefaultList() const { + return show_in_default_list() && url() && url()->SupportsReplacement(); +} + +void TemplateURL::SetFavIconURL(const GURL& url) { + for (std::vector<ImageRef>::iterator i = image_refs_.begin(); + i != image_refs_.end(); ++i) { + if (i->type == L"image/x-icon" && + i->width == kFavIconSize && i->height == kFavIconSize) { + if (!url.is_valid()) + image_refs_.erase(i); + else + i->url = url; + return; + } + } + // Don't have one yet, add it. + if (url.is_valid()) { + add_image_ref( + TemplateURL::ImageRef(L"image/x-icon", kFavIconSize, kFavIconSize, + url)); + } +} + +GURL TemplateURL::GetFavIconURL() const { + for (std::vector<ImageRef>::const_iterator i = image_refs_.begin(); + i != image_refs_.end(); ++i) { + if ((i->type == L"image/x-icon" || i->type == L"image/vnd.microsoft.icon") + && i->width == kFavIconSize && i->height == kFavIconSize) { + return i->url; + } + } + return GURL(); +} + +void TemplateURL::InvalidateCachedValues() const { + url_.InvalidateCachedValues(); + suggestions_url_.InvalidateCachedValues(); + if (autogenerate_keyword_) + keyword_.clear(); +} + diff --git a/chrome/browser/template_url.h b/chrome/browser/template_url.h new file mode 100644 index 0000000..a675eec --- /dev/null +++ b/chrome/browser/template_url.h @@ -0,0 +1,436 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TEMPLATE_URL_H__ +#define CHROME_BROWSER_TEMPLATE_URL_H__ + +#include <vector> + +#include "base/basictypes.h" +#include "base/time.h" +#include "googleurl/src/gurl.h" + +class TemplateURL; + +// TemplateURL represents the relevant portions of the Open Search Description +// Document (http://www.opensearch.org/Specifications/OpenSearch). +// The main use case for TemplateURL is to use the TemplateURLRef returned by +// suggestions_url or url for keyword/suggestion expansion: +// . suggestions_url describes a URL that is ideal for as you type suggestions. +// The returned results are in the mime type application/x-suggestions+json. +// . url describes a URL that may be used as a shortcut. Returned results are +// are text/html. +// Before using either one, make sure it's non-NULL, and if you intend to use +// it to replace search terms, make sure SupportsReplacement returns true. +// To use either URL invoke the ReplaceSearchTerms method on the corresponding +// TemplateURLRef. +// +// For files parsed from the Web, be sure and invoke IsValid. IsValid returns +// true if the URL could be parsed. +// +// Both TemplateURL and TemplateURLRef have value semantics. This allows the +// UI to create a copy while the user modifies the values. +class TemplateURLRef { + public: + // Magic numbers to pass to ReplaceSearchTerms() for the |accepted_suggestion| + // parameter. Most callers aren't using Suggest capabilities and should just + // pass NO_SUGGESTIONS_AVAILABLE. + // NOTE: Because positive values are meaningful, make sure these are negative! + enum AcceptedSuggestion { + NO_SUGGESTION_CHOSEN = -1, + NO_SUGGESTIONS_AVAILABLE = -2, + }; + + TemplateURLRef(); + + TemplateURLRef(const std::wstring& url, int index_offset, int page_offset) + : url_(url), + index_offset_(index_offset), + page_offset_(page_offset), + parsed_(false), + valid_(false), + supports_replacements_(false) { + } + + // Returns true if this URL supports replacement. + bool SupportsReplacement() const; + + // Returns a string that is the result of replacing the search terms in + // the url with the specified value. + // + // If this TemplateURLRef does not support replacement (SupportsReplacement + // returns false), an empty string is returned. + // + // The TemplateURL is used to determine the input encoding for the term. + GURL ReplaceSearchTerms( + const TemplateURL& host, + const std::wstring& terms, + int accepted_suggestion, + const std::wstring& original_query_for_suggestion) const; + + // Returns the raw URL. None of the parameters will have been replaced. + const std::wstring& url() const { return url_; } + + // Returns the index number of the first search result. + int index_offset() const { return index_offset_; } + + // Returns the page number of the first search results. + int page_offset() const { return page_offset_; } + + // Returns true if the TemplateURLRef is valid. An invalid TemplateURLRef is + // one that contains unknown terms, or invalid characters. + bool IsValid() const; + + // Returns a string representation of this TemplateURLRef suitable for + // display. The display format is the same as the format used by Firefox. + std::wstring DisplayURL() const; + + // Converts a string as returned by DisplayURL back into a string as + // understood by TemplateURLRef. + static std::wstring DisplayURLToURLRef(const std::wstring& display_url); + + // If this TemplateURLRef is valid and contains one search term, this returns + // the host/path of the URL, otherwise this returns an empty string. + const std::string& GetHost() const; + const std::string& GetPath() const; + + // If this TemplateURLRef is valid and contains one search term, this returns + // the key of the search term, otherwise this returns an empty string. + const std::string& GetSearchTermKey() const; + + // Converts the specified term in the encoding of the host TemplateURL to a + // wide string. + std::wstring SearchTermToWide(const TemplateURL& host, + const std::string& term) const; + + // Returns true if this TemplateURLRef has a replacement term of + // {google:baseURL} or {google:baseSuggestURL}. + bool HasGoogleBaseURLs() const; + + private: + friend class TemplateURL; + friend class TemplateURLModelTest; + friend class TemplateURLTest; + + // Enumeration of the known types. + enum ReplacementType { + ENCODING, + GOOGLE_ACCEPTED_SUGGESTION, + GOOGLE_BASE_URL, + GOOGLE_BASE_SUGGEST_URL, + GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION, + GOOGLE_RLZ, + GOOGLE_UNESCAPED_SEARCH_TERMS, + LANGUAGE, + SEARCH_TERMS, + }; + + // Used to identify an element of the raw url that can be replaced. + struct Replacement { + Replacement(ReplacementType type, int index) : type(type), index(index) {} + ReplacementType type; + int index; + }; + + // The list of elements to replace. + typedef std::vector<struct Replacement> Replacements; + + // TemplateURLRef internally caches values to make replacement quick. This + // method invalidates any cached values. + void InvalidateCachedValues() const; + + // Resets the url. + void Set(const std::wstring& url, int index_offset, int page_offset); + + // Parses the parameter in url at the specified offset. start/end specify the + // range of the parameter in the url, including the braces. If the parameter + // is valid, url is updated to reflect the appropriate parameter. If + // the parameter is one of the known parameters an element is added to + // replacements indicating the type and range of the element. + // + // If the parameter is not a known parameter, false is returned. + bool ParseParameter(size_t start, + size_t end, + std::wstring* url, + Replacements* replacements) const; + + // Parses the specified url, replacing parameters as necessary. If + // successful, valid is set to true, and the parsed url is returned. For all + // known parameters that are encountered an entry is added to replacements. + // If there is an error parsing (unknown parameter, or bogus url), valid is + // set to false, and an empty string is returned. + std::wstring ParseURL(const std::wstring& url, + Replacements* replacements, + bool* valid) const; + + // If the url has not yet been parsed, ParseURL is invoked. + // NOTE: While this is const, it modifies parsed_, valid_, parsed_url_ and + // search_offset_. + void ParseIfNecessary() const; + + // Extracts the query key and host from the url. + void ParseHostAndSearchTermKey() const; + + // Returns the value for the GOOGLE_BASE_URL term. + static std::wstring GoogleBaseURLValue(); + + // Returns the value for the GOOGLE_BASE_SUGGEST_URL term. + static std::wstring GoogleBaseSuggestURLValue(); + + // The raw URL. Where as this contains all the terms (such as {searchTerms}), + // parsed_url_ has them all stripped out. + std::wstring url_; + + // indexOffset defined for the Url element. + int index_offset_; + + // searchOffset defined for the Url element. + int page_offset_; + + // Whether the URL has been parsed. + mutable bool parsed_; + + // Whether the url was successfully parsed. + mutable bool valid_; + + // The parsed URL. All terms have been stripped out of this with + // replacements_ giving the index of the terms to replace. + mutable std::wstring parsed_url_; + + // Do we support replacement? + mutable bool supports_replacements_; + + // The replaceable parts of url (parsed_url_). These are ordered by index + // into the string, and may be empty. + mutable Replacements replacements_; + + // Host, path and key of the search term. These are only set if the url + // contains one search term. + mutable std::string host_; + mutable std::string path_; + mutable std::string search_term_key_; + + // For testing. If non-null this is the replacement value for GOOGLE_BASE_URL + // terms. + static std::wstring* google_base_url_; +}; + +// Describes the relevant portions of a single OSD document. +class TemplateURL { + public: + typedef int64 IDType; + + // Describes a single image reference. Each TemplateURL may have + // any number (including 0) of ImageRefs. + // + // If a TemplateURL has no images, the favicon for the generated URL + // should be used. + struct ImageRef { + ImageRef(const std::wstring& type, int width, int height) + : type(type), width(width), height(height) { + } + + ImageRef(const std::wstring& type, int width, int height, const GURL& url) + : type(type), width(width), height(height), url(url) { + } + + // Mime type for the image. + // ICO image will have the format: image/x-icon or image/vnd.microsoft.icon + std::wstring type; + + // Size of the image + int width; + int height; + + // URL of the image. + GURL url; + }; + + // Generates a favicon URL from the specified url. + static GURL GenerateFaviconURL(const GURL& url); + + TemplateURL() + : autogenerate_keyword_(false), + show_in_default_list_(false), + safe_for_autoreplace_(false), + id_(0), + date_created_(base::Time::Now()), + usage_count_(0), + prepopulate_id_(0) {} + ~TemplateURL() {} + + // A short description of the template. This is the name we show to the user + // in various places that use keywords. For example, the location bar shows + // this when the user selects the keyword. + void set_short_name(const std::wstring& short_name) { + short_name_ = short_name; + } + const std::wstring& short_name() const { return short_name_; } + + // A description of the template; this may be empty. + void set_description(const std::wstring& description) { + description_ = description; + } + const std::wstring& description() const { return description_; } + + // URL providing JSON results. This is typically used to provide suggestions + // as your type. If NULL, this url does not support suggestions. + // Be sure and check the resulting TemplateURLRef for SupportsReplacement + // before using. + void SetSuggestionsURL(const std::wstring& suggestions_url, + int index_offset, + int page_offset); + const TemplateURLRef* suggestions_url() const { + if (suggestions_url_.url().empty()) + return NULL; + return &suggestions_url_; + } + + // Parameterized URL for providing the results. This may be NULL. + // Be sure and check the resulting TemplateURLRef for SupportsReplacement + // before using. + void SetURL(const std::wstring& url, int index_offset, int page_offset); + // Returns the TemplateURLRef that may be used for search results. This + // returns NULL if a url element was not specified. + const TemplateURLRef* url() const { + if (url_.url().empty()) + return NULL; + return &url_; + } + + // URL to the OSD file this came from. May be empty. + void set_originating_url(const GURL& url) { + originating_url_ = url; + } + const GURL& originating_url() const { return originating_url_; } + + // The shortcut for this template url. May be empty. + void set_keyword(const std::wstring& keyword); + const std::wstring& keyword() const; + + // Whether to autogenerate a keyword from the url() in GetKeyword(). Most + // consumers should not need this. + // NOTE: Calling set_keyword() turns this back off. Manual and automatic + // keywords are mutually exclusive. + void set_autogenerate_keyword(bool autogenerate_keyword) { + autogenerate_keyword_ = autogenerate_keyword; + if (autogenerate_keyword_) + keyword_.clear(); + } + bool autogenerate_keyword() const { + return autogenerate_keyword_; + } + + // Whether this keyword is shown in the default list of search providers. This + // is just a property and does not indicate whether this TemplateURL has + // a TemplateURLRef that supports replacement. Use ShowInDefaultList to + // test both. + // The default value is false. + void set_show_in_default_list(bool show_in_default_list) { + show_in_default_list_ = show_in_default_list; + } + bool show_in_default_list() const { return show_in_default_list_; } + + // Returns true if show_in_default_list() is true and this TemplateURL has a + // TemplateURLRef that supports replacement. + bool ShowInDefaultList() const; + + // Whether it's safe for auto-modification code (the autogenerator and the + // code that imports data from other browsers) to replace the TemplateURL. + // This should be set to false for any keyword the user edits, or any keyword + // that the user clearly manually edited in the past, like a bookmark keyword + // from another browser. + void set_safe_for_autoreplace(bool safe_for_autoreplace) { + safe_for_autoreplace_ = safe_for_autoreplace; + } + bool safe_for_autoreplace() const { return safe_for_autoreplace_; } + + // Images for this URL. May be empty. + void add_image_ref(const ImageRef& ref) { image_refs_.push_back(ref); } + const std::vector<ImageRef>& image_refs() const { return image_refs_; } + + // Convenience methods for getting/setting an ImageRef that points to a + // favicon. A TemplateURL need not have an ImageRef for a favicon. In such + // a situation GetFavIconURL returns an invalid url. + // + // If url is empty and there is an image ref for a favicon, it is removed. + void SetFavIconURL(const GURL& url); + GURL GetFavIconURL() const; + + // Set of languages supported. This may be empty. + void add_language(const std::wstring& language) { + languages_.push_back(language); + } + const std::vector<std::wstring>& languages() const { return languages_; } + + // Date this keyword was created. + // + // NOTE: this may be 0, which indicates the keyword was created before we + // started tracking creation time. + void set_date_created(base::Time time) { date_created_ = time; } + base::Time date_created() const { return date_created_; } + + // Number of times this keyword has been explicitly used to load a URL. We + // don't increment this for uses as the "default search engine" since that's + // not really "explicit" usage and incrementing would result in pinning the + // user's default search engine(s) to the top of the list of searches on the + // New Tab page, de-emphasizing the omnibox as "where you go to search". + void set_usage_count(int count) { usage_count_ = count; } + int usage_count() const { return usage_count_; } + + // The list of supported encodings for the search terms. This may be empty, + // which indicates the terms should be encoded with UTF-8. + void set_input_encodings(const std::vector<std::string>& encodings) { + input_encodings_ = encodings; + } + void add_input_encoding(const std::string& encoding) { + input_encodings_.push_back(encoding); + } + const std::vector<std::string>& input_encodings() const { + return input_encodings_; + } + + // Returns the unique identifier of this TemplateURL. The unique ID is set + // by the TemplateURLModel when the TemplateURL is added to it. + IDType id() const { return id_; } + + // If this TemplateURL comes from prepopulated data the prepopulate_id is > 0. + void set_prepopulate_id(int id) { prepopulate_id_ = id; } + int prepopulate_id() const { return prepopulate_id_; } + + private: + friend class WebDatabaseTest; + friend class WebDatabase; + friend class TemplateURLModel; + + // Invalidates cached values on this object and its child TemplateURLRefs. + void InvalidateCachedValues() const; + + // Unique identifier, used when archived to the database. + void set_id(IDType id) { id_ = id;} + + std::wstring short_name_; + std::wstring description_; + TemplateURLRef suggestions_url_; + TemplateURLRef url_; + GURL originating_url_; + mutable std::wstring keyword_; + bool autogenerate_keyword_; // If this is set, |keyword_| holds the cached + // generated keyword if available. + bool show_in_default_list_; + bool safe_for_autoreplace_; + std::vector<ImageRef> image_refs_; + std::vector<std::wstring> languages_; + // List of supported input encodings. + std::vector<std::string> input_encodings_; + IDType id_; + base::Time date_created_; + int usage_count_; + int prepopulate_id_; + + // TODO(sky): Add date last parsed OSD file. +}; + +#endif // CHROME_BROWSER_TEMPLATE_URL_PARSER_H__ + diff --git a/chrome/browser/template_url_fetcher.cc b/chrome/browser/template_url_fetcher.cc new file mode 100644 index 0000000..57bb259 --- /dev/null +++ b/chrome/browser/template_url_fetcher.cc @@ -0,0 +1,116 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/template_url_fetcher.h" + +#include "chrome/browser/profile.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" +#include "chrome/browser/template_url_parser.h" +#include "chrome/browser/views/edit_keyword_controller.h" + +// RequestDelegate ------------------------------------------------------------ + +void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete( + const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + // Make sure we can still replace the keyword. + if (response_code != 200) { + fetcher_->RequestCompleted(this); + // WARNING: RequestCompleted deletes us. + return; + } + + scoped_ptr<TemplateURL> template_url(new TemplateURL()); + if (TemplateURLParser::Parse( + reinterpret_cast<const unsigned char*>(data.c_str()), + data.length(), + NULL, + template_url.get()) && + template_url->url() && template_url->url()->SupportsReplacement()) { + TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel(); + const TemplateURL* existing_url; + if (!model || !model->loaded() || + !model->CanReplaceKeyword(keyword_, template_url->url()->url(), + &existing_url)) { + // TODO(pamg): If we're coming from JS (not autodetected) and this URL + // already exists in the model, consider bringing up the + // EditKeywordController to edit it. This would be helpful feedback in + // the case of clicking a button twice, and annoying in the case of a + // page that calls AddSearchProvider() in JS without a user action. + fetcher_->RequestCompleted(this); + // WARNING: RequestCompleted deletes us. + return; + } + + if (existing_url) + model->Remove(existing_url); + + // The short name is what is shown to the user. We reset it to make sure + // we don't display random text from the web. + template_url->set_short_name(keyword_); + template_url->set_keyword(keyword_); + template_url->set_originating_url(osdd_url_); + + // The page may have specified a URL to use for favicons, if not, set it. + if (!template_url->GetFavIconURL().is_valid()) + template_url->SetFavIconURL(favicon_url_); + + if (autodetected_) { + // Mark the keyword as replaceable so it can be removed if necessary. + template_url->set_safe_for_autoreplace(true); + model->Add(template_url.release()); + } else { + // Confirm addition and allow user to edit default choices. It's ironic + // that only *non*-autodetected additions get confirmed, but the user + // expects feedback that his action did something. + // The edit controller will take care of adding the URL to the model, + // which takes ownership, or of deleting it if the add is cancelled. + EditKeywordController* controller = + new EditKeywordController(parent_window_, + template_url.release(), + NULL, // no KeywordEditorView + fetcher_->profile()); + controller->Show(); + } + } + fetcher_->RequestCompleted(this); + // WARNING: RequestCompleted deletes us. +} + +// TemplateURLFetcher --------------------------------------------------------- + +TemplateURLFetcher::TemplateURLFetcher(Profile* profile) : profile_(profile) { + DCHECK(profile_); +} + +void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword, + const GURL& osdd_url, + const GURL& favicon_url, + const HWND parent_window, + bool autodetected) { + DCHECK(!keyword.empty() && osdd_url.is_valid()); + // Make sure we aren't already downloading this request. + for (std::vector<RequestDelegate*>::iterator i = requests_->begin(); + i != requests_->end(); ++i) { + if ((*i)->url() == osdd_url || (*i)->keyword() == keyword) + return; + } + + requests_->push_back( + new RequestDelegate(this, keyword, osdd_url, favicon_url, parent_window, + autodetected)); +} + +void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) { + DCHECK(find(requests_->begin(), requests_->end(), request) != + requests_->end()); + requests_->erase(find(requests_->begin(), requests_->end(), request)); + delete request; +} + diff --git a/chrome/browser/template_url_fetcher.h b/chrome/browser/template_url_fetcher.h new file mode 100644 index 0000000..a07277f --- /dev/null +++ b/chrome/browser/template_url_fetcher.h @@ -0,0 +1,104 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TEMPLATE_URL_FETCHER_H__ +#define CHROME_BROWSER_TEMPLATE_URL_FETCHER_H__ + +#include "chrome/browser/profile.h" +#include "chrome/browser/url_fetcher.h" +#include "chrome/common/scoped_vector.h" + +class GURL; +class Profile; +class TemplateURL; +class WebContents; + +// TemplateURLFetcher is responsible for downloading OpenSearch description +// documents, creating a TemplateURL from the OSDD, and adding the TemplateURL +// to the TemplateURLModel. Downloading is done in the background. +// +class TemplateURLFetcher { + public: + // Creates a TemplateURLFetcher with the specified Profile. + explicit TemplateURLFetcher(Profile* profile); + + // If TemplateURLFetcher is not already downloading the OSDD for osdd_url, + // it is downloaded. If successful and the result can be parsed, a TemplateURL + // is added to the TemplateURLModel. + void ScheduleDownload(const std::wstring& keyword, + const GURL& osdd_url, + const GURL& favicon_url, + const HWND parent_window, + bool autodetected); + + private: + friend class RequestDelegate; + + // A RequestDelegate is created to download each OSDD. When done downloading + // RequestCompleted is invoked back on the TemplateURLFetcher. + class RequestDelegate : public URLFetcher::Delegate { + public: + RequestDelegate(TemplateURLFetcher* fetcher, + const std::wstring& keyword, + const GURL& osdd_url, + const GURL& favicon_url, + const HWND parent_window, + bool autodetected) +#pragma warning(disable:4355) + : url_fetcher_(osdd_url, URLFetcher::GET, this), + fetcher_(fetcher), + keyword_(keyword), + osdd_url_(osdd_url), + favicon_url_(favicon_url), + parent_window_(parent_window), + autodetected_(autodetected) { + url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext()); + url_fetcher_.Start(); + } + + // If data contains a valid OSDD, a TemplateURL is created and added to + // the TemplateURLModel. + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + // URL of the OSDD. + const GURL& url() const { return osdd_url_; } + + // Keyword to use. + const std::wstring keyword() const { return keyword_; } + + private: + URLFetcher url_fetcher_; + TemplateURLFetcher* fetcher_; + const std::wstring keyword_; + const GURL osdd_url_; + const GURL favicon_url_; + bool autodetected_; + + // Used to determine where to place a confirmation dialog. May be NULL, + // in which case the confirmation will be centered in the screen if needed. + const HWND parent_window_; + + DISALLOW_EVIL_CONSTRUCTORS(RequestDelegate); + }; + + Profile* profile() const { return profile_; } + + // Invoked from the RequestDelegate when done downloading. + void RequestCompleted(RequestDelegate* request); + + Profile* profile_; + + // In progress requests. + ScopedVector<RequestDelegate> requests_; + + DISALLOW_EVIL_CONSTRUCTORS(TemplateURLFetcher); +}; + +#endif // CHROME_BROWSER_OSDD_FETCHER_H__ + diff --git a/chrome/browser/template_url_model.cc b/chrome/browser/template_url_model.cc new file mode 100644 index 0000000..a3ffd5f --- /dev/null +++ b/chrome/browser/template_url_model.cc @@ -0,0 +1,980 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/template_url_model.h" + +#include <algorithm> + +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/app/locales/locale_settings.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/google_url_tracker.h" +#include "chrome/browser/history/history.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/rlz/rlz.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_prepopulate_data.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/common/stl_util-inl.h" +#include "googleurl/src/gurl.h" +#include "googleurl/src/url_parse.h" +#include "net/base/net_util.h" +#include "unicode/rbbi.h" +#include "unicode/uchar.h" + +using base::Time; + +// String in the URL that is replaced by the search term. +static const wchar_t kSearchTermParameter[] = L"{searchTerms}"; + +// String in Initializer that is replaced with kSearchTermParameter. +static const wchar_t kTemplateParameter[] = L"%s"; + +// Term used when generating a search url. Use something obscure so that on +// the rare case the term replaces the URL it's unlikely another keyword would +// have the same url. +static const wchar_t kReplacementTerm[] = L"blah.blah.blah.blah.blah"; + +class TemplateURLModel::LessWithPrefix { + public: + // We want to find the set of keywords that begin with a prefix. The STL + // algorithms will return the set of elements that are "equal to" the + // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))". When + // cmp() is the typical std::less<>, this results in lexicographic equality; + // we need to extend this to mark a prefix as "not less than" a keyword it + // begins, which will cause the desired elements to be considered "equal to" + // the prefix. Note: this is still a strict weak ordering, as required by + // equal_range() (though I will not prove that here). + // + // Unfortunately the calling convention is not "prefix and element" but + // rather "two elements", so we pass the prefix as a fake "element" which has + // a NULL KeywordDataElement pointer. + bool operator()(const KeywordToTemplateMap::value_type& elem1, + const KeywordToTemplateMap::value_type& elem2) const { + return (elem1.second == NULL) ? + (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0) : + (elem1.first < elem2.first); + } +}; + +TemplateURLModel::TemplateURLModel(Profile* profile) + : profile_(profile), + loaded_(false), + load_handle_(0), + default_search_provider_(NULL), + next_id_(1) { + DCHECK(profile_); + Init(NULL, 0); +} + +TemplateURLModel::TemplateURLModel(const Initializer* initializers, + const int count) + : profile_(NULL), + loaded_(true), + load_handle_(0), + service_(NULL), + default_search_provider_(NULL), + next_id_(1) { + Init(initializers, count); +} + +TemplateURLModel::~TemplateURLModel() { + if (load_handle_) { + DCHECK(service_.get()); + service_->CancelRequest(load_handle_); + } + + STLDeleteElements(&template_urls_); + + NotificationService* ns = NotificationService::current(); + if (profile_) { + ns->RemoveObserver(this, NOTIFY_HISTORY_URL_VISITED, + Source<Profile>(profile_->GetOriginalProfile())); + } + ns->RemoveObserver(this, NOTIFY_GOOGLE_URL_UPDATED, + NotificationService::AllSources()); +} + +void TemplateURLModel::Init(const Initializer* initializers, + int num_initializers) { + // Register for notifications. + NotificationService* ns = NotificationService::current(); + if (profile_) { + // TODO(sky): bug 1166191. The keywords should be moved into the history + // db, which will mean we no longer need this notification and the history + // backend can handle automatically adding the search terms as the user + // navigates. + ns->AddObserver(this, NOTIFY_HISTORY_URL_VISITED, + Source<Profile>(profile_->GetOriginalProfile())); + } + ns->AddObserver(this, NOTIFY_GOOGLE_URL_UPDATED, + NotificationService::AllSources()); + + // Add specific initializers, if any. + for (int i(0); i < num_initializers; ++i) { + DCHECK(initializers[i].keyword); + DCHECK(initializers[i].url); + DCHECK(initializers[i].content); + + size_t template_position = + std::wstring(initializers[i].url).find(kTemplateParameter); + DCHECK(template_position != std::wstring::npos); + std::wstring osd_url(initializers[i].url); + osd_url.replace(template_position, arraysize(kTemplateParameter) - 1, + kSearchTermParameter); + + // TemplateURLModel ends up owning the TemplateURL, don't try and free it. + TemplateURL* template_url = new TemplateURL(); + template_url->set_keyword(initializers[i].keyword); + template_url->set_short_name(initializers[i].content); + template_url->SetURL(osd_url, 0, 0); + Add(template_url); + } + + // Request a server check for the correct Google URL if Google is the default + // search engine. + const TemplateURL* default_provider = GetDefaultSearchProvider(); + if (default_provider) { + const TemplateURLRef* default_provider_ref = default_provider->url(); + if (default_provider_ref && default_provider_ref->HasGoogleBaseURLs()) + GoogleURLTracker::RequestServerCheck(); + } +} + +// static +std::wstring TemplateURLModel::GenerateKeyword(const GURL& url, + bool autodetected) { + // Don't autogenerate keywords for referrers that are the result of a form + // submission (TODO: right now we approximate this by checking for the URL + // having a query, but we should replace this with a call to WebCore to see if + // the originating page was actually a form submission), anything other than + // http, or referrers with a path. + // + // If we relax the path constraint, we need to be sure to sanitize the path + // elements and update AutocompletePopup to look for keywords using the path. + // See http://b/issue?id=863583. + if (!url.is_valid() || + (autodetected && (url.has_query() || (url.scheme() != "http") || + ((url.path() != "") && (url.path() != "/"))))) + return std::wstring(); + + // Strip "www." off the front of the keyword; otherwise the keyword won't work + // properly. See http://b/issue?id=1205573. + return net::StripWWW(UTF8ToWide(url.host())); +} + +// static +std::wstring TemplateURLModel::CleanUserInputKeyword( + const std::wstring& keyword) { + // Remove the scheme. + std::wstring result(l10n_util::ToLower(keyword)); + url_parse::Component scheme_component; + if (url_parse::ExtractScheme(WideToUTF8(keyword).c_str(), + static_cast<int>(keyword.length()), + &scheme_component)) { + // Include trailing ':'. + result.erase(0, scheme_component.end() + 1); + // Many schemes usually have "//" after them, so strip it too. + const std::wstring after_scheme(L"//"); + if (result.compare(0, after_scheme.length(), after_scheme) == 0) + result.erase(0, after_scheme.length()); + } + + // Remove leading "www.". + result = net::StripWWW(result); + + // Remove trailing "/". + return (result.length() > 0 && result[result.length() - 1] == L'/') ? + result.substr(0, result.length() - 1) : result; +} + +// static +GURL TemplateURLModel::GenerateSearchURL(const TemplateURL* t_url) { + DCHECK(t_url); + const TemplateURLRef* search_ref = t_url->url(); + if (!search_ref || !search_ref->IsValid()) + return GURL(); + + if (!search_ref->SupportsReplacement()) + return GURL(WideToUTF8(search_ref->url())); + + return search_ref->ReplaceSearchTerms( + *t_url, + kReplacementTerm, + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); +} + +bool TemplateURLModel::CanReplaceKeyword( + const std::wstring& keyword, + const std::wstring& url, + const TemplateURL** template_url_to_replace) { + DCHECK(!keyword.empty()); // This should only be called for non-empty + // keywords. If we need to support empty kewords + // the code needs to change slightly. + const TemplateURL* existing_url = GetTemplateURLForKeyword(keyword); + if (existing_url) { + // We already have a TemplateURL for this keyword. Only allow it to be + // replaced if the TemplateURL can be replaced. + if (template_url_to_replace) + *template_url_to_replace = existing_url; + return CanReplace(existing_url); + } + + // We don't have a TemplateURL with keyword. Only allow a new one if there + // isn't a TemplateURL for the specified host, or there is one but it can + // be replaced. We do this to ensure that if the user assigns a different + // keyword to a generated TemplateURL, we won't regenerate another keyword for + // the same host. + GURL gurl(WideToUTF8(url)); + if (gurl.is_valid() && !gurl.host().empty()) + return CanReplaceKeywordForHost(gurl.host(), template_url_to_replace); + return true; +} + +void TemplateURLModel::FindMatchingKeywords( + const std::wstring& prefix, + bool support_replacement_only, + std::vector<std::wstring>* matches) const { + // Sanity check args. + if (prefix.empty()) + return; + DCHECK(matches != NULL); + DCHECK(matches->empty()); // The code for exact matches assumes this. + + // Find matching keyword range. Searches the element map for keywords + // beginning with |prefix| and stores the endpoints of the resulting set in + // |match_range|. + const std::pair<KeywordToTemplateMap::const_iterator, + KeywordToTemplateMap::const_iterator> match_range( + std::equal_range( + keyword_to_template_map_.begin(), keyword_to_template_map_.end(), + KeywordToTemplateMap::value_type(prefix, NULL), LessWithPrefix())); + + // Return vector of matching keywords. + for (KeywordToTemplateMap::const_iterator i(match_range.first); + i != match_range.second; ++i) { + DCHECK(i->second->url()); + if (!support_replacement_only || i->second->url()->SupportsReplacement()) + matches->push_back(i->first); + } +} + +const TemplateURL* TemplateURLModel::GetTemplateURLForKeyword( + const std::wstring& keyword) const { + KeywordToTemplateMap::const_iterator elem( + keyword_to_template_map_.find(keyword)); + return (elem == keyword_to_template_map_.end()) ? NULL : elem->second; +} + +const TemplateURL* TemplateURLModel::GetTemplateURLForHost( + const std::string& host) const { + HostToURLsMap::const_iterator iter = host_to_urls_map_.find(host); + if (iter == host_to_urls_map_.end() || iter->second.empty()) + return NULL; + return *(iter->second.begin()); // Return the 1st element. +} + +void TemplateURLModel::Add(TemplateURL* template_url) { + DCHECK(template_url); + DCHECK(template_url->id() == 0); + DCHECK(find(template_urls_.begin(), template_urls_.end(), template_url) == + template_urls_.end()); + template_url->set_id(++next_id_); + template_urls_.push_back(template_url); + AddToMaps(template_url); + + if (service_.get()) + service_->AddKeyword(*template_url); + + if (loaded_) { + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); + } +} + +void TemplateURLModel::AddToMaps(const TemplateURL* template_url) { + if (!template_url->keyword().empty()) + keyword_to_template_map_[template_url->keyword()] = template_url; + + const GURL url(GenerateSearchURL(template_url)); + if (url.is_valid() && url.has_host()) + host_to_urls_map_[url.host()].insert(template_url); +} + +void TemplateURLModel::Remove(const TemplateURL* template_url) { + TemplateURLVector::iterator i = find(template_urls_.begin(), + template_urls_.end(), + template_url); + if (i == template_urls_.end()) + return; + + if (template_url == default_search_provider_) { + // Should never delete the default search provider. + NOTREACHED(); + return; + } + + RemoveFromMaps(template_url); + + // Remove it from the vector containing all TemplateURLs. + template_urls_.erase(i); + + if (loaded_) { + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); + } + + if (service_.get()) + service_->RemoveKeyword(*template_url); + + if (profile_) { + HistoryService* history = + profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); + if (history) + history->DeleteAllSearchTermsForKeyword(template_url->id()); + } + + // We own the TemplateURL and need to delete it. + delete template_url; +} + +void TemplateURLModel::Replace(const TemplateURL* existing_turl, + TemplateURL* new_turl) { + DCHECK(existing_turl && new_turl); + + TemplateURLVector::iterator i = find(template_urls_.begin(), + template_urls_.end(), + existing_turl); + DCHECK(i != template_urls_.end()); + RemoveFromMaps(existing_turl); + template_urls_.erase(i); + + new_turl->set_id(existing_turl->id()); + + template_urls_.push_back(new_turl); + AddToMaps(new_turl); + + if (service_.get()) + service_->UpdateKeyword(*new_turl); + + if (default_search_provider_ == existing_turl) + SetDefaultSearchProvider(new_turl); + + if (loaded_) { + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); + } + + delete existing_turl; +} + +void TemplateURLModel::RemoveAutoGeneratedBetween(Time created_after, + Time created_before) { + for (size_t i = 0; i < template_urls_.size();) { + if (template_urls_[i]->date_created() >= created_after && + (created_before.is_null() || + template_urls_[i]->date_created() < created_before) && + CanReplace(template_urls_[i])) { + Remove(template_urls_[i]); + } else { + ++i; + } + } +} + +void TemplateURLModel::RemoveAutoGeneratedSince(Time created_after) { + RemoveAutoGeneratedBetween(created_after, Time()); +} + +void TemplateURLModel::SetKeywordSearchTermsForURL(const TemplateURL* t_url, + const GURL& url, + const std::wstring& term) { + HistoryService* history = profile_ ? + profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) : NULL; + if (!history) + return; + history->SetKeywordSearchTermsForURL(url, t_url->id(), term); +} + +void TemplateURLModel::RemoveFromMaps(const TemplateURL* template_url) { + if (!template_url->keyword().empty()) { + keyword_to_template_map_.erase(template_url->keyword()); + } + + const GURL url(GenerateSearchURL(template_url)); + if (url.is_valid() && url.has_host()) { + const std::string host(url.host()); + DCHECK(host_to_urls_map_.find(host) != host_to_urls_map_.end()); + TemplateURLSet& urls = host_to_urls_map_[host]; + DCHECK(urls.find(template_url) != urls.end()); + urls.erase(urls.find(template_url)); + if (urls.empty()) + host_to_urls_map_.erase(host_to_urls_map_.find(host)); + } +} + +void TemplateURLModel::RemoveFromMapsByPointer( + const TemplateURL* template_url) { + DCHECK(template_url); + for (KeywordToTemplateMap::iterator i = keyword_to_template_map_.begin(); + i != keyword_to_template_map_.end(); ++i) { + if (i->second == template_url) { + keyword_to_template_map_.erase(i); + // A given TemplateURL only occurs once in the map. As soon as we find the + // entry, stop. + break; + } + } + + for (HostToURLsMap::iterator i = host_to_urls_map_.begin(); + i != host_to_urls_map_.end(); ++i) { + TemplateURLSet::iterator url_set_iterator = i->second.find(template_url); + if (url_set_iterator != i->second.end()) { + i->second.erase(url_set_iterator); + if (i->second.empty()) + host_to_urls_map_.erase(i); + // A given TemplateURL only occurs once in the map. As soon as we find the + // entry, stop. + return; + } + } +} + +void TemplateURLModel::SetTemplateURLs( + const std::vector<const TemplateURL*>& urls) { + DCHECK(template_urls_.empty()); // This should only be called on load, + // when we have no TemplateURLs. + + // Add mappings for the new items. + for (TemplateURLVector::const_iterator i = urls.begin(); i != urls.end(); + ++i) { + next_id_ = std::max(next_id_, (*i)->id()); + AddToMaps(*i); + } + + template_urls_ = urls; +} + +std::vector<const TemplateURL*> TemplateURLModel::GetTemplateURLs() const { + return template_urls_; +} + +void TemplateURLModel::IncrementUsageCount(const TemplateURL* url) { + DCHECK(url && find(template_urls_.begin(), template_urls_.end(), url) != + template_urls_.end()); + const_cast<TemplateURL*>(url)->set_usage_count(url->usage_count() + 1); + if (service_.get()) + service_.get()->UpdateKeyword(*url); +} + +void TemplateURLModel::ResetTemplateURL(const TemplateURL* url, + const std::wstring& title, + const std::wstring& keyword, + const std::wstring& search_url) { + DCHECK(url && find(template_urls_.begin(), template_urls_.end(), url) != + template_urls_.end()); + RemoveFromMaps(url); + TemplateURL* modifiable_url = const_cast<TemplateURL*>(url); + modifiable_url->set_short_name(title); + modifiable_url->set_keyword(keyword); + if ((modifiable_url->url() && search_url.empty()) || + (!modifiable_url->url() && !search_url.empty()) || + (modifiable_url->url() && modifiable_url->url()->url() != search_url)) { + // The urls have changed, reset the favicon url. + modifiable_url->SetFavIconURL(GURL()); + modifiable_url->SetURL(search_url, 0, 0); + } + modifiable_url->set_safe_for_autoreplace(false); + AddToMaps(url); + if (service_.get()) + service_.get()->UpdateKeyword(*url); + + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); +} + +void TemplateURLModel::SetDefaultSearchProvider(const TemplateURL* url) { + if (default_search_provider_ == url) + return; + + DCHECK(!url || find(template_urls_.begin(), template_urls_.end(), url) != + template_urls_.end()); + default_search_provider_ = url; + + if (url) { + TemplateURL* modifiable_url = const_cast<TemplateURL*>(url); + // Don't mark the url as edited, otherwise we won't be able to rev the + // templateurls we ship with. + modifiable_url->set_show_in_default_list(true); + if (service_.get()) + service_.get()->UpdateKeyword(*url); + + const TemplateURLRef* url_ref = url->url(); + if (url_ref && url_ref->HasGoogleBaseURLs()) { + GoogleURLTracker::RequestServerCheck(); + RLZTracker::RecordProductEvent(RLZTracker::CHROME, + RLZTracker::CHROME_OMNIBOX, + RLZTracker::SET_TO_GOOGLE); + } + } + + SaveDefaultSearchProviderToPrefs(url); + + if (service_.get()) + service_->SetDefaultSearchProvider(url); + + if (loaded_) { + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); + } +} + +const TemplateURL* TemplateURLModel::GetDefaultSearchProvider() { + if (loaded_) + return default_search_provider_; + + if (!prefs_default_search_provider_.get()) { + TemplateURL* default_from_prefs; + if (LoadDefaultSearchProviderFromPrefs(&default_from_prefs)) { + prefs_default_search_provider_.reset(default_from_prefs); + } else { + std::vector<TemplateURL*> loaded_urls; + size_t default_search_index; + TemplateURLPrepopulateData::GetPrepopulatedEngines(GetPrefs(), + &loaded_urls, + &default_search_index); + if (default_search_index < loaded_urls.size()) { + prefs_default_search_provider_.reset(loaded_urls[default_search_index]); + loaded_urls.erase(loaded_urls.begin() + default_search_index); + } + STLDeleteElements(&loaded_urls); + } + } + + return prefs_default_search_provider_.get(); +} + +void TemplateURLModel::AddObserver(TemplateURLModelObserver* observer) { + model_observers_.AddObserver(observer); +} + +void TemplateURLModel::RemoveObserver(TemplateURLModelObserver* observer) { + model_observers_.RemoveObserver(observer); +} + +void TemplateURLModel::Load() { + if (loaded_ || load_handle_) + return; + + if (!service_.get()) + service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); + + if (service_.get()) { + load_handle_ = service_->GetKeywords(this); + } else { + loaded_ = true; + NotifyLoaded(); + } +} + +void TemplateURLModel::OnWebDataServiceRequestDone( + WebDataService::Handle h, + const WDTypedResult* result) { + // Reset the load_handle so that we don't try and cancel the load in + // the destructor. + load_handle_ = 0; + + if (!result) { + // Results are null if the database went away. + loaded_ = true; + NotifyLoaded(); + return; + } + + DCHECK(result->GetType() == KEYWORDS_RESULT); + + WDKeywordsResult keyword_result = reinterpret_cast< + const WDResult<WDKeywordsResult>*>(result)->GetValue(); + + // prefs_default_search_provider_ is only needed before we've finished + // loading. Now that we've loaded we can nuke it. + prefs_default_search_provider_.reset(); + + // Compiler won't implicitly convert std::vector<TemplateURL*> to + // std::vector<const TemplateURL*>, and reinterpret_cast is unsafe, + // so we just copy it. + std::vector<const TemplateURL*> template_urls(keyword_result.keywords.begin(), + keyword_result.keywords.end()); + + const int resource_keyword_version = + TemplateURLPrepopulateData::GetDataVersion(); + if (keyword_result.builtin_keyword_version != resource_keyword_version) { + // There should never be duplicate TemplateURLs. We had a bug such that + // duplicate TemplateURLs existed for one locale. As such we invoke + // RemoveDuplicatePrepopulateIDs to nuke the duplicates. + RemoveDuplicatePrepopulateIDs(&template_urls); + } + SetTemplateURLs(template_urls); + + if (keyword_result.default_search_provider_id) { + // See if we can find the default search provider. + for (TemplateURLVector::iterator i = template_urls_.begin(); + i != template_urls_.end(); ++i) { + if ((*i)->id() == keyword_result.default_search_provider_id) { + default_search_provider_ = *i; + break; + } + } + } + + if (keyword_result.builtin_keyword_version != resource_keyword_version) { + MergeEnginesFromPrepopulateData(); + service_->SetBuiltinKeywordVersion(resource_keyword_version); + } + + // Always save the default search provider to prefs. That way we don't have to + // worry about it being out of sync. + if (default_search_provider_) + SaveDefaultSearchProviderToPrefs(default_search_provider_); + + // Delete any hosts that were deleted before we finished loading. + for (std::vector<std::wstring>::iterator i = hosts_to_delete_.begin(); + i != hosts_to_delete_.end(); ++i) { + DeleteGeneratedKeywordsMatchingHost(*i); + } + hosts_to_delete_.clear(); + + // Index any visits that occurred before we finished loading. + for (size_t i = 0; i < visits_to_add_.size(); ++i) + UpdateKeywordSearchTermsForURL(visits_to_add_[i]); + visits_to_add_.clear(); + + loaded_ = true; + + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); + + NotifyLoaded(); +} + +void TemplateURLModel::RemoveDuplicatePrepopulateIDs( + std::vector<const TemplateURL*>* urls) { + std::set<int> ids; + for (std::vector<const TemplateURL*>::iterator i = urls->begin(); + i != urls->end(); ) { + int prepopulate_id = (*i)->prepopulate_id(); + if (prepopulate_id) { + if (ids.find(prepopulate_id) != ids.end()) { + if (service_.get()) + service_->RemoveKeyword(**i); + delete *i; + i = urls->erase(i); + } else { + ids.insert(prepopulate_id); + ++i; + } + } else { + ++i; + } + } +} + +void TemplateURLModel::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NOTIFY_HISTORY_URL_VISITED) { + Details<history::URLVisitedDetails> visit_details(details); + + if (!loaded()) + visits_to_add_.push_back(visit_details->row); + else + UpdateKeywordSearchTermsForURL(visit_details->row); + } else if (type == NOTIFY_GOOGLE_URL_UPDATED) { + if (loaded_) + GoogleBaseURLChanged(); + } else { + NOTREACHED(); + } +} + +void TemplateURLModel::DeleteGeneratedKeywordsMatchingHost( + const std::wstring& host) { + const std::wstring host_slash = host + L"/"; + // Iterate backwards as we may end up removing multiple entries. + for (int i = static_cast<int>(template_urls_.size()) - 1; i >= 0; --i) { + if (CanReplace(template_urls_[i]) && + (template_urls_[i]->keyword() == host || + template_urls_[i]->keyword().compare(0, host_slash.length(), + host_slash) == 0)) { + Remove(template_urls_[i]); + } + } +} + +void TemplateURLModel::NotifyLoaded() { + NotificationService::current()-> + Notify(TEMPLATE_URL_MODEL_LOADED, Source<TemplateURLModel>(this), + NotificationService::NoDetails()); +} + +void TemplateURLModel::MergeEnginesFromPrepopulateData() { + // Build a map from prepopulate id to TemplateURL of existing urls. + std::map<int, const TemplateURL*> id_to_turl; + for (size_t i = 0; i < template_urls_.size(); ++i) { + if (template_urls_[i]->prepopulate_id() > 0) + id_to_turl[template_urls_[i]->prepopulate_id()] = template_urls_[i]; + } + + std::vector<TemplateURL*> loaded_urls; + size_t default_search_index; + TemplateURLPrepopulateData::GetPrepopulatedEngines(GetPrefs(), + &loaded_urls, + &default_search_index); + + for (size_t i = 0; i < loaded_urls.size(); ++i) { + scoped_ptr<TemplateURL> t_url(loaded_urls[i]); + + if (!t_url->prepopulate_id()) { + // Prepopulate engines need an id. + NOTREACHED(); + continue; + } + + const TemplateURL* existing_url = id_to_turl[t_url->prepopulate_id()]; + if (existing_url) { + if (!existing_url->safe_for_autoreplace()) { + // User edited the entry, preserve the keyword and description. + loaded_urls[i]->set_safe_for_autoreplace(false); + loaded_urls[i]->set_keyword(existing_url->keyword()); + loaded_urls[i]->set_autogenerate_keyword( + existing_url->autogenerate_keyword()); + loaded_urls[i]->set_short_name(existing_url->short_name()); + } + Replace(existing_url, loaded_urls[i]); + id_to_turl[t_url->prepopulate_id()] = loaded_urls[i]; + } else { + Add(loaded_urls[i]); + } + if (i == default_search_index && !default_search_provider_) + SetDefaultSearchProvider(loaded_urls[i]); + + t_url.release(); + } +} + +void TemplateURLModel::SaveDefaultSearchProviderToPrefs( + const TemplateURL* t_url) { + PrefService* prefs = GetPrefs(); + if (!prefs) + return; + + RegisterPrefs(prefs); + + const std::wstring search_url = + (t_url && t_url->url()) ? t_url->url()->url() : std::wstring(); + prefs->SetString(prefs::kDefaultSearchProviderSearchURL, search_url); + + const std::wstring suggest_url = + (t_url && t_url->suggestions_url()) ? t_url->suggestions_url()->url() : + std::wstring(); + prefs->SetString(prefs::kDefaultSearchProviderSuggestURL, suggest_url); + + const std::wstring name = + t_url ? t_url->short_name() : std::wstring(); + prefs->SetString(prefs::kDefaultSearchProviderName, name); + + const std::wstring id_string = + t_url ? Int64ToWString(t_url->id()) : std::wstring(); + prefs->SetString(prefs::kDefaultSearchProviderID, id_string); + + prefs->ScheduleSavePersistentPrefs(g_browser_process->file_thread()); +} + +bool TemplateURLModel::LoadDefaultSearchProviderFromPrefs( + TemplateURL** default_provider) { + PrefService* prefs = GetPrefs(); + if (!prefs || !prefs->HasPrefPath(prefs::kDefaultSearchProviderSearchURL) || + !prefs->HasPrefPath(prefs::kDefaultSearchProviderSuggestURL) || + !prefs->HasPrefPath(prefs::kDefaultSearchProviderName) || + !prefs->HasPrefPath(prefs::kDefaultSearchProviderID)) { + return false; + } + RegisterPrefs(prefs); + + std::wstring suggest_url = + prefs->GetString(prefs::kDefaultSearchProviderSuggestURL); + std::wstring search_url = + prefs->GetString(prefs::kDefaultSearchProviderSearchURL); + + if (suggest_url.empty() && search_url.empty()) { + // The user doesn't want a default search provider. + *default_provider = NULL; + return true; + } + + std::wstring name = prefs->GetString(prefs::kDefaultSearchProviderName); + + std::wstring id_string = prefs->GetString(prefs::kDefaultSearchProviderID); + + *default_provider = new TemplateURL(); + (*default_provider)->set_short_name(name); + (*default_provider)->SetURL(search_url, 0, 0); + (*default_provider)->SetSuggestionsURL(suggest_url, 0, 0); + if (!id_string.empty()) + (*default_provider)->set_id(StringToInt64(id_string)); + return true; +} + +void TemplateURLModel::RegisterPrefs(PrefService* prefs) { + if (prefs->IsPrefRegistered(prefs::kDefaultSearchProviderName)) + return; + prefs->RegisterStringPref( + prefs::kDefaultSearchProviderName, std::wstring()); + prefs->RegisterStringPref( + prefs::kDefaultSearchProviderID, std::wstring()); + prefs->RegisterStringPref( + prefs::kDefaultSearchProviderSuggestURL, std::wstring()); + prefs->RegisterStringPref( + prefs::kDefaultSearchProviderSearchURL, std::wstring()); +} + +bool TemplateURLModel::CanReplaceKeywordForHost( + const std::string& host, + const TemplateURL** to_replace) { + const HostToURLsMap::iterator matching_urls = host_to_urls_map_.find(host); + const bool have_matching_urls = (matching_urls != host_to_urls_map_.end()); + if (have_matching_urls) { + TemplateURLSet& urls = matching_urls->second; + for (TemplateURLSet::iterator i = urls.begin(); i != urls.end(); ++i) { + const TemplateURL* url = *i; + if (CanReplace(url)) { + if (to_replace) + *to_replace = url; + return true; + } + } + } + + if (to_replace) + *to_replace = NULL; + return !have_matching_urls; +} + +bool TemplateURLModel::CanReplace(const TemplateURL* t_url) { + return (t_url != default_search_provider_ && !t_url->show_in_default_list() && + t_url->safe_for_autoreplace()); +} + +PrefService* TemplateURLModel::GetPrefs() { + return profile_ ? profile_->GetPrefs() : NULL; +} + +void TemplateURLModel::UpdateKeywordSearchTermsForURL( + const history::URLRow& row) { + if (!row.url().is_valid() || + !row.url().parsed_for_possibly_invalid_spec().query.is_nonempty()) { + return; + } + + HostToURLsMap::const_iterator t_urls_for_host_iterator = + host_to_urls_map_.find(row.url().host()); + if (t_urls_for_host_iterator == host_to_urls_map_.end() || + t_urls_for_host_iterator->second.empty()) { + return; + } + + const TemplateURLSet& urls_for_host = t_urls_for_host_iterator->second; + QueryTerms query_terms; + bool built_terms = false; // Most URLs won't match a TemplateURLs host; + // so we lazily build the query_terms. + const std::string path = row.url().path(); + + for (TemplateURLSet::const_iterator i = urls_for_host.begin(); + i != urls_for_host.end(); ++i) { + const TemplateURLRef* search_ref = (*i)->url(); + + // Count the URL against a TemplateURL if the host and path of the + // visited URL match that of the TemplateURL as well as the search term's + // key of the TemplateURL occurring in the visited url. + // + // NOTE: Even though we're iterating over TemplateURLs indexed by the host + // of the URL we still need to call GetHost on the search_ref. In + // particular, GetHost returns an empty string if search_ref doesn't support + // replacement or isn't valid for use in keyword search terms. + + if (search_ref && search_ref->GetHost() == row.url().host() && + search_ref->GetPath() == path) { + if (!built_terms && !BuildQueryTerms(row.url(), &query_terms)) { + // No query terms. No need to continue with the rest of the + // TemplateURLs. + return; + } + built_terms = true; + + QueryTerms::iterator terms_iterator = + query_terms.find(search_ref->GetSearchTermKey()); + if (terms_iterator != query_terms.end() && + !terms_iterator->second.empty()) { + SetKeywordSearchTermsForURL( + *i, row.url(), search_ref->SearchTermToWide(*(*i), + terms_iterator->second)); + } + } + } +} + +// static +bool TemplateURLModel::BuildQueryTerms(const GURL& url, + QueryTerms* query_terms) { + url_parse::Component query = url.parsed_for_possibly_invalid_spec().query; + url_parse::Component key, value; + size_t valid_term_count = 0; + while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key, + &value)) { + if (key.is_nonempty() && value.is_nonempty()) { + std::string key_string = url.spec().substr(key.begin, key.len); + std::string value_string = url.spec().substr(value.begin, value.len); + QueryTerms::iterator query_terms_iterator = + query_terms->find(key_string); + if (query_terms_iterator != query_terms->end()) { + if (!query_terms_iterator->second.empty() && + query_terms_iterator->second != value_string) { + // The term occurs in multiple places with different values. Treat + // this as if the term doesn't occur by setting the value to an empty + // string. + (*query_terms)[key_string] = std::string(); + DCHECK (valid_term_count > 0); + valid_term_count--; + } + } else { + valid_term_count++; + (*query_terms)[key_string] = value_string; + } + } + } + return (valid_term_count > 0); +} + +void TemplateURLModel::GoogleBaseURLChanged() { + bool something_changed = false; + for (size_t i = 0; i < template_urls_.size(); ++i) { + const TemplateURL* t_url = template_urls_[i]; + if ((t_url->url() && t_url->url()->HasGoogleBaseURLs()) || + (t_url->suggestions_url() && + t_url->suggestions_url()->HasGoogleBaseURLs())) { + RemoveFromMapsByPointer(t_url); + t_url->InvalidateCachedValues(); + AddToMaps(t_url); + something_changed = true; + } + } + + if (something_changed && loaded_) { + FOR_EACH_OBSERVER(TemplateURLModelObserver, model_observers_, + OnTemplateURLModelChanged()); + } +} diff --git a/chrome/browser/template_url_model.h b/chrome/browser/template_url_model.h new file mode 100644 index 0000000..6b9569b --- /dev/null +++ b/chrome/browser/template_url_model.h @@ -0,0 +1,348 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TEMPLATE_URL_MODEL_H__ +#define CHROME_BROWSER_TEMPLATE_URL_MODEL_H__ + +#include <map> +#include <string> +#include <vector> + +#include "base/observer_list.h" +#include "chrome/browser/history/history_notifications.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/webdata/web_data_service.h" +#include "chrome/common/notification_service.h" + +class GURL; +class PrefService; +class Profile; +class TemplateURL; +class TemplateURLModelTest; + +// TemplateURLModel is the backend for keywords. It's used by +// KeywordAutocomplete. +// +// TemplateURLModel stores a vector of TemplateURLs. The TemplateURLs are +// persisted to the database maintained by WebDataService. *ALL* mutations +// to the TemplateURLs must funnel through TemplateURLModel. This allows +// TemplateURLModel to notify listeners of changes as well as keep the +// database in sync. +// +// There is a TemplateURLModel per Profile. +// +// TemplateURLModel does not load the vector of TemplateURLs in it's +// constructor (except for testing). Use the Load method to trigger a load. +// When TemplateURLModel has completed loading, observers are notified via +// OnTemplateURLModelChanged as well as the TEMPLATE_URL_MODEL_LOADED +// notification message. +// +// TemplateURLModel takes ownership of any TemplateURL passed to it. If there +// is a WebDataService, deletion is handled by WebDataService, otherwise +// TemplateURLModel handles deletion. + +// TemplateURLModelObserver is notified whenever the set of TemplateURLs +// are modified. +class TemplateURLModelObserver { + public: + // Notification that the template url model has changed in some way. + virtual void OnTemplateURLModelChanged() = 0; +}; + +class TemplateURLModel : public WebDataServiceConsumer, + public NotificationObserver { + public: + typedef std::map<std::string, std::string> QueryTerms; + + // Struct used for initializing the data store with fake data. + // Each initializer is mapped to a TemplateURL. + struct Initializer { + const wchar_t* const keyword; + const wchar_t* const url; + const wchar_t* const content; + }; + + explicit TemplateURLModel(Profile* profile); + // The following is for testing. + TemplateURLModel(const Initializer* initializers, const int count); + + ~TemplateURLModel(); + + // Generates a suitable keyword for the specified url. Returns an empty + // string if a keyword couldn't be generated. If |autodetected| is true, we + // don't generate keywords for a variety of situations where we would probably + // not want to auto-add keywords, such as keywords for searches on pages that + // themselves come from form submissions. + static std::wstring GenerateKeyword(const GURL& url, bool autodetected); + + // Removes any unnecessary characters from a user input keyword. + // This removes the leading scheme, "www." and any trailing slash. + static std::wstring CleanUserInputKeyword(const std::wstring& keyword); + + // Returns the search url for t_url. Returns an empty GURL if t_url has no + // url(). + static GURL GenerateSearchURL(const TemplateURL* t_url); + + // Returns true if there is no TemplateURL that conflicts with the + // keyword/url pair, or there is one but it can be replaced. If there is an + // existing keyword that can be replaced and template_url_to_replace is + // non-NULL, template_url_to_replace is set to the keyword to replace. + // + // url gives the url of the search query. The url is used to avoid generating + // a TemplateURL for an existing TemplateURL that shares the same host. + bool CanReplaceKeyword(const std::wstring& keyword, + const std::wstring& url, + const TemplateURL** template_url_to_replace); + + // Returns (in |matches|) all keywords beginning with |prefix|, sorted + // shortest-first. If support_replacement_only is true, only keywords that + // support replacement are returned. + void FindMatchingKeywords(const std::wstring& prefix, + bool support_replacement_only, + std::vector<std::wstring>* matches) const; + + // Looks up |keyword| and returns the element it maps to. Returns NULL if + // the keyword was not found. + // The caller should not try to delete the returned pointer; the data store + // retains ownership of it. + const TemplateURL* GetTemplateURLForKeyword( + const std::wstring& keyword) const; + + // Returns the first TemplateURL found with a URL using the specified |host|, + // or NULL if there are no such TemplateURLs + const TemplateURL* GetTemplateURLForHost(const std::string& host) const; + + // Adds a new TemplateURL to this model. TemplateURLModel will own the + // reference, and delete it when the TemplateURL is removed. + void Add(TemplateURL* template_url); + + // Removes the keyword from the model. This deletes the supplied TemplateURL. + // This fails if the supplied template_url is the default search provider. + void Remove(const TemplateURL* template_url); + + // Removes all auto-generated keywords that were created in the specified + // range. + void RemoveAutoGeneratedBetween(base::Time created_after, base::Time created_before); + + // Replaces existing_turl with new_turl. new_turl is given the same ID as + // existing_turl. If existing_turl was the default, new_turl is made the + // default. After this call existing_turl is deleted. As with Add, + // TemplateURLModel takes ownership of existing_turl. + void Replace(const TemplateURL* existing_turl, + TemplateURL* new_turl); + + // Removes all auto-generated keywords that were created on or after the + // date passed in. + void RemoveAutoGeneratedSince(base::Time created_after); + + // Returns the set of URLs describing the keywords. The elements are owned + // by TemplateURLModel and should not be deleted. + std::vector<const TemplateURL*> GetTemplateURLs() const; + + // Increment the usage count of a keyword. + // Called when a URL is loaded that was generated from a keyword. + void IncrementUsageCount(const TemplateURL* url); + + // Resets the title, keyword and search url of the specified TemplateURL. + // The TemplateURL is marked as not replaceable. + void ResetTemplateURL(const TemplateURL* url, + const std::wstring& title, + const std::wstring& keyword, + const std::wstring& search_url); + + // The default search provider. This may be null. + void SetDefaultSearchProvider(const TemplateURL* url); + + // Returns the default search provider. If the TemplateURLModel hasn't been + // loaded, the default search provider is pulled from preferences. + // + // NOTE: At least in unittest mode, this may return NULL. + const TemplateURL* GetDefaultSearchProvider(); + + // Observers used to listen for changes to the model. + // TemplateURLModel does NOT delete the observers when deleted. + void AddObserver(TemplateURLModelObserver* observer); + void RemoveObserver(TemplateURLModelObserver* observer); + + // Loads the keywords. This has no effect if the keywords have already been + // loaded. + // Observers are notified when loading completes via the method + // OnTemplateURLsReset. + void Load(); + + // Whether or not the keywords have been loaded. + bool loaded() { return loaded_; } + + // Notification that the keywords have been loaded. + // This is invoked from WebDataService, and should not be directly + // invoked. + virtual void OnWebDataServiceRequestDone(WebDataService::Handle h, + const WDTypedResult* result); + + // Removes (and deletes) TemplateURLs from |urls| that have duplicate + // prepopulate ids. Duplicate prepopulate ids are not allowed, but due to a + // bug it was possible get dups. This step is only called when the version + // number changes. + void RemoveDuplicatePrepopulateIDs(std::vector<const TemplateURL*>* urls); + + // NotificationObserver method. TemplateURLModel listens for three + // notification types: + // . NOTIFY_HISTORY_URL_VISITED: adds keyword search terms if the visit + // corresponds to a keyword. + // . NOTIFY_GOOGLE_URL_UPDATED: updates mapping for any keywords containing + // a google base url replacement term. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + Profile* profile() const { return profile_; } + + protected: + // Cover method for the method of the same name on the HistoryService. + // url is the one that was visited with the given search terms. + // + // This exists and is virtual for testing. + virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url, + const GURL& url, + const std::wstring& term); + + private: + FRIEND_TEST(TemplateURLModelTest, BuildQueryTerms); + FRIEND_TEST(TemplateURLModelTest, UpdateKeywordSearchTermsForURL); + FRIEND_TEST(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable); + FRIEND_TEST(TemplateURLModelTest, ChangeGoogleBaseValue); + friend class TemplateURLModelTest; + + typedef std::map<std::wstring, const TemplateURL*> KeywordToTemplateMap; + typedef std::vector<const TemplateURL*> TemplateURLVector; + + // Helper functor for FindMatchingKeywords(), for finding the range of + // keywords which begin with a prefix. + class LessWithPrefix; + + void Init(const Initializer* initializers, int num_initializers); + + void RemoveFromMaps(const TemplateURL* template_url); + + // Removes the supplied template_url from the maps. This searches through all + // entries in the maps and does not generate the host or keyword. + // This is used when the cached content of the TemplateURL changes. + void RemoveFromMapsByPointer(const TemplateURL* template_url); + + void AddToMaps(const TemplateURL* template_url); + + // Sets the keywords. This is used once the keywords have been loaded. + // This does NOT notify the delegate or the database. + void SetTemplateURLs(const std::vector<const TemplateURL*>& urls); + + void DeleteGeneratedKeywordsMatchingHost(const std::wstring& host); + + // If there is a notification service, sends TEMPLATE_URL_MODEL_LOADED + // notification. + void NotifyLoaded(); + + // Loads engines from prepopulate data and merges them in with the existing + // engines. This is invoked when the version of the prepopulate data changes. + void MergeEnginesFromPrepopulateData(); + + // Saves enough of url to preferences so that it can be loaded from + // preferences on start up. + void SaveDefaultSearchProviderToPrefs(const TemplateURL* url); + + // Creates a TemplateURL that was previously saved to prefs via + // SaveDefaultSearchProviderToPrefs. Returns true if successful, false + // otherwise. This is used if GetDefaultSearchProvider is invoked before the + // TemplateURL has loaded. If the user has opted for no default search, this + // returns true but default_provider is set to NULL. + bool LoadDefaultSearchProviderFromPrefs(TemplateURL** default_provider); + + // Registers the preferences used to save a TemplateURL to prefs. + void RegisterPrefs(PrefService* prefs); + + // Returns true if there is no TemplateURL that has a search url with the + // specified host, or the only TemplateURLs matching the specified host can + // be replaced. + bool CanReplaceKeywordForHost(const std::string& host, + const TemplateURL** to_replace); + + // Returns true if the TemplateURL is replaceable. This doesn't look at the + // uniqueness of the keyword or host and is intended to be called after those + // checks have been done. This returns true if the TemplateURL doesn't appear + // in the default list and is marked as safe_for_autoreplace. + bool CanReplace(const TemplateURL* t_url); + + // Returns the preferences we use. + PrefService* GetPrefs(); + + // Iterates through the TemplateURLs to see if one matches the visited url. + // For each TemplateURL whose url matches the visited url + // SetKeywordSearchTermsForURL is invoked. + void UpdateKeywordSearchTermsForURL(const history::URLRow& row); + + // Adds each of the query terms in the specified url whose key and value are + // non-empty to query_terms. If a query key appears multiple times, the value + // is set to an empty string. Returns true if there is at least one key that + // does not occur multiple times. + static bool BuildQueryTerms( + const GURL& url, + std::map<std::string,std::string>* query_terms); + + // Invoked when the Google base URL has changed. Updates the mapping for all + // TemplateURLs that have a replacement term of {google:baseURL} or + // {google:baseSuggestURL}. + void GoogleBaseURLChanged(); + + // Mapping from keyword to the TemplateURL. + KeywordToTemplateMap keyword_to_template_map_; + + TemplateURLVector template_urls_; + + ObserverList<TemplateURLModelObserver> model_observers_; + + // Maps from host to set of TemplateURLs whose search url host is host. + typedef std::set<const TemplateURL*> TemplateURLSet; + typedef std::map<std::string, TemplateURLSet> HostToURLsMap; + HostToURLsMap host_to_urls_map_; + + // Used to obtain the WebDataService. + // When Load is invoked, if we haven't yet loaded, the WebDataService is + // obtained from the Profile. This allows us to lazily access the database. + Profile* profile_; + + // Whether the keywords have been loaded. + bool loaded_; + + // If non-zero, we're waiting on a load. + WebDataService::Handle load_handle_; + + // Service used to store entries. + scoped_refptr<WebDataService> service_; + + // List of hosts to feed to DeleteGeneratedKeywordsMatchingHost. When + // we receive NOTIFY_HOST_DELETED_FROM_HISTORY if we haven't loaded yet, + // we force a load and add the host to hosts_to_delete_. When done loading + // we invoke DeleteGeneratedKeywordsMatchingHost with all the elements of + // the vector. + std::vector<std::wstring> hosts_to_delete_; + + // All visits that occurred before we finished loading. Once loaded + // UpdateKeywordSearchTermsForURL is invoked for each element of the vector. + std::vector<history::URLRow> visits_to_add_; + + const TemplateURL* default_search_provider_; + + // The default search provider from preferences. This is only valid if + // GetDefaultSearchProvider is invoked and we haven't been loaded. Once loaded + // this is not used. + scoped_ptr<TemplateURL> prefs_default_search_provider_; + + // ID assigned to next TemplateURL added to this model. This is an ever + // increasing integer that is initialized from the database. + TemplateURL::IDType next_id_; + + DISALLOW_EVIL_CONSTRUCTORS(TemplateURLModel); +}; + +#endif // CHROME_BROWSER_TEMPLATE_URL_MODEL_H__ + diff --git a/chrome/browser/template_url_model_unittest.cc b/chrome/browser/template_url_model_unittest.cc new file mode 100644 index 0000000..b5198e4 --- /dev/null +++ b/chrome/browser/template_url_model_unittest.cc @@ -0,0 +1,633 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" +#include "chrome/common/pref_service.h" +#include "chrome/test/testing_profile.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::Time; +using base::TimeDelta; + +// A Task used to coordinate when the database has finished processing +// requests. See note in BlockTillServiceProcessesRequests for details. +// +// When Run() schedules a QuitTask on the message loop it was created with. +class QuitTask2 : public Task { + public: + QuitTask2() : main_loop_(MessageLoop::current()) {} + + virtual void Run() { + main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + } + + private: + MessageLoop* main_loop_; +}; + +// Subclass the TestingProfile so that it can return a WebDataService. +class TemplateURLModelTestingProfile : public TestingProfile { + public: + TemplateURLModelTestingProfile() : TestingProfile() { } + + void SetUp() { + // Name a subdirectory of the temp directory. + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_)); + file_util::AppendToPath(&test_dir_, L"TemplateURLModelTest"); + + // Create a fresh, empty copy of this directory. + file_util::Delete(test_dir_, true); + file_util::CreateDirectory(test_dir_); + + std::wstring path = test_dir_; + file_util::AppendToPath(&path, L"TestDataService.db"); + service_ = new WebDataService; + EXPECT_TRUE(service_->InitWithPath(path)); + } + + void TearDown() { + // Clean up the test directory. + service_->Shutdown(); + ASSERT_TRUE(file_util::Delete(test_dir_, true)); + ASSERT_FALSE(file_util::PathExists(test_dir_)); + } + + virtual WebDataService* GetWebDataService(ServiceAccessType access) { + return service_.get(); + } + + private: + scoped_refptr<WebDataService> service_; + std::wstring test_dir_; +}; + +// Trivial subclass of TemplateURLModel that records the last invocation of +// SetKeywordSearchTermsForURL. +class TestingTemplateURLModel : public TemplateURLModel { + public: + explicit TestingTemplateURLModel(Profile* profile) + : TemplateURLModel(profile) { + } + + std::wstring GetAndClearSearchTerm() { + std::wstring search_term; + search_term.swap(search_term_); + return search_term; + } + + protected: + virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url, + const GURL& url, + const std::wstring& term) { + search_term_ = term; + } + + private: + std::wstring search_term_; + + DISALLOW_EVIL_CONSTRUCTORS(TestingTemplateURLModel); +}; + +class TemplateURLModelTest : public testing::Test, + public TemplateURLModelObserver { + public: + TemplateURLModelTest() : changed_count_(0) { + } + + virtual void SetUp() { + profile_.reset(new TemplateURLModelTestingProfile()); + profile_->SetUp(); + model_.reset(new TestingTemplateURLModel(profile_.get())); + model_->AddObserver(this); + } + + virtual void TearDown() { + profile_->TearDown(); + delete TemplateURLRef::google_base_url_; + TemplateURLRef::google_base_url_ = NULL; + + // Flush the message loop to make Purify happy. + message_loop_.RunAllPending(); + } + + TemplateURL* AddKeywordWithDate(const std::wstring& keyword, + bool autogenerate_keyword, + const std::wstring& url, + const std::wstring& short_name, + bool safe_for_autoreplace, + Time created_date) { + TemplateURL* template_url = new TemplateURL(); + template_url->SetURL(url, 0, 0); + template_url->set_keyword(keyword); + template_url->set_autogenerate_keyword(autogenerate_keyword); + template_url->set_short_name(short_name); + template_url->set_date_created(created_date); + template_url->set_safe_for_autoreplace(safe_for_autoreplace); + model_->Add(template_url); + EXPECT_NE(0, template_url->id()); + return template_url; + } + + virtual void OnTemplateURLModelChanged() { + changed_count_++; + } + + void VerifyObserverCount(int expected_changed_count) { + ASSERT_EQ(expected_changed_count, changed_count_); + changed_count_ = 0; + } + + // Blocks the caller until the service has finished servicing all pending + // requests. + void BlockTillServiceProcessesRequests() { + // Schedule a task on the background thread that is processed after all + // pending requests on the background thread. + profile_->GetWebDataService(Profile::EXPLICIT_ACCESS)->thread()-> + message_loop()->PostTask(FROM_HERE, new QuitTask2()); + // Run the current message loop. QuitTask2, when run, invokes Quit, + // which unblocks this. + MessageLoop::current()->Run(); + } + + // Makes sure the load was successful and sent the correct notification. + void VerifyLoad() { + ASSERT_FALSE(model_->loaded()); + model_->Load(); + BlockTillServiceProcessesRequests(); + VerifyObserverCount(1); + changed_count_ = 0; + } + + // Creates a new TemplateURLModel. + void ResetModel(bool verify_load) { + model_.reset(new TestingTemplateURLModel(profile_.get())); + model_->AddObserver(this); + changed_count_ = 0; + if (verify_load) + VerifyLoad(); + } + + // Verifies the two TemplateURLs are equal. + void AssertEquals(const TemplateURL& expected, const TemplateURL& actual) { + ASSERT_EQ(expected.url()->url(), actual.url()->url()); + ASSERT_EQ(expected.keyword(), actual.keyword()); + ASSERT_EQ(expected.short_name(), actual.short_name()); + ASSERT_TRUE(expected.GetFavIconURL() == actual.GetFavIconURL()); + ASSERT_EQ(expected.id(), actual.id()); + ASSERT_EQ(expected.safe_for_autoreplace(), actual.safe_for_autoreplace()); + ASSERT_EQ(expected.show_in_default_list(), actual.show_in_default_list()); + ASSERT_TRUE(expected.date_created() == actual.date_created()); + } + + std::wstring GetAndClearSearchTerm() { + return model_->GetAndClearSearchTerm(); + } + + void SetGoogleBaseURL(const std::wstring& base_url) const { + delete TemplateURLRef::google_base_url_; + TemplateURLRef::google_base_url_ = new std::wstring(base_url); + } + + MessageLoopForUI message_loop_; + scoped_ptr<TemplateURLModelTestingProfile> profile_; + scoped_ptr<TestingTemplateURLModel> model_; + int changed_count_; +}; + +TEST_F(TemplateURLModelTest, Load) { + VerifyLoad(); +} + +TEST_F(TemplateURLModelTest, AddUpdateRemove) { + // Add a new TemplateURL. + VerifyLoad(); + const size_t initial_count = model_->GetTemplateURLs().size(); + + TemplateURL* t_url = new TemplateURL(); + t_url->SetURL(L"http://www.google.com/foo/bar", 0, 0); + t_url->set_keyword(L"keyword"); + t_url->set_short_name(L"google"); + GURL favicon_url("http://favicon.url"); + t_url->SetFavIconURL(favicon_url); + t_url->set_date_created(Time::FromTimeT(100)); + t_url->set_safe_for_autoreplace(true); + model_->Add(t_url); + ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", std::wstring(), NULL)); + VerifyObserverCount(1); + BlockTillServiceProcessesRequests(); + // We need to clone as model takes ownership of TemplateURL and will + // delete it. + TemplateURL cloned_url(*t_url); + ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size()); + ASSERT_TRUE(model_->GetTemplateURLForKeyword(t_url->keyword()) == t_url); + ASSERT_TRUE(t_url->date_created() == cloned_url.date_created()); + + // Reload the model to verify it was actually saved to the database. + ResetModel(true); + ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size()); + const TemplateURL* loaded_url = model_->GetTemplateURLForKeyword(L"keyword"); + ASSERT_TRUE(loaded_url != NULL); + AssertEquals(cloned_url, *loaded_url); + ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", std::wstring(), NULL)); + + // Mutate an element and verify it succeeded. + model_->ResetTemplateURL(loaded_url, L"a", L"b", L"c"); + ASSERT_EQ(L"a", loaded_url->short_name()); + ASSERT_EQ(L"b", loaded_url->keyword()); + ASSERT_EQ(L"c", loaded_url->url()->url()); + ASSERT_FALSE(loaded_url->safe_for_autoreplace()); + ASSERT_TRUE(model_->CanReplaceKeyword(L"keyword", std::wstring(), NULL)); + ASSERT_FALSE(model_->CanReplaceKeyword(L"b", std::wstring(), NULL)); + cloned_url = *loaded_url; + BlockTillServiceProcessesRequests(); + ResetModel(true); + ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size()); + loaded_url = model_->GetTemplateURLForKeyword(L"b"); + ASSERT_TRUE(loaded_url != NULL); + AssertEquals(cloned_url, *loaded_url); + + // Remove an element and verify it succeeded. + model_->Remove(loaded_url); + VerifyObserverCount(1); + ResetModel(true); + ASSERT_EQ(initial_count, model_->GetTemplateURLs().size()); + EXPECT_TRUE(model_->GetTemplateURLForKeyword(L"b") == NULL); +} + +TEST_F(TemplateURLModelTest, GenerateKeyword) { + ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL(), true)); + // Shouldn't generate keywords for https. + ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("https://blah"), true)); + ASSERT_EQ(L"foo", TemplateURLModel::GenerateKeyword(GURL("http://foo"), + true)); + // www. should be stripped. + ASSERT_EQ(L"foo", TemplateURLModel::GenerateKeyword(GURL("http://www.foo"), + true)); + // Shouldn't generate keywords with paths, if autodetected. + ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"), + true)); + ASSERT_EQ(L"blah", TemplateURLModel::GenerateKeyword(GURL("http://blah/foo"), + false)); + // FTP shouldn't generate a keyword. + ASSERT_EQ(L"", TemplateURLModel::GenerateKeyword(GURL("ftp://blah/"), true)); + // Make sure we don't get a trailing / + ASSERT_EQ(L"blah", TemplateURLModel::GenerateKeyword(GURL("http://blah/"), + true)); +} + +TEST_F(TemplateURLModelTest, ClearBrowsingData_Keywords) { + Time now = Time::Now(); + TimeDelta one_day = TimeDelta::FromDays(1); + Time month_ago = now - TimeDelta::FromDays(30); + + // Nothing has been added. + EXPECT_EQ(0U, model_->GetTemplateURLs().size()); + + // Create one with a 0 time. + AddKeywordWithDate(L"key1", false, L"http://foo1", L"name1", true, Time()); + // Create one for now and +/- 1 day. + AddKeywordWithDate(L"key2", false, L"http://foo2", L"name2", true, + now - one_day); + AddKeywordWithDate(L"key3", false, L"http://foo3", L"name3", true, now); + AddKeywordWithDate(L"key4", false, L"http://foo4", L"name4", true, + now + one_day); + // Try the other three states. + AddKeywordWithDate(L"key5", false, L"http://foo5", L"name5", false, now); + AddKeywordWithDate(L"key6", false, L"http://foo6", L"name6", false, month_ago); + + // We just added a few items, validate them. + EXPECT_EQ(6U, model_->GetTemplateURLs().size()); + + // Try removing from current timestamp. This should delete the one in the + // future and one very recent one. + model_->RemoveAutoGeneratedSince(now); + EXPECT_EQ(4U, model_->GetTemplateURLs().size()); + + // Try removing from two months ago. This should only delete items that are + // auto-generated. + model_->RemoveAutoGeneratedSince(now - TimeDelta::FromDays(60)); + EXPECT_EQ(3U, model_->GetTemplateURLs().size()); + + // Make sure the right values remain. + EXPECT_EQ(L"key1", model_->GetTemplateURLs()[0]->keyword()); + EXPECT_TRUE(model_->GetTemplateURLs()[0]->safe_for_autoreplace()); + EXPECT_EQ(0U, model_->GetTemplateURLs()[0]->date_created().ToInternalValue()); + + EXPECT_EQ(L"key5", model_->GetTemplateURLs()[1]->keyword()); + EXPECT_FALSE(model_->GetTemplateURLs()[1]->safe_for_autoreplace()); + EXPECT_EQ(now.ToInternalValue(), + model_->GetTemplateURLs()[1]->date_created().ToInternalValue()); + + EXPECT_EQ(L"key6", model_->GetTemplateURLs()[2]->keyword()); + EXPECT_FALSE(model_->GetTemplateURLs()[2]->safe_for_autoreplace()); + EXPECT_EQ(month_ago.ToInternalValue(), + model_->GetTemplateURLs()[2]->date_created().ToInternalValue()); + + // Try removing from Time=0. This should delete one more. + model_->RemoveAutoGeneratedSince(Time()); + EXPECT_EQ(2U, model_->GetTemplateURLs().size()); +} + +TEST_F(TemplateURLModelTest, Reset) { + // Add a new TemplateURL. + VerifyLoad(); + const size_t initial_count = model_->GetTemplateURLs().size(); + TemplateURL* t_url = new TemplateURL(); + t_url->SetURL(L"http://www.google.com/foo/bar", 0, 0); + t_url->set_keyword(L"keyword"); + t_url->set_short_name(L"google"); + GURL favicon_url("http://favicon.url"); + t_url->SetFavIconURL(favicon_url); + t_url->set_date_created(Time::FromTimeT(100)); + model_->Add(t_url); + + VerifyObserverCount(1); + BlockTillServiceProcessesRequests(); + + // Reset the short name, keyword, url and make sure it takes. + const std::wstring new_short_name(L"a"); + const std::wstring new_keyword(L"b"); + const std::wstring new_url(L"c"); + model_->ResetTemplateURL(t_url, new_short_name, new_keyword, new_url); + ASSERT_EQ(new_short_name, t_url->short_name()); + ASSERT_EQ(new_keyword, t_url->keyword()); + ASSERT_EQ(new_url, t_url->url()->url()); + + // Make sure the mappings in the model were updated. + ASSERT_TRUE(model_->GetTemplateURLForKeyword(new_keyword) == t_url); + ASSERT_TRUE(model_->GetTemplateURLForKeyword(L"keyword") == NULL); + + TemplateURL last_url = *t_url; + + // Reload the model from the database and make sure the change took. + ResetModel(true); + t_url = NULL; + EXPECT_EQ(initial_count + 1, model_->GetTemplateURLs().size()); + const TemplateURL* read_url = model_->GetTemplateURLForKeyword(new_keyword); + ASSERT_TRUE(read_url); + AssertEquals(last_url, *read_url); +} + +TEST_F(TemplateURLModelTest, DefaultSearchProvider) { + // Add a new TemplateURL. + VerifyLoad(); + const size_t initial_count = model_->GetTemplateURLs().size(); + TemplateURL* t_url = AddKeywordWithDate(L"key1", false, L"http://foo1", + L"name1", true, Time()); + + changed_count_ = 0; + model_->SetDefaultSearchProvider(t_url); + + ASSERT_EQ(t_url, model_->GetDefaultSearchProvider()); + + ASSERT_TRUE(t_url->safe_for_autoreplace()); + ASSERT_TRUE(t_url->show_in_default_list()); + + // Setting the default search provider should have caused notification. + VerifyObserverCount(1); + + BlockTillServiceProcessesRequests(); + + TemplateURL cloned_url = *t_url; + + ResetModel(true); + t_url = NULL; + + // Make sure when we reload we get a default search provider. + EXPECT_EQ(1 + initial_count, model_->GetTemplateURLs().size()); + ASSERT_TRUE(model_->GetDefaultSearchProvider()); + AssertEquals(cloned_url, *model_->GetDefaultSearchProvider()); +} + +TEST_F(TemplateURLModelTest, TemplateURLWithNoKeyword) { + VerifyLoad(); + + const size_t initial_count = model_->GetTemplateURLs().size(); + + AddKeywordWithDate(std::wstring(), false, L"http://foo1", L"name1", true, + Time()); + + // We just added a few items, validate them. + ASSERT_EQ(initial_count + 1, model_->GetTemplateURLs().size()); + + // Reload the model from the database and make sure we get the url back. + ResetModel(true); + + ASSERT_EQ(1 + initial_count, model_->GetTemplateURLs().size()); + + bool found_keyword = false; + for (size_t i = 0; i < initial_count + 1; ++i) { + if (model_->GetTemplateURLs()[i]->keyword().empty()) { + found_keyword = true; + break; + } + } + ASSERT_TRUE(found_keyword); +} + +TEST_F(TemplateURLModelTest, CantReplaceWithSameKeyword) { + ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", std::wstring(), NULL)); + TemplateURL* t_url = AddKeywordWithDate(L"foo", false, L"http://foo1", + L"name1", true, Time()); + + // Can still replace, newly added template url is marked safe to replace. + ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", L"http://foo2", NULL)); + + // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should + // no longer be replaceable. + model_->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(), + t_url->url()->url()); + + ASSERT_FALSE(model_->CanReplaceKeyword(L"foo", L"http://foo2", NULL)); +} + +TEST_F(TemplateURLModelTest, CantReplaceWithSameHosts) { + ASSERT_TRUE(model_->CanReplaceKeyword(L"foo", L"http://foo.com", NULL)); + TemplateURL* t_url = AddKeywordWithDate(L"foo", false, L"http://foo.com", + L"name1", true, Time()); + + // Can still replace, newly added template url is marked safe to replace. + ASSERT_TRUE(model_->CanReplaceKeyword(L"bar", L"http://foo.com", NULL)); + + // ResetTemplateURL marks the TemplateURL as unsafe to replace, so it should + // no longer be replaceable. + model_->ResetTemplateURL(t_url, t_url->short_name(), t_url->keyword(), + t_url->url()->url()); + + ASSERT_FALSE(model_->CanReplaceKeyword(L"bar", L"http://foo.com", NULL)); +} + +TEST_F(TemplateURLModelTest, HasDefaultSearchProvider) { + // We should have a default search provider even if we haven't loaded. + ASSERT_TRUE(model_->GetDefaultSearchProvider()); + + // Now force the model to load and make sure we still have a default. + VerifyLoad(); + + ASSERT_TRUE(model_->GetDefaultSearchProvider()); +} + +TEST_F(TemplateURLModelTest, DefaultSearchProviderLoadedFromPrefs) { + VerifyLoad(); + + TemplateURL* template_url = new TemplateURL(); + template_url->SetURL(L"http://url", 0, 0); + template_url->SetSuggestionsURL(L"http://url2", 0, 0); + template_url->set_short_name(L"a"); + template_url->set_safe_for_autoreplace(true); + template_url->set_date_created(Time::FromTimeT(100)); + + model_->Add(template_url); + + const TemplateURL::IDType id = template_url->id(); + + model_->SetDefaultSearchProvider(template_url); + + BlockTillServiceProcessesRequests(); + + TemplateURL first_default_search_provider = *template_url; + + template_url = NULL; + + // Reset the model and don't load it. The template url we set as the default + // should be pulled from prefs now. + ResetModel(false); + + // NOTE: This doesn't use AssertEquals as only a subset of the TemplateURLs + // value are persisted to prefs. + const TemplateURL* default_turl = model_->GetDefaultSearchProvider(); + ASSERT_TRUE(default_turl); + ASSERT_TRUE(default_turl->url()); + ASSERT_EQ(L"http://url", default_turl->url()->url()); + ASSERT_TRUE(default_turl->suggestions_url()); + ASSERT_EQ(L"http://url2", default_turl->suggestions_url()->url()); + ASSERT_EQ(L"a", default_turl->short_name()); + ASSERT_EQ(id, default_turl->id()); + + // Now do a load and make sure the default search provider really takes. + VerifyLoad(); + + ASSERT_TRUE(model_->GetDefaultSearchProvider()); + AssertEquals(first_default_search_provider, + *model_->GetDefaultSearchProvider()); +} + +TEST_F(TemplateURLModelTest, BuildQueryTerms) { + struct TestData { + const std::string url; + const bool result; + // Keys and values are a semicolon separated list of expected values in the + // map. + const std::string keys; + const std::string values; + } data[] = { + // No query should return false. + { "http://blah/", false, "", "" }, + + // Query with empty key should return false. + { "http://blah/foo?=y", false, "", "" }, + + // Query with key occurring multiple times should return false. + { "http://blah/foo?x=y&x=z", false, "", "" }, + + { "http://blah/foo?x=y", true, "x", "y" }, + { "http://blah/foo?x=y&y=z", true, "x;y", "y;z" }, + + // Key occurring multiple times should get an empty string. + { "http://blah/foo?x=y&x=z&y=z", true, "x;y", ";z" }, + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { + TemplateURLModel::QueryTerms terms; + ASSERT_EQ(data[i].result, + TemplateURLModel::BuildQueryTerms(GURL(data[i].url), &terms)); + if (data[i].result) { + std::vector<std::string> keys; + std::vector<std::string> values; + SplitString(data[i].keys, ';', &keys); + SplitString(data[i].values, ';', &values); + ASSERT_TRUE(keys.size() == values.size()); + ASSERT_EQ(keys.size(), terms.size()); + for (size_t j = 0; j < keys.size(); ++j) { + TemplateURLModel::QueryTerms::iterator term_iterator = + terms.find(keys[j]); + ASSERT_TRUE(term_iterator != terms.end()); + ASSERT_EQ(values[j], term_iterator->second); + } + } + } +} + +TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) { + struct TestData { + const std::string url; + const std::wstring term; + } data[] = { + { "http://foo/", L"" }, + { "http://foo/foo?q=xx", L"" }, + { "http://x/bar?q=xx", L"" }, + { "http://x/foo?y=xx", L"" }, + { "http://x/foo?q=xx", L"xx" }, + { "http://x/foo?a=b&q=xx", L"xx" }, + { "http://x/foo?q=b&q=xx", L"" }, + }; + + AddKeywordWithDate(L"x", false, L"http://x/foo?q={searchTerms}", L"name", + false, Time()); + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { + model_->UpdateKeywordSearchTermsForURL(history::URLRow(GURL(data[i].url))); + EXPECT_EQ(data[i].term, GetAndClearSearchTerm()); + } +} + +TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) { + struct TestData { + const std::string url; + } data[] = { + { "http://foo/" }, + { "http://x/bar?q=xx" }, + { "http://x/foo?y=xx" }, + }; + + AddKeywordWithDate(L"x", false, L"http://x/foo", L"name", false, Time()); + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { + model_->UpdateKeywordSearchTermsForURL(history::URLRow(GURL(data[i].url))); + ASSERT_EQ(std::wstring(), GetAndClearSearchTerm()); + } +} + +TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) { + // NOTE: Do not do a VerifyLoad() here as it will load the prepopulate data, + // which also has a {google:baseURL} keyword in it, which will confuse this + // test. + SetGoogleBaseURL(L"http://google.com/"); + const TemplateURL* t_url = AddKeywordWithDate(std::wstring(), true, + L"{google:baseURL}?q={searchTerms}", L"name", false, Time()); + ASSERT_EQ(t_url, model_->GetTemplateURLForHost("google.com")); + EXPECT_EQ("google.com", t_url->url()->GetHost()); + EXPECT_EQ(L"google.com", t_url->keyword()); + + // Change the Google base url. + model_->loaded_ = true; // Hack to make sure we get notified of the base URL + // changing. + SetGoogleBaseURL(L"http://foo.com/"); + model_->GoogleBaseURLChanged(); + VerifyObserverCount(1); + + // Make sure the host->TemplateURL map was updated appropriately. + ASSERT_EQ(t_url, model_->GetTemplateURLForHost("foo.com")); + EXPECT_TRUE(model_->GetTemplateURLForHost("google.com") == NULL); + EXPECT_EQ("foo.com", t_url->url()->GetHost()); + EXPECT_EQ(L"foo.com", t_url->keyword()); + EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url, + L"x", TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()).spec()); +} diff --git a/chrome/browser/template_url_parser.cc b/chrome/browser/template_url_parser.cc new file mode 100644 index 0000000..93f9f79 --- /dev/null +++ b/chrome/browser/template_url_parser.cc @@ -0,0 +1,586 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/template_url_parser.h" + +#include <map> +#include <vector> + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "chrome/browser/template_url.h" +#include "googleurl/src/gurl.h" +#include "libxml/parser.h" +#include "libxml/xmlwriter.h" + +namespace { + +// +// NOTE: libxml uses the UTF-8 encoding. As 0-127 of UTF-8 corresponds +// to that of char, the following names are all in terms of char. This avoids +// having to convert to wide, then do comparisons + +// Defines for element names of the OSD document: +static const char kURLElement[] = "Url"; +static const char kParamElement[] = "Param"; +static const char kShortNameElement[] = "ShortName"; +static const char kDescriptionElement[] = "Description"; +static const char kImageElement[] = "Image"; +static const char kOpenSearchDescriptionElement[] = "OpenSearchDescription"; +static const char kFirefoxSearchDescriptionElement[] = "SearchPlugin"; +static const char kLanguageElement[] = "Language"; +static const char kInputEncodingElement[] = "InputEncoding"; + +// Various XML attributes used. +static const char kURLTypeAttribute[] = "type"; +static const char kURLTemplateAttribute[] = "template"; +static const char kImageTypeAttribute[] = "type"; +static const char kImageWidthAttribute[] = "width"; +static const char kImageHeightAttribute[] = "height"; +static const char kURLIndexOffsetAttribute[] = "indexOffset"; +static const char kURLPageOffsetAttribute[] = "pageOffset"; +static const char kParamNameAttribute[] = "name"; +static const char kParamValueAttribute[] = "value"; +static const char kParamMethodAttribute[] = "method"; + +// Mime type for search results. +static const char kHTMLType[] = "text/html"; + +// Mime type for as you type suggestions. +static const char kSuggestionType[] = "application/x-suggestions+json"; + +// Namespace identifier. +static const char kOSDNS[] = "xmlns"; + +// The namespace for documents we understand. +static const char kNameSpace[] = "http://a9.com/-/spec/opensearch/1.1/"; + +// Removes the namespace from the specified |name|, ex: os:Url -> Url. +static void PruneNamespace(std::string* name) { + size_t index = name->find_first_of(":"); + if (index != std::string::npos) + name->erase(0, index + 1); +} + +// +// To minimize memory overhead while parsing, a SAX style parser is used. +// ParsingContext is used to maintain the state we're in the document +// while parsing. +class ParsingContext { + public: + // Enum of the known element types. + enum ElementType { + UNKNOWN, + OPEN_SEARCH_DESCRIPTION, + URL, + PARAM, + SHORT_NAME, + DESCRIPTION, + IMAGE, + LANGUAGE, + INPUT_ENCODING, + }; + + enum Method { + GET, + POST + }; + + // Key/value of a Param node. + typedef std::pair<std::string, std::string> Param; + + ParsingContext(TemplateURLParser::ParameterFilter* parameter_filter, + TemplateURL* url) + : url_(url), + parameter_filter_(parameter_filter), + method_(GET), + suggestion_method_(GET), + is_suggest_url_(false), + derive_image_from_url_(false) { + if (kElementNameToElementTypeMap == NULL) + InitMapping(); + } + + // Invoked when an element starts. + void PushElement(const std::string& element) { + ElementType type; + if (kElementNameToElementTypeMap->find(element) == + kElementNameToElementTypeMap->end()) { + type = UNKNOWN; + } else { + type = (*kElementNameToElementTypeMap)[element]; + } + elements_.push_back(type); + } + + void PopElement() { + elements_.pop_back(); + } + + // Returns the current ElementType. + ElementType GetKnownType() { + if (elements_.size() == 2 && elements_[0] == OPEN_SEARCH_DESCRIPTION) + return elements_[1]; + + // We only expect PARAM nodes under the Url node + if (elements_.size() == 3 && elements_[0] == OPEN_SEARCH_DESCRIPTION && + elements_[1] == URL && elements_[2] == PARAM) + return PARAM; + + return UNKNOWN; + } + + TemplateURL* template_url() { return url_; } + + void AddImageRef(const std::wstring& type, int width, int height) { + if (width > 0 && height > 0) + current_image_.reset(new TemplateURL::ImageRef(type, width, height)); + } + + void EndImage() { + current_image_.reset(); + } + + void SetImageURL(const std::wstring& url) { + if (current_image_.get()) { + current_image_->url = GURL(WideToUTF8(url)); + url_->add_image_ref(*current_image_); + current_image_.reset(); + } + } + + void ResetString() { + string_.clear(); + } + + void AppendString(const std::wstring& string) { + string_ += string; + } + + const std::wstring& GetString() { + return string_; + } + + void ResetExtraParams() { + extra_params_.clear(); + } + + void AddExtraParams(const std::string& key, const std::string& value) { + if (parameter_filter_ && !parameter_filter_->KeepParameter(key, value)) + return; + extra_params_.push_back(Param(key, value)); + } + + const std::vector<Param>& extra_params() const { return extra_params_; } + + void set_is_suggestion(bool value) { is_suggest_url_ = value; } + bool is_suggestion() const { return is_suggest_url_; } + + TemplateURLParser::ParameterFilter* parameter_filter() const { + return parameter_filter_; + } + + void set_derive_image_from_url(bool derive_image_from_url) { + derive_image_from_url_ = derive_image_from_url; + } + + void set_method(Method method) { method_ = method; } + Method method() { return method_; } + + void set_suggestion_method(Method method) { suggestion_method_ = method; } + Method suggestion_method() { return suggestion_method_; } + + // Builds the image URL from the Template search URL if no image URL has been + // set. + void DeriveImageFromURL() { + if (derive_image_from_url_ && + url_->GetFavIconURL().is_empty() && url_->url()) { + GURL url(WideToUTF8(url_->url()->url())); // More url's please... + url_->SetFavIconURL(TemplateURL::GenerateFaviconURL(url)); + } + } + + private: + static void InitMapping() { + kElementNameToElementTypeMap = new std::map<std::string,ElementType>; + (*kElementNameToElementTypeMap)[kURLElement] = URL; + (*kElementNameToElementTypeMap)[kParamElement] = PARAM; + (*kElementNameToElementTypeMap)[kShortNameElement] = SHORT_NAME; + (*kElementNameToElementTypeMap)[kDescriptionElement] = DESCRIPTION; + (*kElementNameToElementTypeMap)[kImageElement] = IMAGE; + (*kElementNameToElementTypeMap)[kOpenSearchDescriptionElement] = + OPEN_SEARCH_DESCRIPTION; + (*kElementNameToElementTypeMap)[kFirefoxSearchDescriptionElement] = + OPEN_SEARCH_DESCRIPTION; + (*kElementNameToElementTypeMap)[kLanguageElement] = + LANGUAGE; + (*kElementNameToElementTypeMap)[kInputEncodingElement] = + INPUT_ENCODING; + } + + // Key is UTF8 encoded. + static std::map<std::string,ElementType>* kElementNameToElementTypeMap; + // TemplateURL supplied to Read method. It's owned by the caller, so we + // don't need to free it. + TemplateURL* url_; + std::vector<ElementType> elements_; + scoped_ptr<TemplateURL::ImageRef> current_image_; + + // Character content for the current element. + std::wstring string_; + + TemplateURLParser::ParameterFilter* parameter_filter_; + + // The list of parameters parsed in the Param nodes of a Url node. + std::vector<Param> extra_params_; + + // The HTTP methods used. + Method method_; + Method suggestion_method_; + + // If true, we are currently parsing a suggest URL, otherwise it is an HTML + // search. Note that we don't need a stack as Url nodes cannot be nested. + bool is_suggest_url_; + + // Whether we should derive the image from the URL (when images are data + // URLs). + bool derive_image_from_url_; + + DISALLOW_EVIL_CONSTRUCTORS(ParsingContext); +}; + +//static +std::map<std::string,ParsingContext::ElementType>* + ParsingContext::kElementNameToElementTypeMap = NULL; + +std::wstring XMLCharToWide(const xmlChar* value) { + return UTF8ToWide(std::string((const char*)value)); +} + +std::wstring XMLCharToWide(const xmlChar* value, int length) { + return UTF8ToWide(std::string((const char*)value, length)); +} + +std::string XMLCharToString(const xmlChar* value) { + return std::string((const char*)value); +} + +// Returns true if input_encoding contains a valid input encoding string. This +// doesn't verify that we have a valid encoding for the string, just that the +// string contains characters that constitute a valid input encoding. +bool IsValidEncodingString(const std::string& input_encoding) { + if (input_encoding.empty()) + return false; + + if (!IsAsciiAlpha(input_encoding[0])) + return false; + + for (size_t i = 1, max = input_encoding.size(); i < max; ++i) { + char c = input_encoding[i]; + if (!IsAsciiAlpha(c) && !IsAsciiDigit(c) && c != '.' && c != '_' && + c != '-') { + return false; + } + } + return true; +} + +void ParseURL(const xmlChar** atts, ParsingContext* context) { + if (!atts) + return; + + TemplateURL* turl = context->template_url(); + const xmlChar** attributes = atts; + std::wstring template_url; + bool is_post = false; + bool is_html_url = false; + bool is_suggest_url = false; + int index_offset = 1; + int page_offset = 1; + + while (*attributes) { + std::string name(XMLCharToString(*attributes)); + const xmlChar* value = attributes[1]; + if (name == kURLTypeAttribute) { + std::string type = XMLCharToString(value); + is_html_url = (type == kHTMLType); + is_suggest_url = (type == kSuggestionType); + } else if (name == kURLTemplateAttribute) { + template_url = XMLCharToWide(value); + } else if (name == kURLIndexOffsetAttribute) { + index_offset = std::max(1, StringToInt(XMLCharToWide(value))); + } else if (name == kURLPageOffsetAttribute) { + page_offset = std::max(1, StringToInt(XMLCharToWide(value))); + } else if (name == kParamMethodAttribute) { + is_post = LowerCaseEqualsASCII(XMLCharToString(value), "post"); + } + attributes += 2; + } + if (is_html_url) { + turl->SetURL(template_url, index_offset, page_offset); + context->set_is_suggestion(false); + if (is_post) + context->set_method(ParsingContext::POST); + } else if (is_suggest_url) { + turl->SetSuggestionsURL(template_url, index_offset, page_offset); + context->set_is_suggestion(true); + if (is_post) + context->set_suggestion_method(ParsingContext::POST); + } +} + +void ParseImage(const xmlChar** atts, ParsingContext* context) { + if (!atts) + return; + + const xmlChar** attributes = atts; + int width = 0; + int height = 0; + std::wstring type; + while (*attributes) { + std::string name(XMLCharToString(*attributes)); + const xmlChar* value = attributes[1]; + if (name == kImageTypeAttribute) { + type = XMLCharToWide(value); + } else if (name == kImageWidthAttribute) { + width = StringToInt(XMLCharToWide(value)); + } else if (name == kImageHeightAttribute) { + height = StringToInt(XMLCharToWide(value)); + } + attributes += 2; + } + if (width > 0 && height > 0 && !type.empty()) { + // Valid Image URL. + context->AddImageRef(type, width, height); + } +} + +void ParseParam(const xmlChar** atts, ParsingContext* context) { + if (!atts) + return; + + const xmlChar** attributes = atts; + std::wstring type; + std::string key, value; + while (*attributes) { + std::string name(XMLCharToString(*attributes)); + const xmlChar* val = attributes[1]; + if (name == kParamNameAttribute) { + key = XMLCharToString(val); + } else if (name == kParamValueAttribute) { + value = XMLCharToString(val); + } + attributes += 2; + } + if (!key.empty()) + context->AddExtraParams(key, value); +} + +static void AppendParamToQuery(const std::string& key, + const std::string& value, + std::string* query) { + if (!query->empty()) + query->append("&"); + if (!key.empty()) { + query->append(key); + query->append("="); + } + query->append(value); +} + +void ProcessURLParams(ParsingContext* context) { + TemplateURL* t_url = context->template_url(); + const TemplateURLRef* t_url_ref = + context->is_suggestion() ? t_url->suggestions_url() : + t_url->url(); + if (!t_url_ref) + return; + + if (!context->parameter_filter() && context->extra_params().empty()) + return; + + GURL url(WideToUTF8(t_url_ref->url())); + // If there is a parameter filter, parse the existing URL and remove any + // unwanted parameter. + TemplateURLParser::ParameterFilter* filter = context->parameter_filter(); + std::string new_query; + bool modified = false; + if (filter) { + url_parse::Component query = url.parsed_for_possibly_invalid_spec().query; + url_parse::Component key, value; + const char* url_spec = url.spec().c_str(); + while (url_parse::ExtractQueryKeyValue(url_spec, &query, &key, &value)) { + std::string key_str(url_spec, key.begin, key.len); + std::string value_str(url_spec, value.begin, value.len); + if (filter->KeepParameter(key_str, value_str)) { + AppendParamToQuery(key_str, value_str, &new_query); + } else { + modified = true; + } + } + } + if (!modified) + new_query = url.query(); + + // Add the extra parameters if any. + const std::vector<ParsingContext::Param>& params = context->extra_params(); + if (!params.empty()) { + modified = true; + std::vector<ParsingContext::Param>::const_iterator iter; + for (iter = params.begin(); iter != params.end(); ++iter) + AppendParamToQuery(iter->first, iter->second, &new_query); + } + + if (modified) { + GURL::Replacements repl; + repl.SetQueryStr(new_query); + url = url.ReplaceComponents(repl); + if (context->is_suggestion()) { + t_url->SetSuggestionsURL(UTF8ToWide(url.spec()), + t_url_ref->index_offset(), + t_url_ref->page_offset()); + } else { + t_url->SetURL(UTF8ToWide(url.spec()), + t_url_ref->index_offset(), + t_url_ref->page_offset()); + } + } +} + +void StartElementImpl(void *ctx, const xmlChar *name, const xmlChar **atts) { + ParsingContext* context = reinterpret_cast<ParsingContext*>(ctx); + std::string node_name((const char*)name); + PruneNamespace(&node_name); + context->PushElement(node_name); + switch (context->GetKnownType()) { + case ParsingContext::URL: + context->ResetExtraParams(); + ParseURL(atts, context); + break; + case ParsingContext::IMAGE: + ParseImage(atts, context); + break; + case ParsingContext::PARAM: + ParseParam(atts, context); + break; + default: + break; + } + context->ResetString(); +} + +void EndElementImpl(void *ctx, const xmlChar *name) { + ParsingContext* context = reinterpret_cast<ParsingContext*>(ctx); + switch (context->GetKnownType()) { + case ParsingContext::SHORT_NAME: + context->template_url()->set_short_name(context->GetString()); + break; + case ParsingContext::DESCRIPTION: + context->template_url()->set_description(context->GetString()); + break; + case ParsingContext::IMAGE: { + GURL image_url(WideToUTF8(context->GetString())); + if (image_url.SchemeIs("data")) { + // TODO (jcampan): bug 1169256: when dealing with data URL, we need to + // decode the data URL in the renderer. For now, we'll just point to the + // fav icon from the URL. + context->set_derive_image_from_url(true); + } else { + context->SetImageURL(context->GetString()); + } + context->EndImage(); + break; + } + case ParsingContext::LANGUAGE: + context->template_url()->add_language(context->GetString()); + break; + case ParsingContext::INPUT_ENCODING: { + std::string input_encoding = WideToASCII(context->GetString()); + if (IsValidEncodingString(input_encoding)) + context->template_url()->add_input_encoding(input_encoding); + break; + } + case ParsingContext::URL: + ProcessURLParams(context); + break; + default: + break; + } + context->ResetString(); + context->PopElement(); +} + +void CharactersImpl(void *ctx, const xmlChar *ch, int len) { + ParsingContext* context = reinterpret_cast<ParsingContext*>(ctx); + context->AppendString(XMLCharToWide(ch, len)); +} + +// Returns true if the ref is null, or the url wrapped by ref is +// valid with a spec of http/https. +bool IsHTTPRef(const TemplateURLRef* ref) { + if (ref == NULL) + return true; + GURL url(WideToUTF8(ref->url())); + return (url.is_valid() && (url.SchemeIs("http") || url.SchemeIs("https"))); +} + +// Returns true if the TemplateURL is legal. A legal TemplateURL is one +// where all URLs have a spec of http/https. +bool IsLegal(TemplateURL* url) { + if (!IsHTTPRef(url->url()) || !IsHTTPRef(url->suggestions_url())) + return false; + // Make sure all the image refs are legal. + const std::vector<TemplateURL::ImageRef>& image_refs = url->image_refs(); + for (size_t i = 0; i < image_refs.size(); i++) { + GURL image_url(image_refs[i].url); + if (!image_url.is_valid() || + !(image_url.SchemeIs("http") || image_url.SchemeIs("https"))) { + return false; + } + } + return true; +} + +} // namespace + +// static +bool TemplateURLParser::Parse(const unsigned char* data, size_t length, + TemplateURLParser::ParameterFilter* param_filter, + TemplateURL* url) { + DCHECK(url); + // xmlSubstituteEntitiesDefault(1) makes it so that & isn't mapped to + // & . Unfortunately xmlSubstituteEntitiesDefault effects global state. + // If this becomes problematic we'll need to provide our own entity + // type for &, or strip out " by hand after parsing. + int last_sub_entities_value = xmlSubstituteEntitiesDefault(1); + ParsingContext context(param_filter, url); + xmlSAXHandler sax_handler; + memset(&sax_handler, 0, sizeof(sax_handler)); + sax_handler.startElement = &StartElementImpl; + sax_handler.endElement = &EndElementImpl; + sax_handler.characters = &CharactersImpl; + xmlSAXUserParseMemory(&sax_handler, &context, + reinterpret_cast<const char*>(data), + static_cast<int>(length)); + xmlSubstituteEntitiesDefault(last_sub_entities_value); + // If the image was a data URL, use the favicon from the search URL instead. + // (see TODO inEndElementImpl()). + context.DeriveImageFromURL(); + + // TODO(jcampan): http://b/issue?id=1196285 we do not support search engines + // that use POST yet. + if (context.method() == ParsingContext::POST) + return false; + if (context.suggestion_method() == ParsingContext::POST) + url->SetSuggestionsURL(L"", 0, 0); + + if (!url->short_name().empty() && !url->description().empty()) { + // So far so good, make sure the urls are http. + return IsLegal(url); + } + return false; +} + + diff --git a/chrome/browser/template_url_parser.h b/chrome/browser/template_url_parser.h new file mode 100644 index 0000000..facf7c6 --- /dev/null +++ b/chrome/browser/template_url_parser.h @@ -0,0 +1,48 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TEMPLATE_URL_PARSER_H__ +#define CHROME_BROWSER_TEMPLATE_URL_PARSER_H__ + +#include <string> + +#include "base/basictypes.h" + +class TemplateURL; + +// TemplateURLParser, as the name implies, handling reading of TemplateURLs +// from OpenSearch description documents. +class TemplateURLParser { + public: + class ParameterFilter { + public: + // Invoked for each parameter of the template URL while parsing. If this + // methods returns false, the parameter is not included. + virtual bool KeepParameter(const std::string& key, + const std::string& value) = 0; + }; + // Decodes the chunk of data representing a TemplateURL. If data does + // not describe a valid TemplateURL false is returned. Additionally, if the + // URLs referenced do not point to valid http/https resources, false is + // returned. |parameter_filter| can be used if you want to filter out some + // parameters out of the URL. For example when importing from another browser + // we remove any parameter identifying that browser. If set to NULL, the URL + // is not modified. + // + // NOTE: This does not clear all values of the supplied TemplateURL; it's + // expected callers will supply a new TemplateURL to this method. + static bool Parse(const unsigned char* data, + size_t length, + ParameterFilter* parameter_filter, + TemplateURL* url); + + private: + // No one should create one of these. + TemplateURLParser(); + + DISALLOW_EVIL_CONSTRUCTORS(TemplateURLParser); +}; + +#endif // CHROME_BROWSER_TEMPLATE_URL_PARSER_H__ + diff --git a/chrome/browser/template_url_parser_unittest.cc b/chrome/browser/template_url_parser_unittest.cc new file mode 100644 index 0000000..381eba0 --- /dev/null +++ b/chrome/browser/template_url_parser_unittest.cc @@ -0,0 +1,240 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_parser.h" +#include "chrome/common/chrome_paths.h" +#include "testing/gtest/include/gtest/gtest.h" + +class TemplateURLParserTest : public testing::Test { + public: + TemplateURLParserTest() : parse_result_(true) { + } + + virtual void SetUp() { + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path_)); + file_util::AppendToPath(&full_path_, L"osdd"); + if (!file_util::PathExists(full_path_)) { + LOG(ERROR) << + L"This test can't be run without some non-redistributable data"; + full_path_.clear(); + } + } + + bool IsDisabled() { + return full_path_.empty(); + } + + // Parses the OpenSearch description document at file_name (relative to + // the data dir). The TemplateURL is placed in template_url_. + // The result of Parse is stored in the field parse_result_ (this doesn't + // use a return value due to internally using ASSERT_). + void ParseFile(const std::wstring& file_name, + TemplateURLParser::ParameterFilter* filter) { + std::wstring full_path(full_path_); + file_util::AppendToPath(&full_path, file_name); + parse_result_ = false; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path)); + file_util::AppendToPath(&full_path, L"osdd"); + file_util::AppendToPath(&full_path, file_name); + ASSERT_TRUE(file_util::PathExists(full_path)); + + std::string contents; + file_util::ReadFileToString(full_path, &contents); + parse_result_ = TemplateURLParser::Parse( + reinterpret_cast<const unsigned char*>(contents.c_str()), + contents.length(), filter, &template_url_); + } + + // ParseFile parses the results into this template_url. + TemplateURL template_url_; + + std::wstring full_path_; + + // Result of the parse. + bool parse_result_; +}; + +TEST_F(TemplateURLParserTest, FailOnBogusURL) { + if (IsDisabled()) + return; + ParseFile(L"bogus.xml", NULL); + EXPECT_FALSE(parse_result_); +} + +TEST_F(TemplateURLParserTest, PassOnHTTPS) { + if (IsDisabled()) + return; + ParseFile(L"https.xml", NULL); + EXPECT_TRUE(parse_result_); +} + +TEST_F(TemplateURLParserTest, FailOnPost) { + if (IsDisabled()) + return; + ParseFile(L"post.xml", NULL); + EXPECT_FALSE(parse_result_); +} + +TEST_F(TemplateURLParserTest, TestDictionary) { + if (IsDisabled()) + return; + ParseFile(L"dictionary.xml", NULL); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"Dictionary.com", template_url_.short_name()); + EXPECT_TRUE(template_url_.GetFavIconURL() == + GURL("http://cache.lexico.com/g/d/favicon.ico")); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + EXPECT_EQ(template_url_.url()->url(), + L"http://dictionary.reference.com/browse/{searchTerms}?r=75"); +} + +TEST_F(TemplateURLParserTest, TestMSDN) { + if (IsDisabled()) + return; + ParseFile(L"msdn.xml", NULL); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"Search \" MSDN", template_url_.short_name()); + EXPECT_TRUE(template_url_.GetFavIconURL() == + GURL("http://search.msdn.microsoft.com/search/favicon.ico")); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + EXPECT_EQ(template_url_.url()->url(), + L"http://search.msdn.microsoft.com/search/default.aspx?Query={searchTerms}&brand=msdn&locale=en-US"); +} + +TEST_F(TemplateURLParserTest, TestWikipedia) { + if (IsDisabled()) + return; + ParseFile(L"wikipedia.xml", NULL); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"Wikipedia (English)", template_url_.short_name()); + EXPECT_TRUE(template_url_.GetFavIconURL() == + GURL("http://en.wikipedia.org/favicon.ico")); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + EXPECT_EQ(template_url_.url()->url(), + L"http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}"); + EXPECT_TRUE(template_url_.suggestions_url() != NULL); + EXPECT_TRUE(template_url_.suggestions_url()->SupportsReplacement()); + EXPECT_EQ(template_url_.suggestions_url()->url(), + L"http://en.wikipedia.org/w/api.php?action=opensearch&search={searchTerms}"); + ASSERT_EQ(2U, template_url_.input_encodings().size()); + EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]); + EXPECT_EQ("Shift_JIS", template_url_.input_encodings()[1]); +} + +TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) { + if (IsDisabled()) + return; + ParseFile(L"url_with_no_attributes.xml", NULL); +} + +// Filters any param which as an occurrence of name_str_ in its name or an +// occurrence of value_str_ in its value. +class ParamFilterImpl : public TemplateURLParser::ParameterFilter { + public: + ParamFilterImpl(std::string name_str, std::string value_str) + : name_str_(name_str), + value_str_(value_str) { + } + + bool KeepParameter(const std::string& key, const std::string& value) { + return (name_str_.empty() || key.find(name_str_) == std::string::npos) && + (value_str_.empty() || value.find(value_str_) == std::string::npos); + } + + private: + std::string name_str_; + std::string value_str_; + + DISALLOW_EVIL_CONSTRUCTORS(ParamFilterImpl); +}; + +TEST_F(TemplateURLParserTest, TestFirefoxEbay) { + if (IsDisabled()) + return; + // This file uses the Parameter extension + // (see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0) + ParamFilterImpl filter("ebay", "ebay"); + ParseFile(L"firefox_ebay.xml", &filter); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"eBay", template_url_.short_name()); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + std::wstring exp_url = + L"http://search.ebay.com/search/search.dll?query={searchTerms}&" + L"MfcISAPICommand=GetResult&ht=1&srchdesc=n&maxRecordsReturned=300&" + L"maxRecordsPerPage=50&SortProperty=MetaEndSort"; + EXPECT_EQ(exp_url, template_url_.url()->url()); + ASSERT_EQ(1U, template_url_.input_encodings().size()); + EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]); + EXPECT_EQ(GURL("http://search.ebay.com/favicon.ico"), + template_url_.GetFavIconURL()); +} + +TEST_F(TemplateURLParserTest, TestFirefoxWebster) { + if (IsDisabled()) + return; + // This XML file uses a namespace. + ParamFilterImpl filter("", "Mozilla"); + ParseFile(L"firefox_webster.xml", &filter); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"Webster", template_url_.short_name()); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + EXPECT_EQ(L"http://www.webster.com/cgi-bin/dictionary?va={searchTerms}", + template_url_.url()->url()); + ASSERT_EQ(1U, template_url_.input_encodings().size()); + EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]); + EXPECT_EQ(GURL("http://www.webster.com/favicon.ico"), + template_url_.GetFavIconURL()); +} + +TEST_F(TemplateURLParserTest, TestFirefoxYahoo) { + if (IsDisabled()) + return; + // This XML file uses a namespace. + ParamFilterImpl filter("", "Mozilla"); + ParseFile(L"firefox_yahoo.xml", &filter); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"Yahoo", template_url_.short_name()); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + EXPECT_EQ(L"http://ff.search.yahoo.com/gossip?" + L"output=fxjson&command={searchTerms}", + template_url_.suggestions_url()->url()); + EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8", + template_url_.url()->url()); + ASSERT_EQ(1U, template_url_.input_encodings().size()); + EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]); + EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"), + template_url_.GetFavIconURL()); +} + +// Make sure we ignore POST suggestions (this is the same XML file as +// firefox_yahoo.xml, the suggestion method was just changed to POST). +TEST_F(TemplateURLParserTest, TestPostSuggestion) { + if (IsDisabled()) + return; + // This XML file uses a namespace. + ParamFilterImpl filter("", "Mozilla"); + ParseFile(L"post_suggestion.xml", &filter); + ASSERT_TRUE(parse_result_); + EXPECT_EQ(L"Yahoo", template_url_.short_name()); + EXPECT_TRUE(template_url_.url() != NULL); + EXPECT_TRUE(template_url_.url()->SupportsReplacement()); + EXPECT_TRUE(template_url_.suggestions_url() == NULL); + EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8", + template_url_.url()->url()); + ASSERT_EQ(1U, template_url_.input_encodings().size()); + EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]); + EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"), + template_url_.GetFavIconURL()); +} diff --git a/chrome/browser/template_url_prepopulate_data.cc b/chrome/browser/template_url_prepopulate_data.cc new file mode 100644 index 0000000..11ebf21 --- /dev/null +++ b/chrome/browser/template_url_prepopulate_data.cc @@ -0,0 +1,3082 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/template_url_prepopulate_data.h" + +#include "base/command_line.h" +#include "chrome/browser/template_url.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#undef IN // On Windows, windef.h defines this, which screws up "India" cases. + +using base::Time; + +namespace { + +// NOTE: See comments in GetDataVersion() below! You should probably not change +// the data in this file without changing the result of that function! + +// Engine definitions ////////////////////////////////////////////////////////// + +struct PrepopulatedEngine { + const wchar_t* const name; + // If NULL, we'll autogenerate a keyword based on the search_url every time + // someone asks. Only entries which need keywords to auto-track a dynamically + // generated search URL should use this. + // If the empty string, the engine has no keyword. + const wchar_t* const keyword; + const wchar_t* const favicon_url; // If NULL, there is no favicon. + const wchar_t* const search_url; + const char* const encoding; + const wchar_t* const suggest_url; // If NULL, this engine does not support + // suggestions. + // Unique id for this prepopulate engine (corresponds to + // TemplateURL::prepopulate_id). This ID must be greater than zero and must + // remain the same for a particular site regardless of how the url changes; + // the ID is used when modifying engine data in subsequent versions, so that + // we can find the "old" entry to update even when the name or URL changes. + // + // This ID must be "unique" within one country's prepopulated data, but two + // entries can share an ID if they represent the "same" engine (e.g. Yahoo! US + // vs. Yahoo! UK) and will not appear in the same user-visible data set. This + // facilitates changes like adding more specific per-country data in the + // future; in such a case the localized engines will transparently replace the + // previous, non-localized versions. For engines where we need two instances + // to appear for one country (e.g. Live Search U.S. English and Spanish), we + // must use two different unique IDs (and different keywords). + // + // The following unique IDs are available: 66, 93, 103+ + // NOTE: CHANGE THE ABOVE NUMBERS IF YOU ADD A NEW ENGINE; ID conflicts = bad! + const int id; +}; + +const PrepopulatedEngine abcsok = { + L"ABC S\x00f8k", + L"abcsok.no", + L"http://abcsok.no/favicon.ico", + L"http://abcsok.no/index.html?q={searchTerms}", + "UTF-8", + NULL, + 72, +}; + +const PrepopulatedEngine adonde = { + L"Adonde.com", + L"adonde.com", + L"http://www.adonde.com/favicon.ico", + L"http://www.adonde.com/peru/peru.html?sitesearch=adonde.com&" + L"client=pub-6263803831447773&ie={inputEncoding}&cof=GALT%3A%23CC0000" + L"%3BGL%3A1%3BDIV%3A%23E6E6E6%3BVLC%3A663399%3BAH%3Acenter%3BBGC%3AFFFFFF" + L"%3BLBGC%3AFFFFFF%3BALC%3A000000%3BLC%3A000000%3BT%3A0066CC%3BGFNT" + L"%3ACCCCCC%3BGIMP%3ACCCCCC%3BFORID%3A11&q={searchTerms}", + "ISO-8859-1", + NULL, + 95, +}; + +const PrepopulatedEngine aeiou = { + L"AEIOU", + L"aeiou.pt", + L"http://aeiou.pt/favicon.ico", + L"http://aeiou.pt/pesquisa/index.php?p={searchTerms}", + "ISO-8859-1", + NULL, + 79, +}; + +const PrepopulatedEngine aladin = { + L"Aladin", + L"aladin.info", + L"http://www.aladin.info/favicon.ico", + L"http://www.aladin.info/search/index.php?term={searchTerms}&req=search&" + L"source=2", + "UTF-8", + NULL, + 18, +}; + +const PrepopulatedEngine altavista = { + L"AltaVista", + L"altavista.com", + L"http://www.altavista.com/favicon.ico", + L"http://www.altavista.com/web/results?q={searchTerms}", + "UTF-8", + NULL, + 89, +}; + +const PrepopulatedEngine altavista_ar = { + L"AltaVista", + L"ar.altavista.com", + L"http://ar.altavista.com/favicon.ico", + L"http://ar.altavista.com/web/results?q={searchTerms}", + "UTF-8", + NULL, + 89, +}; + +const PrepopulatedEngine altavista_es = { + L"AltaVista", + L"es.altavista.com", + L"http://es.altavista.com/favicon.ico", + L"http://es.altavista.com/web/results?q={searchTerms}", + "UTF-8", + NULL, + 89, +}; + +const PrepopulatedEngine altavista_mx = { + L"AltaVista", + L"mx.altavista.com", + L"http://mx.altavista.com/favicon.ico", + L"http://mx.altavista.com/web/results?q={searchTerms}", + "UTF-8", + NULL, + 89, +}; + +const PrepopulatedEngine altavista_se = { + L"AltaVista", + L"se.altavista.com", + L"http://se.altavista.com/favicon.ico", + L"http://se.altavista.com/web/results?q={searchTerms}", + "UTF-8", + NULL, + 89, +}; + +const PrepopulatedEngine aol = { + L"AOL", + L"aol.com", + L"http://search.aol.com/favicon.ico", + L"http://search.aol.com/aol/search?query={searchTerms}", + "UTF-8", + NULL, + 35, +}; + +const PrepopulatedEngine aol_fr = { + L"AOL", + L"aol.fr", + L"http://www.aol.fr/favicon.ico", + L"http://www.recherche.aol.fr/aol/search?q={searchTerms}", + "UTF-8", + NULL, + 35, +}; + +const PrepopulatedEngine aonde = { + L"AONDE.com", + L"aonde.com", + L"http://busca.aonde.com/favicon.ico", + L"http://busca.aonde.com/?keys={searchTerms}", + "ISO-8859-1", + NULL, + 80, +}; + +const PrepopulatedEngine araby = { + L"\x0639\x0631\x0628\x064a", + L"araby.com", + L"http://araby.com/favicon.ico", + L"http://araby.com/?q={searchTerms}", + "UTF-8", + NULL, + 12, +}; + +const PrepopulatedEngine ask = { + L"Ask", + L"ask.com", + L"http://www.ask.com/favicon.ico", + L"http://www.ask.com/web?q={searchTerms}", + "UTF-8", + L"http://ss.ask.com/query?q={searchTerms}&li=ff", + 4, +}; + +const PrepopulatedEngine ask_de = { + L"Ask.com Deutschland", + L"de.ask.com", + L"http://de.ask.com/favicon.ico", + L"http://de.ask.com/web?q={searchTerms}", + "UTF-8", + L"http://ss.de.ask.com/query?q={searchTerms}&li=ff", + 4, +}; + +const PrepopulatedEngine ask_es = { + L"Ask.com Espa" L"\x00f1" L"a", + L"es.ask.com", + L"http://es.ask.com/favicon.ico", + L"http://es.ask.com/web?q={searchTerms}", + "UTF-8", + L"http://ss.es.ask.com/query?q={searchTerms}&li=ff", + 4, +}; + +const PrepopulatedEngine ask_it = { + L"Ask.com Italia", + L"it.ask.com", + L"http://it.ask.com/favicon.ico", + L"http://it.ask.com/web?q={searchTerms}", + "UTF-8", + L"http://ss.it.ask.com/query?q={searchTerms}&li=ff", + 4, +}; + +const PrepopulatedEngine ask_uk = { + L"Ask.com UK", + L"uk.ask.com", + L"http://uk.ask.com/favicon.ico", + L"http://uk.ask.com/web?q={searchTerms}", + "UTF-8", + L"http://ss.uk.ask.com/query?q={searchTerms}&li=ff", + 4, +}; + +const PrepopulatedEngine atlas_cz = { + L"Atlas", + L"atlas.cz", + L"http://img.atlas.cz/favicon.ico", + L"http://search.atlas.cz/?q={searchTerms}", + "windows-1250", + NULL, + 27, +}; + +const PrepopulatedEngine atlas_sk = { + L"ATLAS.SK", + L"atlas.sk", + L"http://www.atlas.sk/images/favicon.ico", + L"http://hladaj.atlas.sk/fulltext/?phrase={searchTerms}", + "UTF-8", + NULL, + 27, +}; + +const PrepopulatedEngine baidu = { + L"\x767e\x5ea6", + L"baidu.com", + L"http://www.baidu.com/favicon.ico", + L"http://www.baidu.com/s?wd={searchTerms}", + "GB2312", + NULL, + 21, +}; + +const PrepopulatedEngine biglobe = { + L"BIGLOBE", + L"biglobe.ne.jp", + L"http://cgi.search.biglobe.ne.jp/favicon.ico", + L"http://cgi.search.biglobe.ne.jp/cgi-bin/search2-b?q={searchTerms}", + "Shift_JIS", + NULL, + 64, +}; + +const PrepopulatedEngine bigmir = { + L"bigmir)net", + L"bigmir.net", + L"http://i.bigmir.net/favicon.ico", + L"http://search.bigmir.net/index.php?q={searchTerms}", + "windows-1251", + NULL, + 33, +}; + +const PrepopulatedEngine bluewin = { + L"Bluewin", + L"search.bluewin.ch", + L"http://search.bluewin.ch/favicon.ico", + L"http://search.bluewin.ch/bw/search/web/de/result.jsp?query={searchTerms}", + "ISO-8859-1", + NULL, + 52, +}; + +const PrepopulatedEngine centrum_cz = { + L"Centrum.cz", + L"centrum.cz", + L"http://img.centrum.cz/6/vy2/o/favicon.ico", + L"http://search.centrum.cz/index.php?charset={inputEncoding}&q={searchTerms}", + "UTF-8", + NULL, + 26, +}; + +const PrepopulatedEngine centrum_sk = { + L"Centrum.sk", + L"centrum.sk", + L"http://img.centrum.sk/4/favicon.ico", + L"http://search.centrum.sk/index.php?charset={inputEncoding}&q={searchTerms}", + "UTF-8", + NULL, + 26, +}; + +const PrepopulatedEngine conexcol = { + L"Conexcol.com", + L"conexcol.com", + L"http://www.conexcol.com/favicon.ico", + L"http://buscar.conexcol.com/cgi-ps/busqueda.cgi?query={searchTerms}", + "ISO-8859-1", + NULL, + 91, +}; + +const PrepopulatedEngine daum = { + L"Daum", + L"daum.net", + L"http://search.daum.net/favicon.ico", + L"http://search.daum.net/search?q={searchTerms}", + "EUC-KR", + L"http://sug.search.daum.net/search_nsuggest?mod=fxjson&q={searchTerms}", + 68, +}; + +const PrepopulatedEngine delfi_ee = { + L"DELFI", + L"delfi.ee", + L"http://g.delfi.ee/s/search.png", + L"http://otsing.delfi.ee/i.php?q={searchTerms}", + "ISO-8859-1", + NULL, + 45, +}; + +const PrepopulatedEngine delfi_lt = { + L"DELFI", + L"delfi.lt", + L"http://search.delfi.lt/img/favicon.png", + L"http://search.delfi.lt/search.php?q={searchTerms}", + "UTF-8", + NULL, + 45, +}; + +const PrepopulatedEngine delfi_lv = { + L"DELFI", + L"delfi.lv", + L"http://smart.delfi.lv/img/smart_search.png", + L"http://smart.delfi.lv/i.php?enc={inputEncoding}&q={searchTerms}", + "UTF-8", + NULL, + 45, +}; + +const PrepopulatedEngine embla = { + L"Embla", + L"embla.is", + L"http://embla.is/favicon.ico", + L"http://embla.is/mm/embla/?s={searchTerms}", + "ISO-8859-1", + NULL, + 60, +}; + +const PrepopulatedEngine empas = { + L"\xc5e0\xd30c\xc2a4", + L"empas.com", + L"http://search.empas.com/favicon.ico", + L"http://search.empas.com/search/all.html?q={searchTerms}", + "EUC-KR", + // http://www.empas.com/ac/do.tsp?q={searchTerms} + // returns non-Firefox JSON. searchTerms needs to be in Java notation + // (\uAC00\uAC01). + NULL, + 70, +}; + +const PrepopulatedEngine eniro_dk = { + L"Eniro", + L"eniro.dk", + L"http://eniro.dk/favicon.ico", + L"http://eniro.dk/query?search_word={searchTerms}&what=web_local", + "ISO-8859-1", + NULL, + 29, +}; + +const PrepopulatedEngine eniro_fi = { + L"Eniro", + L"eniro.fi", + L"http://eniro.fi/favicon.ico", + L"http://eniro.fi/query?search_word={searchTerms}&what=web_local", + "ISO-8859-1", + NULL, + 29, +}; + +const PrepopulatedEngine eniro_se = { + L"Eniro", + L"eniro.se", + L"http://eniro.se/favicon.ico", + L"http://eniro.se/query?search_word={searchTerms}&what=web_local", + "ISO-8859-1", + NULL, + 29, +}; + +const PrepopulatedEngine finna = { + L"FINNA", + L"finna.is", + L"http://finna.is/favicon.ico", + L"http://finna.is/WWW_Search/?query={searchTerms}", + "UTF-8", + NULL, + 61, +}; + +const PrepopulatedEngine fonecta_02_fi = { + L"Fonecta 02.fi", + L"www.fi", + L"http://www.02.fi/img/favicon.ico", + L"http://www.02.fi/haku/{searchTerms}", + "UTF-8", + NULL, + 46, +}; + +const PrepopulatedEngine forthnet = { + L"Forthnet", + L"forthnet.gr", + L"http://search.forthnet.gr/favicon.ico", + L"http://search.forthnet.gr/cgi-bin/query?mss=search&q={searchTerms}", + "windows-1253", + NULL, + 53, +}; + +const PrepopulatedEngine gigabusca = { + L"GiGaBusca", + L"gigabusca.com.br", + L"http://www.gigabusca.com.br/favicon.ico", + L"http://www.gigabusca.com.br/buscar.php?query={searchTerms}", + "ISO-8859-1", + NULL, + 81, +}; + +const PrepopulatedEngine go = { + L"GO.com", + L"go.com", + L"http://search.yahoo.com/favicon.ico", + L"http://search.yahoo.com/search?ei={inputEncoding}&p={searchTerms}&" + L"fr=hsusgo1", + "ISO-8859-1", + NULL, + 40, +}; + +const PrepopulatedEngine goo = { + L"goo", + L"goo.ne.jp", + L"http://goo.ne.jp/gooicon.ico", + L"http://search.goo.ne.jp/web.jsp?MT={searchTerms}&IE={inputEncoding}", + "UTF-8", + NULL, + 92, +}; + +const PrepopulatedEngine google = { + L"Google", + NULL, + L"http://www.google.com/favicon.ico", + L"{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}" + L"{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&" + L"q={searchTerms}", + "UTF-8", + L"{google:baseSuggestURL}search?client=chrome&output=chrome&hl={language}&" + L"q={searchTerms}", + 1, +}; + +const PrepopulatedEngine guruji = { + L"guruji", + L"guruji.com", + L"http://guruji.com/favicon.ico", + L"http://guruji.com/search?q={searchTerms}", + "UTF-8", + NULL, + 38, +}; + +const PrepopulatedEngine iafrica = { + L"iafrica.com", + L"iafrica.com", + NULL, + L"http://search.iafrica.com/search?q={searchTerms}", + "ISO-8859-1", + NULL, + 43, +}; + +const PrepopulatedEngine ilse = { + L"Ilse", + L"ilse.nl", + L"http://search.ilse.nl/images/favicon.ico", + L"http://search.ilse.nl/web?search_for={searchTerms}", + "ISO-8859-1", + NULL, + 30, +}; + +const PrepopulatedEngine in = { + L"in.gr", + L"in.gr", + L"http://www.in.gr/favicon.ico", + L"http://find.in.gr/result.asp?q={searchTerms}", + "ISO-8859-7", + NULL, + 54, +}; + +const PrepopulatedEngine jabse = { + L"Jabse", + L"jabse.com", + L"http://www.jabse.com/favicon.ico", + L"http://www.jabse.com/searchmachine.php?query={searchTerms}", + "UTF-8", + NULL, + 19, +}; + +const PrepopulatedEngine jamaicalive = { + L"JamaicaLive", + L"jalive.com.jm", + L"http://jalive.com.jm/favicon.ico", + L"http://jalive.com.jm/search/?mode=allwords&search={searchTerms}", + "ISO-8859-1", + NULL, + 39, +}; + +const PrepopulatedEngine jubii = { + L"Jubii", + L"jubii.dk", + L"http://search.jubii.dk/favicon_jubii.ico", + L"http://search.jubii.dk/cgi-bin/pursuit?query={searchTerms}", + "ISO-8859-1", + NULL, + 28, +}; + +const PrepopulatedEngine krstarica = { + L"Krstarica", + L"krstarica.rs", + L"http://pretraga.krstarica.com/favicon.ico", + L"http://pretraga.krstarica.com/index.php?q={searchTerms}", + "windows-1250", + NULL, + 84, +}; + +const PrepopulatedEngine kvasir = { + L"Kvasir", + L"kvasir.no", + L"http://www.kvasir.no/img/favicon.ico", + L"http://www.kvasir.no/nettsok/searchResult.html?searchExpr={searchTerms}", + "ISO-8859-1", + NULL, + 73, +}; + +const PrepopulatedEngine latne = { + L"LATNE", + L"latne.lv", + L"http://latne.lv/favicon.ico", + L"http://latne.lv/siets.php?q={searchTerms}", + "UTF-8", + NULL, + 71, +}; + +const PrepopulatedEngine leit = { + L"leit.is", + L"leit.is", + L"http://leit.is/leit.ico", + L"http://leit.is/query.aspx?qt={searchTerms}", + "ISO-8859-1", + NULL, + 59, +}; + +const PrepopulatedEngine libero = { + L"Libero", + L"libero.it", + L"http://arianna.libero.it/favicon.ico", + L"http://arianna.libero.it/search/abin/integrata.cgi?query={searchTerms}", + "ISO-8859-1", + NULL, + 63, +}; + +const PrepopulatedEngine live = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_ar_XA = { + L"Live Search (\x0627\x0644\x0639\x0631\x0628\x064a\x0629)", + L"", // "live.com" is already taken by live_en_XA (see comment on ID below). + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=ar-XA&mkt=ar-XA&" + L"q={searchTerms}", + "UTF-8", + NULL, + 7, // Can't be 3 as this has to appear in the Arabian countries' lists + // alongside live_en_XA. +}; + +const PrepopulatedEngine live_bg_BG = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=bg-BG&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_cs_CZ = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=cs-CZ&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_el_GR = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=el-GR&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_en_ID = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=en_ID&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_en_NZ = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=en-NZ&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_en_US = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=en-US&mkt=en-US&" + L"q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_en_XA = { + L"Live Search (English)", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=en-XA&mkt=en-XA&" + L"q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_et_EE = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=et-EE&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_hr_HR = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=hr-HR&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_hu_HU = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=hu-HU&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_it_IT = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=it-IT&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_lt_LT = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=lt-LT&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_pl_PL = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=pl-PL&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_pt_PT = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=pt-PT&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_ro_RO = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=ro-RO&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_ru_RU = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=ru-RU&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_sk_SK = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=sk-SK&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_sl_SI = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=sl-SI&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine live_th_TH = { + L"Live Search", + L"live.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=th-TH&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine lycos_es = { + L"Lycos Espa" L"\x00f1" L"a", + L"lycos.es", + L"http://buscador.lycos.es/favicon.ico", + L"http://buscador.lycos.es/cgi-bin/pursuit?query={searchTerms}", + "ISO-8859-1", + NULL, + 34, +}; + +const PrepopulatedEngine lycos_nl = { + L"Lycos", + L"lycos.nl", + L"http://zoek.lycos.nl/favicon.ico", + L"http://zoek.lycos.nl/cgi-bin/pursuit?query={searchTerms}", + "ISO-8859-1", + NULL, + 34, +}; + +const PrepopulatedEngine mail_ru = { + L"@MAIL.RU", + L"mail.ru", + L"http://img.go.mail.ru/favicon.ico", + L"http://go.mail.ru/search?q={searchTerms}", + "windows-1251", + NULL, + 83, +}; + +const PrepopulatedEngine maktoob = { + L"\x0645\x0643\x062a\x0648\x0628", + L"maktoob.com", + L"http://www.maktoob.com/favicon.ico", + L"http://www.maktoob.com/searchResult.php?q={searchTerms}", + "UTF-8", + NULL, + 13, +}; + +const PrepopulatedEngine masrawy = { + L"\x0645\x0635\x0631\x0627\x0648\x064a", + L"masrawy.com", + L"http://www.masrawy.com/new/images/masrawy.ico", + L"http://masrawy.com/new/search.aspx?sr={searchTerms}", + "windows-1256", + NULL, + 14, +}; + +const PrepopulatedEngine matkurja = { + L"Mat'Kurja", + L"matkurja.com", + L"http://matkurja.com/favicon.ico", + L"http://matkurja.com/si/iskalnik/?q={searchTerms}&search_source=directory", + "ISO-8859-2", + NULL, + 88, +}; + +const PrepopulatedEngine meta = { + L"<META>", + L"meta.ua", + L"http://meta.ua/favicon.ico", + L"http://meta.ua/search.asp?q={searchTerms}", + "windows-1251", + L"http://meta.ua/suggestions/?output=fxjson&oe=utf-8&q={searchTerms}", + 102, +}; + +const PrepopulatedEngine msn = { + L"MSN", + L"msn.com", + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_ar_XA = { + L"MSN (\x0627\x0644\x0639\x0631\x0628\x064a\x0629)", + L"", // "arabia.msn.com" is already taken by msn_en_XA (see comment on ID + // below). + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?setlang=ar-XA&mkt=ar-XA&" + L"q={searchTerms}", + "UTF-8", + NULL, + 7, // Can't be 3 as this has to appear in the Arabian countries' lists + // alongside msn_en_XA. +}; + +const PrepopulatedEngine msn_da_DK = { + L"MSN Danmark", + L"dk.msn.com", + L"http://search.msn.dk/s/wlflag.ico", + L"http://search.msn.dk/results.aspx?mkt=da-DK&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_de_AT = { + L"MSN \x00d6sterreich", + L"at.msn.com", + L"http://search.msn.at/s/wlflag.ico", + L"http://search.msn.at/results.aspx?mkt=de-AT&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_de_CH = { + L"MSN Schweiz (Deutsch)", + L"ch.msn.com", + L"http://search.msn.ch/s/wlflag.ico", + L"http://search.msn.ch/results.aspx?setlang=de-CH&mkt=de-CH&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_de_DE = { + L"MSN", + L"de.msn.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=de-DE&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_AU = { + L"ninemsn.com.au", + L"ninemsn.com.au", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=en-AU&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_CA = { + L"Sympatico / MSN (English)", + L"sympatico.msn.ca", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=en-CA&mkt=en-CA&" + L"q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_GB = { + L"MSN UK", + L"uk.msn.com", + L"http://search.msn.co.uk/s/wlflag.ico", + L"http://search.msn.co.uk/results.aspx?mkt=en-GB&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_IE = { + L"MSN IE", + L"ie.msn.com", + L"http://search.msn.ie/s/wlflag.ico", + L"http://search.msn.ie/results.aspx?mkt=en-IE&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_IN = { + L"MSN India", + L"in.msn.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=en-IN&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_MY = { + L"MSN Malaysia", + L"malaysia.msn.com", + L"http://search.msn.com.my/s/wlflag.ico", + L"http://search.msn.com.my/results.aspx?mkt=en-MY&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_PH = { + L"MSN Philippines", + L"ph.msn.com", + L"http://search.msn.com.ph/s/wlflag.ico", + L"http://search.msn.com.ph/results.aspx?mkt=en-PH&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_SG = { + L"MSN Singapore", + L"sg.msn.com", + L"http://search.msn.com.sg/s/wlflag.ico", + L"http://search.msn.com.sg/results.aspx?mkt=en-SG&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_XA = { + L"MSN (English)", + L"arabia.msn.com", + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?setlang=en-XA&mkt=en-XA&" + L"q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_en_ZA = { + L"MSN ZA", + L"za.msn.com", + L"http://search.msn.co.za/s/wlflag.ico", + L"http://search.msn.co.za/results.aspx?mkt=en-ZA&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_es_AR = { + L"MSN Argentina", + L"ar.msn.com", + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?mkt=es-AR&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_es_CL = { + L"MSN Chile", + L"cl.msn.com", + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?mkt=es-CL&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_es_CO = { + L"MSN Colombia", + L"co.msn.com", + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?mkt=es-CO&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_es_ES = { + L"MSN Espa" L"\x00f1" L"a", + L"es.msn.com", + L"http://search.msn.es/s/wlflag.ico", + L"http://search.msn.es/results.aspx?mkt=es-ES&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_es_MX = { + L"Prodigy / MSN", + L"prodigy.msn.com", + L"http://search.prodigy.msn.com/s/wlflag.ico", + L"http://search.prodigy.msn.com/results.aspx?mkt=es-MX&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_es_XL = { + L"MSN Latinoam\x00e9rica", + L"latam.msn.com", + L"http://search.msn.com/s/wlflag.ico", + L"http://search.msn.com/results.aspx?mkt=es-XL&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_fi_FI = { + L"MSN", + L"fi.msn.com", + L"http://search.msn.fi/s/wlflag.ico", + L"http://search.msn.fi/results.aspx?mkt=fi-FI&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_fr_BE = { + L"MSN Belgique (Fran" L"\x00e7" L"ais)", + L"", // "be.msn.com" is already taken by msn_nl_BE (see comment on ID below). + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=fr-BE&mkt=fr-BE&" + L"q={searchTerms}", + "UTF-8", + NULL, + 8, // Can't be 3 as this has to appear in the Belgium list alongside + // msn_nl_BE. +}; + +const PrepopulatedEngine msn_fr_CA = { + L"Sympatico / MSN (Fran" L"\x00e7" L"ais)", + L"", // "sympatico.msn.ca" is already taken by msn_en_CA (see comment on ID + // below). + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=fr-CA&mkt=fr-CA&" + L"q={searchTerms}", + "UTF-8", + NULL, + 9, // Can't be 3 as this has to appear in the Canada list alongside + // msn_en_CA. +}; + +const PrepopulatedEngine msn_fr_CH = { + L"MSN Suisse (Fran" L"\x00e7" L"ais)", + L"", // "ch.msn.com" is already taken by msn_de_CH (see comment on ID below). + L"http://search.msn.ch/s/wlflag.ico", + L"http://search.msn.ch/results.aspx?setlang=fr-CH&mkt=fr-CH&q={searchTerms}", + "UTF-8", + NULL, + 10, // Can't be 3 as this has to appear in the Switzerland list alongside + // msn_de_CH. +}; + +const PrepopulatedEngine msn_fr_FR = { + L"MSN France", + L"fr.msn.com", + L"http://search.msn.fr/s/wlflag.ico", + L"http://search.msn.fr/results.aspx?mkt=fr-FR&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_he_IL = { + L"msn.co.il", + L"msn.co.il", + L"http://msn.co.il/favicon.ico", + L"http://search.msn.co.il/Search.aspx?q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_ja_JP = { + L"MSN Japan", + L"jp.msn.com", + L"http://search.msn.co.jp/s/wlflag.ico", + L"http://search.msn.co.jp/results.aspx?mkt=ja-JP&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_nb_NO = { + L"MSN Norge", + L"no.msn.com", + L"http://search.msn.no/s/wlflag.ico", + L"http://search.msn.no/results.aspx?mkt=nb-NO&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_nl_BE = { + L"MSN (Nederlandstalige)", + L"be.msn.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?setlang=nl-BE&mkt=nl-BE&" + L"q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_nl_NL = { + L"MSN.nl", + L"nl.msn.com", + L"http://search.msn.nl/s/wlflag.ico", + L"http://search.msn.nl/results.aspx?mkt=nl-NL&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_pt_BR = { + L"MSN Brasil", + L"br.msn.com", + L"http://search.live.com/s/wlflag.ico", + L"http://search.live.com/results.aspx?mkt=pt-BR&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_sv_SE = { + L"MSN", + L"se.msn.com", + L"http://search.msn.se/s/wlflag.ico", + L"http://search.msn.se/results.aspx?mkt=pv-SE&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_tr_TR = { + L"MSN T\x00fckiye'ye", + L"tr.msn.com", + L"http://search.msn.com.tr/s/wlflag.ico", + L"http://search.msn.com.tr/results.aspx?mkt=tr-TR&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine msn_zh_HK = { + L"MSN Hong Kong", + L"hk.msn.com", + L"http://search.msn.com.hk/s/wlflag.ico", + L"http://search.msn.com.hk/results.aspx?mkt=zh-HK&q={searchTerms}", + "UTF-8", + NULL, + 3, +}; + +const PrepopulatedEngine mweb = { + L"MWEB", + L"mweb.co.za", + L"http://mweb.co.za/favicon.ico", + L"http://search.mweb.co.za/search?&q={searchTerms}", + "UTF-8", + NULL, + 42, +}; + +const PrepopulatedEngine mynet = { + L"MYNET", + L"mynet.com", + L"http://img.mynet.com/mynetfavori.ico", + L"http://arama.mynet.com/search.aspx?q={searchTerms}&pg=q", + "windows-1254", + NULL, + 101, +}; + +const PrepopulatedEngine mywebsearch = { + L"mywebsearch", + L"mywebsearch.com", + NULL, + L"http://search.mywebsearch.com/mywebsearch/AJmain.jhtml?" + L"searchfor={searchTerms}", + "UTF-8", + NULL, + 97, +}; + +const PrepopulatedEngine najdi = { + L"Najdi.si", + L"najdi.si", + L"http://www.najdi.si/master/favicon.ico", + L"http://www.najdi.si/search.jsp?q={searchTerms}", + "UTF-8", + NULL, + 87, +}; + +const PrepopulatedEngine nana10 = { + L"\x05e0\x05e2\x05e0\x05e2 10", + L"nana10.co.il", + L"http://f.nau.co.il/Common/Includes/Favicon.ico", + L"http://index.nana10.co.il/search.asp?q={searchTerms}", + "windows-1255", + NULL, + 56, +}; + +const PrepopulatedEngine nate = { + L"\xb124\xc774\xd2b8\xb2f7\xcef4", + L"nate.com", + L"http://nate.search.empas.com/favicon.ico", + L"http://nate.search.empas.com/search/all.html?q={searchTerms}", + "EUC-KR", + NULL, + 69, +}; + +const PrepopulatedEngine naver = { + L"\xb124\xc774\xbc84", + L"naver.com", + L"http://search.naver.com/favicon.ico", + L"http://search.naver.com/search.naver?ie={inputEncoding}" + L"&query={searchTerms}", + "UTF-8", + L"http://ac.search.naver.com/autocompl?m=s&ie={inputEncoding}&oe=utf-8&" + L"q={searchTerms}", + 67, +}; + +const PrepopulatedEngine neti = { + L"NETI", + L"neti.ee", + L"http://www.neti.ee/favicon.ico", + L"http://www.neti.ee/cgi-bin/otsing?query={searchTerms}", + "ISO-8859-1", + NULL, + 44, +}; + +const PrepopulatedEngine netindex = { + L"NetINDEX", + L"netindex.pt", + L"http://www.netindex.pt/favicon.ico", + L"http://www.netindex.pt/cgi-bin/index.cgi?question={searchTerms}", + "ISO-8859-1", + NULL, + 78, +}; + +const PrepopulatedEngine nifty = { + L"@nifty", + L"nifty.com", + L"http://www.nifty.com/favicon.ico", + L"http://search.nifty.com/cgi-bin/search.cgi?Text={searchTerms}", + "Shift_JIS", + NULL, + 65, +}; + +const PrepopulatedEngine ohperu = { + L"Oh Per\x00fa", + L"ohperu.com", + NULL, + L"http://www.google.com.pe/custom?q={searchTerms}&" + L"client=pub-1950414869696311&ie={inputEncoding}&cof=GALT%3A%23000000" + L"%3BGL%3A1%3BDIV%3A%23FFFFFF%3BVLC%3A000000%3BAH%3Acenter%3BBGC%3AFFFFFF" + L"%3BLBGC%3AFFFFFF%3BALC%3A000000%3BLC%3A000000%3BT%3A000000%3BGFNT" + L"%3A000000%3BGIMP%3A000000%3BLH%3A50%3BLW%3A142%3BL%3Ahttp%3A%2F%2F" + L"www.ohperu.com%2Fohperu-logo-inv2.gif%3BS%3Ahttp%3A%2F%2Fwww.ohperu.com" + L"%3BFORID%3A1", + "ISO-8859-1", + NULL, + 96, +}; + +const PrepopulatedEngine ok = { + L"OK.hu", + L"ok.hu", + L"http://ok.hu/gfx/favicon.ico", + L"http://ok.hu/katalogus?q={searchTerms}", + "ISO-8859-2", + NULL, + 6, +}; + +const PrepopulatedEngine onet = { + L"Onet.pl", + L"onet.pl", + L"http://szukaj.onet.pl/favicon.ico", + L"http://szukaj.onet.pl/query.html?qt={searchTerms}", + "ISO-8859-2", + NULL, + 75, +}; + +const PrepopulatedEngine orange = { + L"Orange", + L"orange.fr", + L"http://www.orange.fr/favicon.ico", + L"http://rws.search.ke.voila.fr/RW/S/opensearch_orange?rdata={searchTerms}", + "ISO-8859-1", + L"http://search.ke.voila.fr/fr/cmplopensearch/xml/fullxml?" + L"rdata={searchTerms}", + 48, +}; + +const PrepopulatedEngine ozu = { + L"OZ\x00da", + L"ozu.es", + L"http://www.ozu.es/favicon.ico", + L"http://buscar.ozu.es/index.php?q={searchTerms}", + "ISO-8859-1", + NULL, + 98, +}; + +const PrepopulatedEngine pogodak_ba = { + L"Pogodak!", + L"pogodak.ba", + L"http://www.pogodak.ba/favicon.ico", + L"http://www.pogodak.ba/search.jsp?q={searchTerms}", + "UTF-8", + NULL, + 24, +}; + +const PrepopulatedEngine pogodak_hr = { + L"Pogodak!", + L"pogodak.hr", + L"http://www.pogodak.hr/favicon.ico", + L"http://www.pogodak.hr/search.jsp?q={searchTerms}", + "UTF-8", + NULL, + 24, +}; + +const PrepopulatedEngine pogodak_rs = { + L"Pogodak!", + L"pogodak.rs", + L"http://www.pogodak.rs/favicon.ico", + L"http://www.pogodak.rs/search.jsp?q={searchTerms}", + "UTF-8", + NULL, + 24, +}; + +const PrepopulatedEngine pogodok = { + L"\x041f\x043e\x0433\x043e\x0434\x043e\x043a!", + L"pogodok.com.mk", + L"http://www.pogodok.com.mk/favicon.ico", + L"http://www.pogodok.com.mk/search.jsp?q={searchTerms}", + "UTF-8", + NULL, + 24, // Really the same engine as Pogodak, just has a small name change. +}; + +const PrepopulatedEngine rambler = { + L"Rambler", + L"rambler.ru", + L"http://www.rambler.ru/favicon.ico", + L"http://www.rambler.ru/srch?words={searchTerms}", + "windows-1251", + NULL, + 16, +}; + +const PrepopulatedEngine rediff = { + L"Rediff", + L"rediff.com", + L"http://search1.rediff.com/favicon.ico", + L"http://search1.rediff.com/dirsrch/default.asp?MT={searchTerms}", + "UTF-8", + NULL, + 37, +}; + +const PrepopulatedEngine rednano = { + L"Rednano", + L"rednano.sg", + L"http://rednano.sg/favicon.ico", + L"http://rednano.sg/sfe/lwi.action?querystring={searchTerms}", + "UTF-8", + NULL, + 41, +}; + +const PrepopulatedEngine sanook = { + L"\x0e2a\x0e19\x0e38\x0e01!", + L"sanook.com", + L"http://search.sanook.com/favicon.ico", + L"http://search.sanook.com/search.php?q={searchTerms}", + "UTF-8", + NULL, + 100, +}; + +const PrepopulatedEngine sapo = { + L"SAPO", + L"sapo.pt", + L"http://imgs.sapo.pt/images/sapo.ico", + L"http://pesquisa.sapo.pt/?q={searchTerms}", + "UTF-8", + L"http://pesquisa.sapo.pt/livesapo?q={searchTerms}", + 77, +}; + +const PrepopulatedEngine search_ch = { + L"search.ch", + L"search.ch", + L"http://www.search.ch/favicon.ico", + L"http://www.search.ch/?q={searchTerms}", + "ISO-8859-1", + NULL, + 51, +}; + +const PrepopulatedEngine sensis = { + L"sensis.com.au", + L"sensis.com.au", + L"http://www.sensis.com.au/favicon.ico", + L"http://www.sensis.com.au/search.do?find={searchTerms}", + "UTF-8", + NULL, + 32, +}; + +const PrepopulatedEngine sesam = { + L"Sesam", + L"sesam.no", + L"http://sesam.no/images/favicon.gif", + L"http://sesam.no/search/?q={searchTerms}", + "UTF-8", + NULL, + 74, +}; + +const PrepopulatedEngine seznam = { + L"Seznam", + L"seznam.cz", + L"http://1.im.cz/szn/img/favicon.ico", + L"http://search.seznam.cz/?q={searchTerms}", + "UTF-8", + L"http:///suggest.fulltext.seznam.cz/?dict=fulltext_ff&phrase={searchTerms}&" + L"encoding={inputEncoding}&response_encoding=utf-8", + 25, +}; + +const PrepopulatedEngine sogou = { + L"\x641c\x72d7", + L"sogou.com", + L"http://www.sogou.com/favicon.ico", + L"http://www.sogou.com/web?query={searchTerms}", + "GB2312", + NULL, + 20, +}; + +const PrepopulatedEngine soso = { + L"\x641c\x641c", + L"soso.com", + L"http://www.soso.com/favicon.ico", + L"http://www.soso.com/q?w={searchTerms}", + "GB2312", + NULL, + 22, +}; + +const PrepopulatedEngine spray = { + L"Spray", + L"spray.se", + L"http://www.eniro.se/favicon.ico", + L"http://www.eniro.se/query?ax=spray&search_word={searchTerms}&what=web", + "ISO-8859-1", + NULL, + 99, +}; + +const PrepopulatedEngine szm = { + L"SZM.sk", + L"szm.sk", + L"http://szm.sk/favicon.ico", + L"http://szm.sk/search/?co=1&q={searchTerms}", + "windows-1250", + NULL, + 86, +}; + +const PrepopulatedEngine t_online = { + L"T-Online", + L"suche.t-online.de", + L"http://suche.t-online.de/favicon.ico", + L"http://suche.t-online.de/fast-cgi/tsc?sr=chrome&q={searchTerms}", + "UTF-8", + NULL, + 49, +}; + +const PrepopulatedEngine tango = { + L"Tango", + L"tango.hu", + L"http://tango.hu/favicon.ico", + L"http://tango.hu/search.php?q={searchTerms}", + "windows-1250", + NULL, + 58, +}; + +const PrepopulatedEngine tapuz = { + L"\x05ea\x05e4\x05d5\x05d6 \x05d0\x05e0\x05e9\x05d9\x05dd", + L"tapuz.co.il", + L"http://www.tapuz.co.il/favicon.ico", + L"http://www.tapuz.co.il/search/search.asp?q={searchTerms}", + "windows-1255", + NULL, + 57, +}; + +const PrepopulatedEngine terra_ar = { + L"Terra Argentina", + L"terra.com.ar", + L"http://buscar.terra.com.ar/favicon.ico", + L"http://buscar.terra.com.ar/Default.aspx?query={searchTerms}&source=Search", + "ISO-8859-1", + NULL, + 90, +}; + +const PrepopulatedEngine terra_ec = { + L"Terra Ecuador", + L"terra.com.ec", + L"http://buscador.terra.com.ec/favicon.ico", + L"http://buscador.terra.com.ec/Default.aspx?query={searchTerms}&" + L"source=Search", + "ISO-8859-1", + NULL, + 90, +}; + +const PrepopulatedEngine terra_es = { + L"Terra", + L"terra.es", + L"http://buscador.terra.es/favicon.ico", + L"http://buscador.terra.es/Default.aspx?query={searchTerms}&source=Search", + "ISO-8859-1", + NULL, + 90, +}; + +const PrepopulatedEngine terra_mx = { + L"Terra", + L"terra.com.mx", + L"http://buscador.terra.com.mx/favicon.ico", + L"http://buscador.terra.com.mx/Default.aspx?query={searchTerms}&" + L"source=Search", + "ISO-8859-1", + NULL, + 90, +}; + +const PrepopulatedEngine terra_pe = { + L"Terra", + L"terra.com.pe", + L"http://buscador.terra.com.pe/favicon.ico", + L"http://buscador.terra.com.pe/Default.aspx?query={searchTerms}&" + L"source=Search", + "ISO-8859-1", + NULL, + 90, +}; + +const PrepopulatedEngine toile = { + L"La Toile du Qu" L"\x00e9" L"bec", + L"toile.com", + L"http://static.search.canoe.ca/s-toile/img/favicon_toile.ico", + L"http://www.toile.com/search?q={searchTerms}", + "UTF-8", + NULL, + 36, +}; + +const PrepopulatedEngine tut = { + L"TUT.BY", + L"tut.by", + L"http://www.tut.by/favicon.ico", + L"http://search.tut.by/?query={searchTerms}", + "windows-1251", + NULL, + 17, +}; + +const PrepopulatedEngine uol = { + L"UOL Busca", + L"busca.uol.com.br", + L"http://busca.uol.com.br/favicon.ico", + L"http://busca.uol.com.br/www/index.html?q={searchTerms}", + "ISO-8859-1", + NULL, + 82, +}; + +const PrepopulatedEngine vinden = { + L"Vinden.nl", + L"vinden.nl", + L"http://www.vinden.nl/favicon.ico", + L"http://www.vinden.nl/?q={searchTerms}", + "UTF-8", + NULL, + 31, +}; + +const PrepopulatedEngine virgilio = { + L"Virgilio", + L"virgilio.alice.it", + L"http://ricerca.alice.it/favicon.ico", + L"http://ricerca.alice.it/ricerca?qs={searchTerms}", + "ISO-8859-1", + NULL, + 62, +}; + +const PrepopulatedEngine voila = { + L"Voila", + L"voila.fr", + L"http://search.ke.voila.fr/favicon.ico", + L"http://rws.search.ke.voila.fr/RW/S/opensearch_voila?rdata={searchTerms}", + "ISO-8859-1", + L"http://search.ke.voila.fr/fr/cmplopensearch/xml/fullxml?" + L"rdata={searchTerms}", + 47, +}; + +const PrepopulatedEngine walla = { + L"\x05d5\x05d5\x05d0\x05dc\x05d4!", + L"walla.co.il", + L"http://www.walla.co.il/favicon.ico", + L"http://search.walla.co.il/?e=hew&q={searchTerms}", + "windows-1255", + NULL, + 55, +}; + +const PrepopulatedEngine web_de = { + L"WEB.DE", + L"web.de", + L"http://img.ui-portal.de/search/img/webde/favicon.ico", + L"http://suche.web.de/search/web/?su={searchTerms}", + "ISO-8859-1", + NULL, + 50, +}; + +const PrepopulatedEngine wp = { + L"Wirtualna Polska", + L"wp.pl", + L"http://szukaj.wp.pl/favicon.ico", + L"http://szukaj.wp.pl/szukaj.html?szukaj={searchTerms}", + "ISO-8859-2", + NULL, + 76, +}; + +const PrepopulatedEngine yagua = { + L"Yagua.com", + L"yagua.com", + L"http://yagua.paraguay.com/favicon.ico", + L"http://yagua.paraguay.com/buscador.php?q={searchTerms}&cs={inputEncoding}", + "ISO-8859-1", + NULL, + 94, +}; + +const PrepopulatedEngine yahoo = { + L"Yahoo!", + L"yahoo.com", + L"http://search.yahoo.com/favicon.ico", + L"http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}", + "UTF-8", + L"http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}", + 2, +}; + +// For regional Yahoo variants without region-specific suggestion service, +// suggestion is disabled. For some of them, we might consider +// using a fallback (e.g. de for at/ch, ca or fr for qc, en for nl, no, hk). +const PrepopulatedEngine yahoo_ar = { + L"Yahoo! Argentina", + L"ar.yahoo.com", + L"http://ar.search.yahoo.com/favicon.ico", + L"http://ar.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://ar-sayt.ff.search.yahoo.com/gossip-ar-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_at = { + L"Yahoo! Suche", + L"at.yahoo.com", + L"http://at.search.yahoo.com/favicon.ico", + L"http://at.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_au = { + L"Yahoo!7", + L"au.yahoo.com", + L"http://au.search.yahoo.com/favicon.ico", + L"http://au.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://aue-sayt.ff.search.yahoo.com/gossip-au-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_br = { + L"Yahoo! Brasil", + L"br.yahoo.com", + L"http://br.search.yahoo.com/favicon.ico", + L"http://br.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://br-sayt.ff.search.yahoo.com/gossip-br-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_ca = { + L"Yahoo! Canada", + L"ca.yahoo.com", + L"http://ca.search.yahoo.com/favicon.ico", + L"http://ca.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://gossip.ca.yahoo.com/gossip-ca-sayt?output=fxjsonp&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_ch = { + L"Yahoo! Suche", + L"ch.yahoo.com", + L"http://ch.search.yahoo.com/favicon.ico", + L"http://ch.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_cl = { + L"Yahoo! Chile", + L"cl.yahoo.com", + L"http://cl.search.yahoo.com/favicon.ico", + L"http://cl.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_cn = { + L"\x4e2d\x56fd\x96c5\x864e", + L"cn.yahoo.com", + L"http://search.cn.yahoo.com/favicon.ico", + L"http://search.cn.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "GB2312", + // http://cn.yahoo.com/cnsuggestion/suggestion.inc.php?of=fxjson&query= + // returns in a proprietary format ('|' delimeted word list). + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_co = { + L"Yahoo! Colombia", + L"co.yahoo.com", + L"http://co.search.yahoo.com/favicon.ico", + L"http://co.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_de = { + L"Yahoo! Deutschland", + L"de.yahoo.com", + L"http://de.search.yahoo.com/favicon.ico", + L"http://de.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://de-sayt.ff.search.yahoo.com/gossip-de-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_dk = { + L"Yahoo! Danmark", + L"dk.yahoo.com", + L"http://dk.search.yahoo.com/favicon.ico", + L"http://dk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_es = { + L"Yahoo! Espa" L"\x00f1" L"a", + L"es.yahoo.com", + L"http://es.search.yahoo.com/favicon.ico", + L"http://es.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://es-sayt.ff.search.yahoo.com/gossip-es-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_fi = { + L"Yahoo!-haku", + L"fi.yahoo.com", + L"http://fi.search.yahoo.com/favicon.ico", + L"http://fi.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_fr = { + L"Yahoo! France", + L"fr.yahoo.com", + L"http://fr.search.yahoo.com/favicon.ico", + L"http://fr.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://fr-sayt.ff.search.yahoo.com/gossip-fr-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_hk = { + L"Yahoo! Hong Kong", + L"hk.yahoo.com", + L"http://hk.search.yahoo.com/favicon.ico", + L"http://hk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + // http://history.hk.search.yahoo.com/ac/ac_msearch.php?query={searchTerms} + // returns a JSON with key-value pairs. Setting parameters (ot, of, output) + // to fxjson, json, or js doesn't help. + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_id = { + L"Yahoo! Indonesia", + L"id.yahoo.com", + L"http://id.search.yahoo.com/favicon.ico", + L"http://id.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://id-sayt.ff.search.yahoo.com/gossip-id-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_in = { + L"Yahoo! India", + L"in.yahoo.com", + L"http://in.search.yahoo.com/favicon.ico", + L"http://in.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://in-sayt.ff.search.yahoo.com/gossip-in-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_it = { + L"Yahoo! Italia", + L"it.yahoo.com", + L"http://it.search.yahoo.com/favicon.ico", + L"http://it.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://it-sayt.ff.search.yahoo.com/gossip-it-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_jp = { + L"Yahoo! JAPAN", + L"yahoo.co.jp", + L"http://search.yahoo.co.jp/favicon.ico", + L"http://search.yahoo.co.jp/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_kr = { + L"\xc57c\xd6c4! \xcf54\xb9ac\xc544", + L"kr.yahoo.com", + L"http://kr.search.yahoo.com/favicon.ico", + L"http://kr.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://kr.atc.search.yahoo.com/atcx.php?property=main&ot=fxjson&" + L"ei=utf8&eo=utf8&command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_malaysia = { + L"Yahoo! Malaysia", + L"malaysia.yahoo.com", + L"http://malaysia.search.yahoo.com/favicon.ico", + L"http://malaysia.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://my-sayt.ff.search.yahoo.com/gossip-my-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_mx = { + L"Yahoo! M\x00e9xico", + L"mx.yahoo.com", + L"http://mx.search.yahoo.com/favicon.ico", + L"http://mx.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://gossip.mx.yahoo.com/gossip-mx-sayt?output=fxjsonp&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_nl = { + L"Yahoo! Nederland", + L"nl.yahoo.com", + L"http://nl.search.yahoo.com/favicon.ico", + L"http://nl.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_no = { + L"Yahoo! Norge", + L"no.yahoo.com", + L"http://no.search.yahoo.com/favicon.ico", + L"http://no.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_nz = { + L"Yahoo!Xtra", + L"nz.yahoo.com", + L"http://nz.search.yahoo.com/favicon.ico", + L"http://nz.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://aue-sayt.ff.search.yahoo.com/gossip-nz-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_pe = { + L"Yahoo! Per\x00fa", + L"pe.yahoo.com", + L"http://pe.search.yahoo.com/favicon.ico", + L"http://pe.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_ph = { + L"Yahoo! Philippines", + L"ph.yahoo.com", + L"http://ph.search.yahoo.com/favicon.ico", + L"http://ph.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://ph-sayt.ff.search.yahoo.com/gossip-ph-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_qc = { + L"Yahoo! Qu" L"\x00e9" L"bec", + L"qc.yahoo.com", + L"http://qc.search.yahoo.com/favicon.ico", + L"http://qc.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 5, // Can't be 2 as this has to appear in the Canada list alongside yahoo_ca. +}; + +const PrepopulatedEngine yahoo_ru = { + L"Yahoo! \x043f\x043e-\x0440\x0443\x0441\x0441\x043a\x0438", + L"ru.yahoo.com", + L"http://ru.search.yahoo.com/favicon.ico", + L"http://ru.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_sg = { + L"Yahoo! Singapore", + L"sg.yahoo.com", + L"http://sg.search.yahoo.com/favicon.ico", + L"http://sg.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://sg-sayt.ff.search.yahoo.com/gossip-sg-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_th = { + L"Yahoo! \x0e1b\x0e23\x0e30\x0e40\x0e17\x0e28\x0e44\x0e17\x0e22", + L"th.yahoo.com", + L"http://th.search.yahoo.com/favicon.ico", + L"http://th.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://th-sayt.ff.search.yahoo.com/gossip-th-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_tw = { + L"Yahoo!\x5947\x6469", + L"tw.yahoo.com", + L"http://tw.search.yahoo.com/favicon.ico", + L"http://tw.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + // "http://tw.yahoo.com/ac/ac_search.php?eo=utf8&of=js&prop=web&query=" + // returns a JSON file prepended with 'fxjson={'. + NULL, + 2, +}; + +const PrepopulatedEngine yahoo_uk = { + L"Yahoo! UK & Ireland", + L"uk.yahoo.com", + L"http://uk.search.yahoo.com/favicon.ico", + L"http://uk.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://uk-sayt.ff.search.yahoo.com/gossip-uk-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_ve = { + L"Yahoo! Venezuela", + L"ve.yahoo.com", + L"http://ve.search.yahoo.com/favicon.ico", + L"http://ve.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://gossip.telemundo.yahoo.com/gossip-e1-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yahoo_vn = { + L"Yahoo! Vi\x1ec7t Nam", + L"vn.yahoo.com", + L"http://vn.search.yahoo.com/favicon.ico", + L"http://vn.search.yahoo.com/search?ei={inputEncoding}&fr=crmas&" + L"p={searchTerms}", + "UTF-8", + L"http://vn-sayt.ff.search.yahoo.com/gossip-vn-sayt?output=fxjson&" + L"command={searchTerms}", + 2, +}; + +const PrepopulatedEngine yam = { + L"\u5929\u7a7a", + L"yam.com", + L"http://www.yam.com/i/8/sky.ico", + L"http://search.yam.com/wps?k={searchTerms}", + "Big5", + NULL, + 23, +}; + +const PrepopulatedEngine yamli = { + L"Yamli", + L"yamli.com", + L"http://www.yamli.com/favicon.ico", + L"http://www.yamli.com/#q={searchTerms}", + "UTF-8", + NULL, + 11, +}; + +const PrepopulatedEngine yandex_ru = { + L"\x042f\x043d\x0434\x0435\x043a\x0441", + L"yandex.ru", + L"http://yandex.ru/favicon.ico", + L"http://yandex.ru/yandsearch?text={searchTerms}", + "UTF-8", + L"http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}", + 15, +}; + +const PrepopulatedEngine yandex_ua = { + L"\x042f\x043d\x0434\x0435\x043a\x0441", + L"yandex.ua", + L"http://yandex.ua/favicon.ico", + L"http://yandex.ua/yandsearch?text={searchTerms}", + "UTF-8", + L"http://suggest.yandex.net/suggest-ff.cgi?part={searchTerms}", + 15, +}; + +const PrepopulatedEngine zoznam = { + L"Zoznam", + L"zoznam.sk", + L"http://zoznam.sk/favicon.ico", + L"http://zoznam.sk/hladaj.fcgi?s={searchTerms}", + "windows-1250", + NULL, + 85, +}; + +// Lists of engines per country //////////////////////////////////////////////// + +// Put these in order with most interesting/important first. The default will +// be the first engine. + +// Default (for countries with no better engine set) +const PrepopulatedEngine* engines_default[] = { &google, &yahoo, &live, }; + +// United Arab Emirates +const PrepopulatedEngine* engines_AE[] = + { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Albania +const PrepopulatedEngine* engines_AL[] = + { &google, &yahoo, &live_en_XA, &live_ar_XA, }; + +// Argentina +const PrepopulatedEngine* engines_AR[] = + { &google, &msn_es_AR, &altavista_ar, &terra_ar, &yahoo_ar, }; + +// Austria +const PrepopulatedEngine* engines_AT[] = { &google, &yahoo_at, &msn_de_AT, }; + +// Australia +const PrepopulatedEngine* engines_AU[] = + { &google, &yahoo_au, &msn_en_AU, &sensis, }; + +// Bosnia and Herzegovina +const PrepopulatedEngine* engines_BA[] = + { &google, &pogodak_ba, &yahoo, &live, }; + +// Belgium +const PrepopulatedEngine* engines_BE[] = + { &google, &yahoo, &msn_nl_BE, &msn_fr_BE, }; + +// Bulgaria +// The commented-out entry for "dir" below is for dir.bg, &which we don't +// currently support because it uses POST instead of GET for its searches. +// See http://b/1196285 +const PrepopulatedEngine* engines_BG[] = + { &google, &/*dir,*/ yahoo, &jabse, &live_bg_BG, }; + +// Bahrain +const PrepopulatedEngine* engines_BH[] = + { &google, &maktoob, &yamli, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Brunei +const PrepopulatedEngine* engines_BN[] = + { &google, &yahoo_malaysia, &msn_en_MY, }; + +// Bolivia +const PrepopulatedEngine* engines_BO[] = + { &google, &altavista, &msn_es_XL, &yahoo, &ask_es, }; + +// Brazil +const PrepopulatedEngine* engines_BR[] = + { &google, &msn_pt_BR, &yahoo_br, &aonde, &gigabusca, &uol, }; + +// Belarus +const PrepopulatedEngine* engines_BY[] = + { &google, &yandex_ru, &rambler, &yahoo, &tut, }; + +// Belize +const PrepopulatedEngine* engines_BZ[] = { &google, &yahoo, &live, &aol, }; + +// Canada +const PrepopulatedEngine* engines_CA[] = + { &google, &msn_en_CA, &msn_fr_CA, &yahoo_ca, &yahoo_qc, &toile, }; + +// Switzerland +const PrepopulatedEngine* engines_CH[] = + { &google, &search_ch, &yahoo_ch, &msn_de_CH, &msn_fr_CH, &bluewin, }; + +// Chile +const PrepopulatedEngine* engines_CL[] = + { &google, &yahoo_cl, &altavista, &msn_es_CL, }; + +// China +const PrepopulatedEngine* engines_CN[] = + { &google, &baidu, &yahoo_cn, &sogou, &soso, }; + +// Colombia +const PrepopulatedEngine* engines_CO[] = + { &google, &msn_es_CO, &ask_es, &altavista, &conexcol, &yahoo_co, }; + +// Costa Rica +const PrepopulatedEngine* engines_CR[] = + { &google, &msn_es_XL, &yahoo, &altavista, &aol, &lycos_es, }; + +// Czech Republic +const PrepopulatedEngine* engines_CZ[] = + { &google, &seznam, ¢rum_cz, &atlas_cz, &live_cs_CZ, }; + +// Germany +const PrepopulatedEngine* engines_DE[] = + { &google, &msn_de_DE, &yahoo_de, &t_online, &ask_de, &web_de, }; + +// Denmark +const PrepopulatedEngine* engines_DK[] = + { &google, &jubii, &msn_da_DK, &yahoo_dk, &eniro_dk, }; + +// Dominican Republic +const PrepopulatedEngine* engines_DO[] = + { &google, &msn_es_XL, &yahoo, &altavista, &go, &aol, }; + +// Algeria +const PrepopulatedEngine* engines_DZ[] = + { &google, &yahoo, &yamli, &msn_en_XA, &msn_ar_XA, &araby, }; + +// Ecuador +const PrepopulatedEngine* engines_EC[] = + { &google, &msn_es_XL, &yahoo, &terra_ec, }; + +// Estonia +const PrepopulatedEngine* engines_EE[] = + { &google, &neti, &delfi_ee, &yahoo, &live_et_EE, }; + +// Egypt +const PrepopulatedEngine* engines_EG[] = + { &google, &masrawy, &yahoo, &maktoob, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Spain +const PrepopulatedEngine* engines_ES[] = + { &google, &msn_es_ES, &yahoo_es, &terra_es, &ozu, &altavista_es, }; + +// Faroe Islands +const PrepopulatedEngine* engines_FO[] = + { &google, &jubii, &msn_da_DK, &yahoo_dk, &eniro_dk, }; + +// Finland +const PrepopulatedEngine* engines_FI[] = + { &google, &msn_fi_FI, &yahoo_fi, &eniro_fi, &fonecta_02_fi, }; + +// France +const PrepopulatedEngine* engines_FR[] = + { &google, &voila, &yahoo_fr, &msn_fr_FR, &orange, &aol_fr, }; + +// Greece +const PrepopulatedEngine* engines_GR[] = + { &google, &yahoo, &forthnet, &in, &live_el_GR }; + +// Guatemala +const PrepopulatedEngine* engines_GT[] = + { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &go, }; + +// Hong Kong +const PrepopulatedEngine* engines_HK[] = + { &google, &yahoo_hk, &msn_zh_HK, &sogou, &baidu, }; + +// Honduras +const PrepopulatedEngine* engines_HN[] = + { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, }; + +// Croatia +const PrepopulatedEngine* engines_HR[] = + { &google, &yahoo, &pogodak_hr, &live_hr_HR, }; + +// Hungary +const PrepopulatedEngine* engines_HU[] = { &google, &tango, &ok, &live_hu_HU, }; + +// Indonesia +const PrepopulatedEngine* engines_ID[] = { &google, &yahoo_id, &live_en_ID, }; + +// Ireland +const PrepopulatedEngine* engines_IE[] = { &google, &yahoo_uk, &msn_en_IE, }; + +// Israel +const PrepopulatedEngine* engines_IL[] = + { &google, &walla, &nana10, &tapuz, &msn_he_IL, }; + +// India +const PrepopulatedEngine* engines_IN[] = + { &google, &yahoo_in, &msn_en_IN, &rediff, &guruji, }; + +// Iraq +const PrepopulatedEngine* engines_IQ[] = + { &google, &maktoob, &yamli, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Iran +const PrepopulatedEngine* engines_IR[] = { &google, }; + +// Iceland +const PrepopulatedEngine* engines_IS[] = { &google, &leit, &embla, &finna, }; + +// Italy +const PrepopulatedEngine* engines_IT[] = + { &google, &virgilio, &yahoo_it, &libero, &ask_it, &live_it_IT, }; + +// Jamaica +const PrepopulatedEngine* engines_JM[] = + { &google, &jamaicalive, &yahoo, &live, &go, &aol, }; + +// Jordan +const PrepopulatedEngine* engines_JO[] = + { &google, &maktoob, &yamli, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Japan +const PrepopulatedEngine* engines_JP[] = + { &google, &yahoo_jp, &msn_ja_JP, &biglobe, &goo, &nifty, }; + +// Kenya +const PrepopulatedEngine* engines_KE[] = { &google, &yahoo, &msn, }; + +// Kuwait +const PrepopulatedEngine* engines_KW[] = + { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// South Korea +const PrepopulatedEngine* engines_KR[] = + { &google, &naver, &daum, &yahoo_kr, &nate, &empas, }; + +// Lebanon +const PrepopulatedEngine* engines_LB[] = + { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Liechtenstein +const PrepopulatedEngine* engines_LI[] = + { &google, &msn_de_DE, &yahoo_de, &t_online, &ask_de, &web_de, }; + +// Lithuania +const PrepopulatedEngine* engines_LT[] = + { &google, &delfi_lt, &yahoo, &yandex_ru, &live_lt_LT, }; + +// Luxembourg +const PrepopulatedEngine* engines_LU[] = + { &google, &voila, &yahoo_fr, &msn_fr_FR, &orange, &aol_fr, }; + +// Latvia +const PrepopulatedEngine* engines_LV[] = + { &google, &delfi_lv, &yahoo, &yandex_ru, &latne, }; + +// Libya +const PrepopulatedEngine* engines_LY[] = + { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Morocco +const PrepopulatedEngine* engines_MA[] = + { &google, &yamli, &araby, &yahoo, &msn_en_XA, &msn_ar_XA, }; + +// Monaco +const PrepopulatedEngine* engines_MC[] = + { &google, &voila, &yahoo_fr, &msn_fr_FR, &orange, &aol_fr, }; + +// Macedonia +const PrepopulatedEngine* engines_MK[] = { &google, &pogodok, &yahoo, &live, }; + +// Mexico +const PrepopulatedEngine* engines_MX[] = + { &google, &msn_es_MX, &yahoo_mx, &ask_es, &altavista_mx, &terra_mx, }; + +// Malaysia +const PrepopulatedEngine* engines_MY[] = + { &google, &yahoo_malaysia, &msn_en_MY, }; + +// Nicaragua +const PrepopulatedEngine* engines_NI[] = + { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, }; + +// Netherlands +const PrepopulatedEngine* engines_NL[] = + { &google, &ilse, &msn_nl_NL, &yahoo_nl, &lycos_nl, &vinden, }; + +// Norway +const PrepopulatedEngine* engines_NO[] = + { &google, &msn_nb_NO, &abcsok, &yahoo_no, &kvasir, &sesam, }; + +// New Zealand +const PrepopulatedEngine* engines_NZ[] = { &google, &yahoo_nz, &live_en_NZ, }; + +// Oman +const PrepopulatedEngine* engines_OM[] = + { &google, &maktoob, &yahoo, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Panama +const PrepopulatedEngine* engines_PA[] = + { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &lycos_es, }; + +// Peru +const PrepopulatedEngine* engines_PE[] = + { &google, &msn_es_XL, &yahoo_pe, &terra_pe, &adonde, &ohperu, }; + +// Philippines +const PrepopulatedEngine* engines_PH[] = { &google, &yahoo_ph, &msn_en_PH, }; + +// Pakistan +const PrepopulatedEngine* engines_PK[] = { &google, &yahoo, &msn, }; + +// Puerto Rico +const PrepopulatedEngine* engines_PR[] = + { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &mywebsearch, }; + +// Poland +const PrepopulatedEngine* engines_PL[] = { &google, &onet, &wp, &live_pl_PL, }; + +// Portugal +const PrepopulatedEngine* engines_PT[] = + { &google, &sapo, &yahoo, &live_pt_PT, &netindex, &aeiou, }; + +// Paraguay +const PrepopulatedEngine* engines_PY[] = + { &google, &msn_es_XL, &yahoo, &lycos_es, &yagua, &go, }; + +// Qatar +const PrepopulatedEngine* engines_QA[] = + { &google, &maktoob, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Romania +const PrepopulatedEngine* engines_RO[] = { &google, &yahoo, &live_ro_RO, }; + +// Serbia/Montenegro +const PrepopulatedEngine* engines_RS_ME[] = + { &google, &yahoo, &krstarica, &pogodak_rs, &aladin, &live, }; + +// Russia +const PrepopulatedEngine* engines_RU[] = + { &google, &yandex_ru, &rambler, &mail_ru, &yahoo_ru, &live_ru_RU, }; + +// Saudi Arabia +const PrepopulatedEngine* engines_SA[] = + { &google, &yahoo, &araby, &msn_en_XA, &msn_ar_XA, &maktoob, }; + +// Sweden +const PrepopulatedEngine* engines_SE[] = + { &google, &eniro_se, &msn_sv_SE, &altavista_se, &spray, }; + +// Singapore +const PrepopulatedEngine* engines_SG[] = + { &google, &yahoo_sg, &msn_en_SG, &rednano, }; + +// Slovenia +const PrepopulatedEngine* engines_SI[] = + { &google, &najdi, &yahoo, &matkurja, &live_sl_SI, }; + +// Slovakia +const PrepopulatedEngine* engines_SK[] = + { &google, &zoznam, ¢rum_sk, &atlas_sk, &szm, &live_sk_SK, }; + +// El Salvador +const PrepopulatedEngine* engines_SV[] = + { &google, &msn_es_XL, &yahoo, &ask_es, &altavista, &go, }; + +// Syria +const PrepopulatedEngine* engines_SY[] = + { &google, &yahoo, &maktoob, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// Thailand +const PrepopulatedEngine* engines_TH[] = + { &google, &sanook, &yahoo_th, &live_th_TH, }; + +// Tunisia +const PrepopulatedEngine* engines_TN[] = + { &google, &maktoob, &yamli, &yahoo, &msn_en_XA, &msn_ar_XA, }; + +// Turkey +const PrepopulatedEngine* engines_TR[] = + { &google, &msn_tr_TR, &yahoo, &mynet, }; + +// Trinidad and Tobago +const PrepopulatedEngine* engines_TT[] = { &google, &live, &yahoo, &go, &aol, }; + +// Taiwan +const PrepopulatedEngine* engines_TW[] = { &google, &yahoo_tw, &yam, }; + +// Ukraine +const PrepopulatedEngine* engines_UA[] = + { &google, &meta, &yandex_ua, &bigmir, &rambler, }; + +// United Kingdom +const PrepopulatedEngine* engines_UK[] = + { &google, &yahoo_uk, &msn_en_GB, &ask_uk, }; + +// United States +const PrepopulatedEngine* engines_US[] = + { &google, &yahoo, &live_en_US, &aol, &ask, }; + +// Uruguay +const PrepopulatedEngine* engines_UY[] = + { &google, &msn_es_XL, &yahoo, &go, &lycos_es, }; + +// Venezuela +const PrepopulatedEngine* engines_VE[] = + { &google, &msn_es_XL, &yahoo_ve, &altavista, }; + +// Vietnam +const PrepopulatedEngine* engines_VN[] = { &google, &yahoo_vn, }; + +// Yemen +const PrepopulatedEngine* engines_YE[] = + { &google, &yahoo, &maktoob, &yamli, &araby, &msn_en_XA, &msn_ar_XA, }; + +// South Africa +const PrepopulatedEngine* engines_ZA[] = + { &google, &yahoo, &msn_en_ZA, &mweb, &iafrica, }; + +// Zimbabwe +const PrepopulatedEngine* engines_ZW[] = { &google, &yahoo, &msn, }; + +// GeoID mappings ////////////////////////////////////////////////////////////// + +LONG GetCurrentGeoID() { + // TODO(pkasting): http://b/1225276 Much of this should live in a utility + // function somewhere. + typedef GEOID (WINAPI *GetUserGeoIDFunction)(GEOCLASS); + const HMODULE kernel32_handle = GetModuleHandle(L"kernel32.dll"); + if (!kernel32_handle) { + NOTREACHED(); + return GEOID_NOT_AVAILABLE; + } + const GetUserGeoIDFunction GetUserGeoIDPtr = + reinterpret_cast<GetUserGeoIDFunction>(GetProcAddress(kernel32_handle, + "GetUserGeoID")); + return GetUserGeoIDPtr ? + ((*GetUserGeoIDPtr)(GEOCLASS_NATION)) : GEOID_NOT_AVAILABLE; +} + +int GetGeoIDFromPrefs(PrefService* prefs) { + // See if the user overrode the GeoID on the command line. + CommandLine parsed_command_line; + const std::wstring geoID( + parsed_command_line.GetSwitchValue(switches::kGeoID)); + if (!geoID.empty()) + return _wtoi(geoID.c_str()); + + // Cache first run GeoID value in prefs, and use it afterwards. This ensures + // that just because the user moves around, we won't automatically make major + // changes to their available search providers, which would feel surprising. + if (!prefs) + return GetCurrentGeoID(); + if (!prefs->HasPrefPath(prefs::kGeoIDAtInstall)) + prefs->SetInteger(prefs::kGeoIDAtInstall, GetCurrentGeoID()); + return prefs->GetInteger(prefs::kGeoIDAtInstall); +} + +void GetPrepopulationSetFromGeoID(PrefService* prefs, + const PrepopulatedEngine*** engines, + size_t* num_engines) { + // NOTE: This function should ALWAYS set its outparams. + + // If you add a new geo id make sure and update the unit test for coverage. + + // GeoIDs are from http://msdn.microsoft.com/en-us/library/ms776390.aspx . + // Country codes and names are from http://www.geonames.org/countries/ . + switch (GetGeoIDFromPrefs(prefs)) { + +#define UNHANDLED_COUNTRY(id, code)\ + case id: +#define END_UNHANDLED_COUNTRIES(code)\ + *engines = engines_##code;\ + *num_engines = arraysize(engines_##code);\ + return; +#define DECLARE_COUNTRY(id, code)\ + UNHANDLED_COUNTRY(id, code)\ + END_UNHANDLED_COUNTRIES(code) + + // Countries with their own, dedicated engine set. + DECLARE_COUNTRY(0x4, DZ) // Algeria + DECLARE_COUNTRY(0x6, AL) // Albania + DECLARE_COUNTRY(0xB, AR) // Argentina + DECLARE_COUNTRY(0xC, AU) // Australia + DECLARE_COUNTRY(0xE, AT) // Austria + DECLARE_COUNTRY(0x11, BH) // Bahrain + DECLARE_COUNTRY(0x15, BE) // Belgium + DECLARE_COUNTRY(0x18, BZ) // Belize + DECLARE_COUNTRY(0x19, BA) // Bosnia and Herzegovina + DECLARE_COUNTRY(0x1A, BO) // Bolivia + DECLARE_COUNTRY(0x1D, BY) // Belarus + DECLARE_COUNTRY(0x20, BR) // Brazil + DECLARE_COUNTRY(0x23, BG) // Bulgaria + DECLARE_COUNTRY(0x25, BN) // Brunei + DECLARE_COUNTRY(0x27, CA) // Canada + DECLARE_COUNTRY(0x2D, CN) // China + DECLARE_COUNTRY(0x2E, CL) // Chile + DECLARE_COUNTRY(0x33, CO) // Colombia + DECLARE_COUNTRY(0x36, CR) // Costa Rica + DECLARE_COUNTRY(0x3D, DK) // Denmark + DECLARE_COUNTRY(0x41, DO) // Dominican Republic + DECLARE_COUNTRY(0x42, EC) // Ecuador + DECLARE_COUNTRY(0x43, EG) // Egypt + DECLARE_COUNTRY(0x44, IE) // Ireland + DECLARE_COUNTRY(0x46, EE) // Estonia + DECLARE_COUNTRY(0x48, SV) // El Salvador + DECLARE_COUNTRY(0x4B, CZ) // Czech Republic + DECLARE_COUNTRY(0x4D, FI) // Finland + DECLARE_COUNTRY(0x51, FO) // Faroe Islands + DECLARE_COUNTRY(0x54, FR) // France + DECLARE_COUNTRY(0x5E, DE) // Germany + DECLARE_COUNTRY(0x62, GR) // Greece + DECLARE_COUNTRY(0x63, GT) // Guatemala + DECLARE_COUNTRY(0x68, HK) // Hong Kong + DECLARE_COUNTRY(0x6A, HN) // Honduras + DECLARE_COUNTRY(0x6C, HR) // Croatia + DECLARE_COUNTRY(0x6D, HU) // Hungary + DECLARE_COUNTRY(0x6E, IS) // Iceland + DECLARE_COUNTRY(0x6F, ID) // Indonesia + DECLARE_COUNTRY(0x71, IN) // India + DECLARE_COUNTRY(0x74, IR) // Iran + DECLARE_COUNTRY(0x75, IL) // Israel + DECLARE_COUNTRY(0x76, IT) // Italy + DECLARE_COUNTRY(0x79, IQ) // Iraq + DECLARE_COUNTRY(0x7A, JP) // Japan + DECLARE_COUNTRY(0x7C, JM) // Jamaica + DECLARE_COUNTRY(0x7E, JO) // Jordan + DECLARE_COUNTRY(0x81, KE) // Kenya + DECLARE_COUNTRY(0x86, KR) // South Korea + DECLARE_COUNTRY(0x88, KW) // Kuwait + DECLARE_COUNTRY(0x8B, LB) // Lebanon + DECLARE_COUNTRY(0x8C, LV) // Latvia + DECLARE_COUNTRY(0x8D, LT) // Lithuania + DECLARE_COUNTRY(0x8F, SK) // Slovakia + DECLARE_COUNTRY(0x91, LI) // Liechtenstein + DECLARE_COUNTRY(0x93, LU) // Luxembourg + DECLARE_COUNTRY(0x94, LY) // Libya + DECLARE_COUNTRY(0x9E, MC) // Monaco + DECLARE_COUNTRY(0x9F, MA) // Morocco + DECLARE_COUNTRY(0xA4, OM) // Oman + DECLARE_COUNTRY(0xA6, MX) // Mexico + DECLARE_COUNTRY(0xA7, MY) // Malaysia + DECLARE_COUNTRY(0xB0, NL) // Netherlands + DECLARE_COUNTRY(0xB1, NO) // Norway + DECLARE_COUNTRY(0xB6, NI) // Nicaragua + DECLARE_COUNTRY(0xB7, NZ) // New Zealand + DECLARE_COUNTRY(0xB9, PY) // Paraguay + DECLARE_COUNTRY(0xBB, PE) // Peru + DECLARE_COUNTRY(0xBE, PK) // Pakistan + DECLARE_COUNTRY(0xBF, PL) // Poland + DECLARE_COUNTRY(0xC0, PA) // Panama + DECLARE_COUNTRY(0xC1, PT) // Portugal + DECLARE_COUNTRY(0xC5, QA) // Qatar + DECLARE_COUNTRY(0xC8, RO) // Romania + DECLARE_COUNTRY(0xC9, PH) // Philippines + DECLARE_COUNTRY(0xCA, PR) // Puerto Rico + DECLARE_COUNTRY(0xCB, RU) // Russia + DECLARE_COUNTRY(0xCD, SA) // Saudi Arabia + DECLARE_COUNTRY(0xD1, ZA) // South Africa + DECLARE_COUNTRY(0xD4, SI) // Slovenia + DECLARE_COUNTRY(0xD7, SG) // Singapore + DECLARE_COUNTRY(0xD9, ES) // Spain + DECLARE_COUNTRY(0xDD, SE) // Sweden + DECLARE_COUNTRY(0xDE, SY) // Syria + DECLARE_COUNTRY(0xDF, CH) // Switzerland + DECLARE_COUNTRY(0xE0, AE) // United Arab Emirates + DECLARE_COUNTRY(0xE1, TT) // Trinidad and Tobago + DECLARE_COUNTRY(0xE3, TH) // Thailand + DECLARE_COUNTRY(0xEA, TN) // Tunisia + DECLARE_COUNTRY(0xEB, TR) // Turkey + DECLARE_COUNTRY(0xED, TW) // Taiwan + DECLARE_COUNTRY(0xF1, UA) // Ukraine + DECLARE_COUNTRY(0xF2, UK) // United Kingdom + DECLARE_COUNTRY(0xF4, US) // United States + DECLARE_COUNTRY(0xF6, UY) // Uruguay + DECLARE_COUNTRY(0xF9, VE) // Venezuela + DECLARE_COUNTRY(0xFB, VN) // Vietnam + DECLARE_COUNTRY(0x105, YE) // Yemen + DECLARE_COUNTRY(0x108, ZW) // Zimbabwe + DECLARE_COUNTRY(0x10D, RS_ME) // Serbia/Montenegro + DECLARE_COUNTRY(0x4CA2, MK) // Macedonia + + // Countries using the "Australia" engine set. + UNHANDLED_COUNTRY(0x130, XX) // Ashmore and Cartier Islands + UNHANDLED_COUNTRY(0x135, CX) // Christmas Island + UNHANDLED_COUNTRY(0x137, CC) // Cocos Islands + UNHANDLED_COUNTRY(0x139, XX) // Coral Sea Islands + UNHANDLED_COUNTRY(0x145, HM) // Heard Island and McDonald Islands + UNHANDLED_COUNTRY(0x150, NF) // Norfolk Island + END_UNHANDLED_COUNTRIES(AU) + + // Countries using the "China" engine set. + UNHANDLED_COUNTRY(0x97, MO) // Macao + END_UNHANDLED_COUNTRIES(CN) + + // Countries using the "Denmark" engine set. + UNHANDLED_COUNTRY(0x5D, GL) // Greenland + END_UNHANDLED_COUNTRIES(DK) + + // Countries using the "Spain" engine set. + UNHANDLED_COUNTRY(0x8, AD) // Andorra + END_UNHANDLED_COUNTRIES(ES) + + // Countries using the "France" engine set. + UNHANDLED_COUNTRY(0x1C, BJ) // Benin + UNHANDLED_COUNTRY(0x26, BI) // Burundi + UNHANDLED_COUNTRY(0x29, TD) // Chad + UNHANDLED_COUNTRY(0x2B, CG) // Congo - Brazzaville + UNHANDLED_COUNTRY(0x2C, CD) // Congo - Kinshasa + UNHANDLED_COUNTRY(0x31, CM) // Cameroon + UNHANDLED_COUNTRY(0x37, CF) // Central African Republic + UNHANDLED_COUNTRY(0x3E, DJ) // Djibouti + UNHANDLED_COUNTRY(0x57, GA) // Gabon + UNHANDLED_COUNTRY(0x64, GN) // Guinea + UNHANDLED_COUNTRY(0x67, HT) // Haiti + UNHANDLED_COUNTRY(0x77, CI) // Ivory Coast + UNHANDLED_COUNTRY(0x9D, ML) // Mali + UNHANDLED_COUNTRY(0xAD, NE) // Niger + UNHANDLED_COUNTRY(0xC6, RE) // Reunion + UNHANDLED_COUNTRY(0xCE, PM) // Saint Pierre and Miquelon + UNHANDLED_COUNTRY(0xD2, SN) // Senegal + UNHANDLED_COUNTRY(0xE8, TG) // Togo + UNHANDLED_COUNTRY(0xF5, BF) // Burkina Faso + UNHANDLED_COUNTRY(0x136, XX) // Clipperton Island + UNHANDLED_COUNTRY(0x13D, GF) // French Guiana + UNHANDLED_COUNTRY(0x13E, PF) // French Polynesia + UNHANDLED_COUNTRY(0x13F, TF) // French Southern Territories + UNHANDLED_COUNTRY(0x141, GP) // Guadeloupe + UNHANDLED_COUNTRY(0x14A, MQ) // Martinique + UNHANDLED_COUNTRY(0x14B, YT) // Mayotte + UNHANDLED_COUNTRY(0x14E, NC) // New Caledonia + UNHANDLED_COUNTRY(0x160, WF) // Wallis and Futuna + END_UNHANDLED_COUNTRIES(FR) + + // Countries using the "Greece" engine set. + UNHANDLED_COUNTRY(0x3B, CY) // Cyprus + END_UNHANDLED_COUNTRIES(GR) + + // Countries using the "Italy" engine set. + UNHANDLED_COUNTRY(0xD6, SM) // San Marino + UNHANDLED_COUNTRY(0xFD, VA) // Vatican + END_UNHANDLED_COUNTRIES(IT) + + // Countries using the "Netherlands" engine set. + UNHANDLED_COUNTRY(0x12E, AW) // Aruba + UNHANDLED_COUNTRY(0x14D, AN) // Netherlands Antilles + END_UNHANDLED_COUNTRIES(NL) + + // Countries using the "Norway" engine set. + UNHANDLED_COUNTRY(0x7D, SJ) // [Svalbard and] Jan Mayen + UNHANDLED_COUNTRY(0xDC, SJ) // Svalbard [and Jan Mayen] + UNHANDLED_COUNTRY(0x132, BV) // Bouvet Island + END_UNHANDLED_COUNTRIES(NO) + + // Countries using the "New Zealand" engine set. + UNHANDLED_COUNTRY(0x138, CK) // Cook Islands + UNHANDLED_COUNTRY(0x14F, NU) // Niue + UNHANDLED_COUNTRY(0x15B, TK) // Tokelau + END_UNHANDLED_COUNTRIES(NZ) + + // Countries using the "Portugal" engine set. + UNHANDLED_COUNTRY(0x39, CV) // Cape Verde + UNHANDLED_COUNTRY(0xA8, MZ) // Mozambique + UNHANDLED_COUNTRY(0xC4, GW) // Guinea-Bissau + UNHANDLED_COUNTRY(0xE9, ST) // Sao Tome and Principe + UNHANDLED_COUNTRY(0x6F60E7, TL) // East Timor + END_UNHANDLED_COUNTRIES(PT) + + // Countries using the "Russia" engine set. + UNHANDLED_COUNTRY(0x5, AZ) // Azerbaijan + UNHANDLED_COUNTRY(0x7, AM) // Armenia + UNHANDLED_COUNTRY(0x82, KG) // Kyrgyzstan + UNHANDLED_COUNTRY(0x89, KZ) // Kazakhstan + UNHANDLED_COUNTRY(0xE4, TJ) // Tajikistan + UNHANDLED_COUNTRY(0xEE, TM) // Turkmenistan + UNHANDLED_COUNTRY(0xF7, UZ) // Uzbekistan + END_UNHANDLED_COUNTRIES(RU) + + // Countries using the "Saudi Arabia" engine set. + UNHANDLED_COUNTRY(0xA2, MR) // Mauritania + UNHANDLED_COUNTRY(0xB8, PS) // Palestinian Territory + UNHANDLED_COUNTRY(0xDB, SD) // Sudan + END_UNHANDLED_COUNTRIES(SA) + + // Countries using the "United Kingdom" engine set. + UNHANDLED_COUNTRY(0x14, BM) // Bermuda + UNHANDLED_COUNTRY(0x5A, GI) // Gibraltar + UNHANDLED_COUNTRY(0x72, IO) // British Indian Ocean Territory + UNHANDLED_COUNTRY(0xA3, MT) // Malta + UNHANDLED_COUNTRY(0x12F, XX) // Ascension Island + UNHANDLED_COUNTRY(0x133, KY) // Cayman Islands + UNHANDLED_COUNTRY(0x134, XX) // Channel Islands + UNHANDLED_COUNTRY(0x13A, XX) // Diego Garcia + UNHANDLED_COUNTRY(0x13B, FK) // Falkland Islands + UNHANDLED_COUNTRY(0x144, GG) // Guernsey + UNHANDLED_COUNTRY(0x148, JE) // Jersey + UNHANDLED_COUNTRY(0x14C, MS) // Montserrat + UNHANDLED_COUNTRY(0x153, PN) // Pitcairn Islands + UNHANDLED_COUNTRY(0x156, GS) // South Georgia and the South Sandwich + // Islands + UNHANDLED_COUNTRY(0x157, SH) // Saint Helena + UNHANDLED_COUNTRY(0x15C, XX) // Tristan da Cunha + UNHANDLED_COUNTRY(0x15D, TC) // Turks and Caicos Islands + UNHANDLED_COUNTRY(0x15F, VG) // British Virgin Islands + UNHANDLED_COUNTRY(0x3B16, IM) // Isle of Man + END_UNHANDLED_COUNTRIES(UK) + + // Countries using the "United States" engine set. + UNHANDLED_COUNTRY(0xA, AS) // American Samoa + UNHANDLED_COUNTRY(0x7F, XX) // Johnston Atoll + UNHANDLED_COUNTRY(0xFC, VI) // U.S. Virgin Islands + UNHANDLED_COUNTRY(0x102, XX) // Wake Island + UNHANDLED_COUNTRY(0x131, XX) // Baker Island + UNHANDLED_COUNTRY(0x142, GU) // Guam + UNHANDLED_COUNTRY(0x146, XX) // Howland Island + UNHANDLED_COUNTRY(0x147, XX) // Jarvis Island + UNHANDLED_COUNTRY(0x149, XX) // Kingman Reef + UNHANDLED_COUNTRY(0x151, MP) // Northern Mariana Islands + UNHANDLED_COUNTRY(0x152, XX) // Palmyra Atoll + UNHANDLED_COUNTRY(0x154, XX) // Rota Island + UNHANDLED_COUNTRY(0x155, XX) // Saipan + UNHANDLED_COUNTRY(0x15A, XX) // Tinian Island + UNHANDLED_COUNTRY(0x52FA, XX) // Midway Islands + END_UNHANDLED_COUNTRIES(US) + + // Countries using the "default" engine set. + UNHANDLED_COUNTRY(0x2, AG) // Antigua and Barbuda + UNHANDLED_COUNTRY(0x3, AF) // Afghanistan + UNHANDLED_COUNTRY(0x9, AO) // Angola + UNHANDLED_COUNTRY(0x12, BB) // Barbados + UNHANDLED_COUNTRY(0x13, BW) // Botswana + UNHANDLED_COUNTRY(0x16, BS) // Bahamas + UNHANDLED_COUNTRY(0x17, BD) // Bangladesh + UNHANDLED_COUNTRY(0x1B, MM) // Myanmar + UNHANDLED_COUNTRY(0x1E, SB) // Solomon Islands + UNHANDLED_COUNTRY(0x22, BT) // Bhutan + UNHANDLED_COUNTRY(0x28, KH) // Cambodia + UNHANDLED_COUNTRY(0x2A, LK) // Sri Lanka + UNHANDLED_COUNTRY(0x32, KM) // Comoros + UNHANDLED_COUNTRY(0x38, CU) // Cuba + UNHANDLED_COUNTRY(0x3F, DM) // Dominica + UNHANDLED_COUNTRY(0x45, GQ) // Equatorial Guinea + UNHANDLED_COUNTRY(0x47, ER) // Eritrea + UNHANDLED_COUNTRY(0x49, ET) // Ethiopia + UNHANDLED_COUNTRY(0x4E, FJ) // Fiji + UNHANDLED_COUNTRY(0x50, FM) // Micronesia + UNHANDLED_COUNTRY(0x56, GM) // Gambia + UNHANDLED_COUNTRY(0x58, GE) // Georgia + UNHANDLED_COUNTRY(0x59, GH) // Ghana + UNHANDLED_COUNTRY(0x5B, GD) // Grenada + UNHANDLED_COUNTRY(0x65, GY) // Guyana + UNHANDLED_COUNTRY(0x83, KP) // North Korea + UNHANDLED_COUNTRY(0x85, KI) // Kiribati + UNHANDLED_COUNTRY(0x8A, LA) // Laos + UNHANDLED_COUNTRY(0x8E, LR) // Liberia + UNHANDLED_COUNTRY(0x92, LS) // Lesotho + UNHANDLED_COUNTRY(0x95, MG) // Madagascar + UNHANDLED_COUNTRY(0x98, MD) // Moldova + UNHANDLED_COUNTRY(0x9A, MN) // Mongolia + UNHANDLED_COUNTRY(0x9C, MW) // Malawi + UNHANDLED_COUNTRY(0xA0, MU) // Mauritius + UNHANDLED_COUNTRY(0xA5, MV) // Maldives + UNHANDLED_COUNTRY(0xAE, VU) // Vanuatu + UNHANDLED_COUNTRY(0xAF, NG) // Nigeria + UNHANDLED_COUNTRY(0xB2, NP) // Nepal + UNHANDLED_COUNTRY(0xB4, NR) // Nauru + UNHANDLED_COUNTRY(0xB5, SR) // Suriname + UNHANDLED_COUNTRY(0xC2, PG) // Papua New Guinea + UNHANDLED_COUNTRY(0xC3, PW) // Palau + UNHANDLED_COUNTRY(0xC7, MH) // Marshall Islands + UNHANDLED_COUNTRY(0xCC, RW) // Rwanda + UNHANDLED_COUNTRY(0xCF, KN) // Saint Kitts and Nevis + UNHANDLED_COUNTRY(0xD0, SC) // Seychelles + UNHANDLED_COUNTRY(0xD5, SL) // Sierra Leone + UNHANDLED_COUNTRY(0xD8, SO) // Somalia + UNHANDLED_COUNTRY(0xDA, LC) // Saint Lucia + UNHANDLED_COUNTRY(0xE7, TO) // Tonga + UNHANDLED_COUNTRY(0xEC, TV) // Tuvalu + UNHANDLED_COUNTRY(0xEF, TZ) // Tanzania + UNHANDLED_COUNTRY(0xF0, UG) // Uganda + UNHANDLED_COUNTRY(0xF8, VC) // Saint Vincent and the + // Grenadines + UNHANDLED_COUNTRY(0xFE, NA) // Namibia + UNHANDLED_COUNTRY(0x103, WS) // Samoa + UNHANDLED_COUNTRY(0x104, SZ) // Swaziland + UNHANDLED_COUNTRY(0x107, ZM) // Zambia + UNHANDLED_COUNTRY(0x12C, AI) // Anguilla + UNHANDLED_COUNTRY(0x12D, AQ) // Antarctica + UNHANDLED_COUNTRY(0x143, XX) // Guantanamo Bay + UNHANDLED_COUNTRY(GEOID_NOT_AVAILABLE, XX) // Unknown location + default: // Unhandled location + END_UNHANDLED_COUNTRIES(default) + } +} + +} // namespace + +namespace TemplateURLPrepopulateData { + +void RegisterUserPrefs(PrefService* prefs) { + prefs->RegisterIntegerPref(prefs::kGeoIDAtInstall, -1); +} + +int GetDataVersion() { + return 19; // Increment this if you change the above data in ways that mean + // users with existing data should get a new version. +} + +void GetPrepopulatedEngines(PrefService* prefs, + std::vector<TemplateURL*>* t_urls, + size_t* default_search_provider_index) { + // TODO(pkasting): http://b/1225464 GeoID is not available on Win2k. We'll + // need to do something else there. + const PrepopulatedEngine** engines; + size_t num_engines; + GetPrepopulationSetFromGeoID(prefs, &engines, &num_engines); + *default_search_provider_index = 0; + + for (size_t i = 0; i < num_engines; ++i) { + TemplateURL* new_turl = new TemplateURL(); + new_turl->SetURL(engines[i]->search_url, 0, 0); + if (engines[i]->favicon_url) + new_turl->SetFavIconURL(GURL(engines[i]->favicon_url)); + if (engines[i]->suggest_url) + new_turl->SetSuggestionsURL(engines[i]->suggest_url, 0, 0); + new_turl->set_short_name(engines[i]->name); + if (engines[i]->keyword == NULL) + new_turl->set_autogenerate_keyword(true); + else + new_turl->set_keyword(engines[i]->keyword); + new_turl->set_show_in_default_list(true); + new_turl->set_safe_for_autoreplace(true); + new_turl->set_date_created(Time()); + std::vector<std::string> turl_encodings; + turl_encodings.push_back(engines[i]->encoding); + new_turl->set_input_encodings(turl_encodings); + new_turl->set_prepopulate_id(engines[i]->id); + t_urls->push_back(new_turl); + } +} + +} // namespace TemplateURLPrepopulateData diff --git a/chrome/browser/template_url_prepopulate_data.h b/chrome/browser/template_url_prepopulate_data.h new file mode 100644 index 0000000..9bc3a70 --- /dev/null +++ b/chrome/browser/template_url_prepopulate_data.h @@ -0,0 +1,32 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TEMPLATE_URL_PREPOPULATE_DATA_H__ +#define CHROME_BROWSER_TEMPLATE_URL_PREPOPULATE_DATA_H__ + +#include <vector> + +class PrefService; +class TemplateURL; + +namespace TemplateURLPrepopulateData { + +void RegisterUserPrefs(PrefService* prefs); + +// Returns the current version of the prepopulate data, so callers can know when +// they need to re-merge. +int GetDataVersion(); + +// Loads the set of TemplateURLs from the prepopulate data. Ownership of the +// TemplateURLs is passed to the caller. On return, +// |default_search_provider_index| is set to the index of the default search +// provider. +void GetPrepopulatedEngines(PrefService* prefs, + std::vector<TemplateURL*>* t_urls, + size_t* default_search_provider_index); + +} // namespace TemplateURLPrepopulateData + +#endif // CHROME_BROWSER_TEMPLATE_URL_PREPOPULATE_DATA_H__ + diff --git a/chrome/browser/template_url_prepopulate_data_unittest.cc b/chrome/browser/template_url_prepopulate_data_unittest.cc new file mode 100644 index 0000000..14c6abb --- /dev/null +++ b/chrome/browser/template_url_prepopulate_data_unittest.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_prepopulate_data.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/scoped_vector.h" +#include "chrome/test/testing_profile.h" +#include "testing/gtest/include/gtest/gtest.h" + +typedef testing::Test TemplateURLPrepopulateDataTest; + +// Verifies the set of prepopulate data doesn't contain entries with duplicate +// ids. +TEST_F(TemplateURLPrepopulateDataTest, UniqueIDs) { + // GEO ids. + int ids[] = { 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, + 0xE, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0x23, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x32, + 0x33, 0x36, 0x37, 0x38, 0x39, 0x3B, 0x3D, 0x3E, 0x3F, 0x41, + 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4B, 0x4D, + 0x4E, 0x50, 0x51, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, + 0x5D, 0x5E, 0x62, 0x63, 0x64, 0x65, 0x67, 0x68, 0x6A, 0x6C, + 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x74, 0x75, 0x76, 0x77, 0x79, + 0x7A, 0x7C, 0x7D, 0x7E, 0x7F, 0x81, 0x82, 0x83, 0x85, 0x86, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x97, 0x98, 0x9A, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xAD, 0xAE, + 0xAF, 0xB0, 0xB1, 0xB2, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, + 0xBB, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, + 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, + 0xD1, 0xD2, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, + 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE3, 0xE4, 0xE7, 0xE8, + 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, + 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFB, 0xFC, 0xFD, 0xFE, + 0x102, 0x103, 0x104, 0x105, 0x107, 0x108, 0x10D, 0x12C, 0x12D, + 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136, + 0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13D, 0x13E, 0x13F, 0x141, + 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, + 0x14B, 0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, + 0x154, 0x155, 0x156, 0x157, 0x15A, 0x15B, 0x15C, 0x15D, 0x15F, + 0x160, 0x3B16, 0x4CA2, 0x52FA, 0x6F60E7, -1 }; + TestingProfile profile; + for (size_t i = 0; i < arraysize(ids); ++i) { + profile.GetPrefs()->SetInteger(prefs::kGeoIDAtInstall, ids[i]); + ScopedVector<TemplateURL> urls; + size_t url_count; + TemplateURLPrepopulateData::GetPrepopulatedEngines( + profile.GetPrefs(), &(urls.get()), &url_count); + std::set<int> unique_ids; + for (size_t turl_i = 0; turl_i < urls.size(); ++turl_i) { + ASSERT_TRUE(unique_ids.find(urls[turl_i]->prepopulate_id()) == + unique_ids.end()); + unique_ids.insert(urls[turl_i]->prepopulate_id()); + } + } +} diff --git a/chrome/browser/template_url_unittest.cc b/chrome/browser/template_url_unittest.cc new file mode 100644 index 0000000..d5d745f --- /dev/null +++ b/chrome/browser/template_url_unittest.cc @@ -0,0 +1,386 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/string_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/rlz/rlz.h" +#include "chrome/browser/template_url.h" +#include "testing/gtest/include/gtest/gtest.h" + +class TemplateURLTest : public testing::Test { + public: + virtual void TearDown() { + delete TemplateURLRef::google_base_url_; + TemplateURLRef::google_base_url_ = NULL; + } + + void CheckSuggestBaseURL(const wchar_t* base_url, + const wchar_t* base_suggest_url) const { + delete TemplateURLRef::google_base_url_; + TemplateURLRef::google_base_url_ = new std::wstring(base_url); + EXPECT_STREQ(base_suggest_url, + TemplateURLRef::GoogleBaseSuggestURLValue().c_str()); + } +}; + +TEST_F(TemplateURLTest, Defaults) { + TemplateURL url; + ASSERT_FALSE(url.show_in_default_list()); + ASSERT_FALSE(url.safe_for_autoreplace()); + ASSERT_EQ(0, url.prepopulate_id()); +} + +TEST_F(TemplateURLTest, TestValidWithComplete) { + TemplateURLRef ref(L"{searchTerms}", 0, 0); + ASSERT_TRUE(ref.IsValid()); +} + +TEST_F(TemplateURLTest, URLRefTestSearchTerms) { + TemplateURL t_url; + TemplateURLRef ref(L"http://foo{searchTerms}", 0, 0); + ASSERT_TRUE(ref.IsValid()); + + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"search", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://foosearch/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTestCount) { + TemplateURL t_url; + TemplateURLRef ref(L"http://foo{searchTerms}{count?}", 0, 0); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://foox/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTestCount2) { + TemplateURL t_url; + TemplateURLRef ref(L"http://foo{searchTerms}{count}", 0, 0); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://foox10/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTestIndices) { + TemplateURL t_url; + TemplateURLRef ref(L"http://foo{searchTerms}x{startIndex?}y{startPage?}", + 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://fooxxy/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTestIndices2) { + TemplateURL t_url; + TemplateURLRef ref(L"http://foo{searchTerms}x{startIndex}y{startPage}", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://fooxx1y2/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTestEncoding) { + TemplateURL t_url; + TemplateURLRef ref( + L"http://foo{searchTerms}x{inputEncoding?}y{outputEncoding?}a", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://fooxxutf-8ya/", result.spec()); +} + +TEST_F(TemplateURLTest, InputEncodingBeforeSearchTerm) { + TemplateURL t_url; + TemplateURLRef ref( + L"http://foox{inputEncoding?}a{searchTerms}y{outputEncoding?}b", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://fooxutf-8axyb/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTestEncoding2) { + TemplateURL t_url; + TemplateURLRef ref( + L"http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + ASSERT_EQ("http://fooxxutf-8yutf-8a/", result.spec()); +} + +TEST_F(TemplateURLTest, URLRefTermToWide) { + struct ToWideCase { + const char* encoded_search_term; + const wchar_t* expected_decoded_term; + } to_wide_cases[] = { + {"hello+world", L"hello world"}, + // Test some big-5 input. + {"%a7A%A6%6e+to+you", L"\x4f60\x597d to you"}, + // Test some UTF-8 input. We should fall back to this when the encoding + // doesn't look like big-5. We have a '5' in the middle, which is an invalid + // Big-5 trailing byte. + {"%e4%bd%a05%e5%a5%bd+to+you", L"\x4f60\x35\x597d to you"}, + // Undecodable input should stay escaped. + {"%91%01+abcd", L"%91%01 abcd"}, + }; + + TemplateURL t_url; + + // Set one input encoding: big-5. This is so we can test fallback to UTF-8. + std::vector<std::string> encodings; + encodings.push_back("big-5"); + t_url.set_input_encodings(encodings); + + TemplateURLRef ref(L"http://foo?q={searchTerms}", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + + for (int i = 0; i < arraysize(to_wide_cases); i++) { + std::wstring result = ref.SearchTermToWide(t_url, + to_wide_cases[i].encoded_search_term); + + EXPECT_EQ(std::wstring(to_wide_cases[i].expected_decoded_term), result); + } +} + +TEST_F(TemplateURLTest, SetFavIcon) { + TemplateURL url; + GURL favicon_url("http://favicon.url"); + url.SetFavIconURL(favicon_url); + ASSERT_EQ(1, url.image_refs().size()); + ASSERT_TRUE(favicon_url == url.GetFavIconURL()); + + GURL favicon_url2("http://favicon2.url"); + url.SetFavIconURL(favicon_url2); + ASSERT_EQ(1, url.image_refs().size()); + ASSERT_TRUE(favicon_url2 == url.GetFavIconURL()); +} + +TEST_F(TemplateURLTest, DisplayURLToURLRef) { + struct TestData { + const std::wstring url; + const std::wstring expected_result; + } data[] = { + { L"http://foo{searchTerms}x{inputEncoding}y{outputEncoding}a", + L"http://foo%sx{inputEncoding}y{outputEncoding}a" }, + { L"http://X", + L"http://X" }, + { L"http://foo{searchTerms", + L"http://foo{searchTerms" }, + { L"http://foo{searchTerms}{language}", + L"http://foo%s{language}" }, + }; + for (int i = 0; i < arraysize(data); ++i) { + TemplateURLRef ref(data[i].url, 1, 2); + EXPECT_EQ(data[i].expected_result, ref.DisplayURL()); + EXPECT_EQ(data[i].url, + TemplateURLRef::DisplayURLToURLRef(ref.DisplayURL())); + } +} + +TEST_F(TemplateURLTest, ReplaceSearchTerms) { + struct TestData { + const std::wstring url; + const std::string expected_result; + } data[] = { + { L"http://foo/{language}{searchTerms}{inputEncoding}", + "http://foo/{language}XUTF-8" }, + { L"http://foo/{language}{inputEncoding}{searchTerms}", + "http://foo/{language}UTF-8X" }, + { L"http://foo/{searchTerms}{language}{inputEncoding}", + "http://foo/X{language}UTF-8" }, + { L"http://foo/{searchTerms}{inputEncoding}{language}", + "http://foo/XUTF-8{language}" }, + { L"http://foo/{inputEncoding}{searchTerms}{language}", + "http://foo/UTF-8X{language}" }, + { L"http://foo/{inputEncoding}{language}{searchTerms}", + "http://foo/UTF-8{language}X" }, + { L"http://foo/{language}a{searchTerms}a{inputEncoding}a", + "http://foo/{language}aXaUTF-8a" }, + { L"http://foo/{language}a{inputEncoding}a{searchTerms}a", + "http://foo/{language}aUTF-8aXa" }, + { L"http://foo/{searchTerms}a{language}a{inputEncoding}a", + "http://foo/Xa{language}aUTF-8a" }, + { L"http://foo/{searchTerms}a{inputEncoding}a{language}a", + "http://foo/XaUTF-8a{language}a" }, + { L"http://foo/{inputEncoding}a{searchTerms}a{language}a", + "http://foo/UTF-8aXa{language}a" }, + { L"http://foo/{inputEncoding}a{language}a{searchTerms}a", + "http://foo/UTF-8a{language}aXa" }, + }; + TemplateURL turl; + turl.add_input_encoding("UTF-8"); + for (int i = 0; i < arraysize(data); ++i) { + TemplateURLRef ref(data[i].url, 1, 2); + EXPECT_TRUE(ref.IsValid()); + EXPECT_TRUE(ref.SupportsReplacement()); + std::string expected_result = data[i].expected_result; + ReplaceSubstringsAfterOffset(&expected_result, 0, "{language}", + WideToASCII(g_browser_process->GetApplicationLocale())); + GURL result = ref.ReplaceSearchTerms(turl, L"X", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + EXPECT_TRUE(result.is_valid()); + EXPECT_EQ(expected_result, result.spec()); + } +} + + +// Tests replacing search terms in various encodings and making sure the +// generated URL matches the expected value. +TEST_F(TemplateURLTest, ReplaceArbitrarySearchTerms) { + struct TestData { + const std::string encoding; + const std::wstring search_term; + const std::wstring url; + const std::string expected_result; + } data[] = { + { "BIG5", L"\x60BD", L"http://foo/{searchTerms}{inputEncoding}", + "http://foo/%B1~BIG5" }, + { "UTF-8", L"blah", L"http://foo/{searchTerms}{inputEncoding}", + "http://foo/blahUTF-8" }, + }; + for (int i = 0; i < arraysize(data); ++i) { + TemplateURL turl; + turl.add_input_encoding(data[i].encoding); + TemplateURLRef ref(data[i].url, 1, 2); + GURL result = ref.ReplaceSearchTerms(turl, data[i].search_term, + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + EXPECT_TRUE(result.is_valid()); + EXPECT_EQ(data[i].expected_result, result.spec()); + } +} + +TEST_F(TemplateURLTest, Suggestions) { + struct TestData { + const int accepted_suggestion; + const std::wstring original_query_for_suggestion; + const std::string expected_result; + } data[] = { + { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring(), + "http://bar/foo?q=foobar" }, + { TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, L"foo", + "http://bar/foo?q=foobar" }, + { TemplateURLRef::NO_SUGGESTION_CHOSEN, std::wstring(), + "http://bar/foo?aq=f&q=foobar" }, + { TemplateURLRef::NO_SUGGESTION_CHOSEN, L"foo", + "http://bar/foo?aq=f&q=foobar" }, + { 0, std::wstring(), "http://bar/foo?aq=0&oq=&q=foobar" }, + { 1, L"foo", "http://bar/foo?aq=1&oq=foo&q=foobar" }, + }; + TemplateURL turl; + turl.add_input_encoding("UTF-8"); + TemplateURLRef ref(L"http://bar/foo?{google:acceptedSuggestion}" + L"{google:originalQueryForSuggestion}q={searchTerms}", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + for (int i = 0; i < arraysize(data); ++i) { + GURL result = ref.ReplaceSearchTerms(turl, L"foobar", + data[i].accepted_suggestion, data[i].original_query_for_suggestion); + EXPECT_TRUE(result.is_valid()); + EXPECT_EQ(data[i].expected_result, result.spec()); + } +} + +TEST_F(TemplateURLTest, RLZ) { + std::wstring rlz_string; + RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &rlz_string); + + TemplateURL t_url; + TemplateURLRef ref(L"http://bar/{google:RLZ}{searchTerms}", 1, 2); + ASSERT_TRUE(ref.IsValid()); + ASSERT_TRUE(ref.SupportsReplacement()); + GURL result = ref.ReplaceSearchTerms(t_url, L"x", + TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()); + ASSERT_TRUE(result.is_valid()); + // TODO(levin): fix this! + // ASSERT_EQ("http://bar/" + WideToUTF8(rlz_string) + "x", result.spec()); +} + +TEST_F(TemplateURLTest, HostAndSearchTermKey) { + struct TestData { + const std::wstring url; + const std::string host; + const std::string path; + const std::string search_term_key; + } data[] = { + { L"http://blah/?foo=bar&q={searchTerms}&b=x", "blah", "/", "q"}, + + // No query key should result in empty values. + { L"http://blah/{searchTerms}", "", "", ""}, + + // No term should result in empty values. + { L"http://blah/", "", "", ""}, + + // Multiple terms should result in empty values. + { L"http://blah/?q={searchTerms}&x={searchTerms}", "", "", ""}, + + // Term in the host shouldn't match. + { L"http://{searchTerms}", "", "", ""}, + + { L"http://blah/?q={searchTerms}", "blah", "/", "q"}, + + // Single term with extra chars in value should match. + { L"http://blah/?q=stock:{searchTerms}", "blah", "/", "q"}, + + }; + + TemplateURL t_url; + for (int i = 0; i < arraysize(data); ++i) { + t_url.SetURL(data[i].url, 0, 0); + EXPECT_EQ(data[i].host, t_url.url()->GetHost()); + EXPECT_EQ(data[i].path, t_url.url()->GetPath()); + EXPECT_EQ(data[i].search_term_key, t_url.url()->GetSearchTermKey()); + } +} + +TEST_F(TemplateURLTest, GoogleBaseSuggestURL) { + static const struct { + const wchar_t* const base_url; + const wchar_t* const base_suggest_url; + } data[] = { + { L"http://google.com/", L"http://clients1.google.com/complete/", }, + { L"http://www.google.com/", L"http://clients1.google.com/complete/", }, + { L"http://www.google.co.uk/", L"http://clients1.google.co.uk/complete/", }, + { L"http://www.google.com.by/", + L"http://clients1.google.com.by/complete/", }, + { L"http://google.com/intl/xx/", L"http://clients1.google.com/complete/", }, + }; + + for (int i = 0; i < arraysize(data); ++i) + CheckSuggestBaseURL(data[i].base_url, data[i].base_suggest_url); +} + +TEST_F(TemplateURLTest, Keyword) { + TemplateURL t_url; + t_url.SetURL(L"http://www.google.com/search", 0, 0); + EXPECT_FALSE(t_url.autogenerate_keyword()); + t_url.set_keyword(L"foo"); + EXPECT_EQ(L"foo", t_url.keyword()); + t_url.set_autogenerate_keyword(true); + EXPECT_TRUE(t_url.autogenerate_keyword()); + EXPECT_EQ(L"google.com", t_url.keyword()); + t_url.set_keyword(L"foo"); + EXPECT_FALSE(t_url.autogenerate_keyword()); + EXPECT_EQ(L"foo", t_url.keyword()); +} diff --git a/chrome/browser/views/clear_browsing_data.cc b/chrome/browser/views/clear_browsing_data.cc index 2bdd1f2..b71bf99 100644 --- a/chrome/browser/views/clear_browsing_data.cc +++ b/chrome/browser/views/clear_browsing_data.cc @@ -6,7 +6,7 @@ #include "chrome/app/locales/locale_settings.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/views/standard_layout.h" #include "chrome/common/l10n_util.h" #include "chrome/views/background.h" diff --git a/chrome/browser/views/edit_keyword_controller.cc b/chrome/browser/views/edit_keyword_controller.cc index 86f1cd0..4eb913f 100644 --- a/chrome/browser/views/edit_keyword_controller.cc +++ b/chrome/browser/views/edit_keyword_controller.cc @@ -7,8 +7,8 @@ #include "base/string_util.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/url_fixer_upper.h" #include "chrome/browser/user_metrics.h" #include "chrome/browser/views/keyword_editor_view.h" diff --git a/chrome/browser/views/first_run_bubble.cc b/chrome/browser/views/first_run_bubble.cc index 25b01db..ac6678a 100644 --- a/chrome/browser/views/first_run_bubble.cc +++ b/chrome/browser/views/first_run_bubble.cc @@ -10,7 +10,7 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/options_window.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/views/standard_layout.h" #include "chrome/common/l10n_util.h" #include "chrome/common/resource_bundle.h" diff --git a/chrome/browser/views/keyword_editor_view.cc b/chrome/browser/views/keyword_editor_view.cc index e4acaa6..be35283 100644 --- a/chrome/browser/views/keyword_editor_view.cc +++ b/chrome/browser/views/keyword_editor_view.cc @@ -12,8 +12,8 @@ #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/history/history.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/user_metrics.h" #include "chrome/browser/views/edit_keyword_controller.h" #include "chrome/browser/views/standard_layout.h" diff --git a/chrome/browser/views/keyword_editor_view.h b/chrome/browser/views/keyword_editor_view.h index c2135a4..879ed24 100644 --- a/chrome/browser/views/keyword_editor_view.h +++ b/chrome/browser/views/keyword_editor_view.h @@ -9,7 +9,7 @@ #include <map> #include "base/logging.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url_model.h" #include "chrome/views/dialog_delegate.h" #include "chrome/views/native_button.h" #include "chrome/views/table_view.h" diff --git a/chrome/browser/views/keyword_editor_view_unittest.cc b/chrome/browser/views/keyword_editor_view_unittest.cc index 4d04a07..1bbb43c 100644 --- a/chrome/browser/views/keyword_editor_view_unittest.cc +++ b/chrome/browser/views/keyword_editor_view_unittest.cc @@ -3,8 +3,8 @@ // found in the LICENSE file. #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/views/keyword_editor_view.h" #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index 8c727b7..cad8583 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -13,9 +13,9 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/info_bubble.h" #include "chrome/browser/views/first_run_bubble.h" diff --git a/chrome/browser/views/options/general_page_view.cc b/chrome/browser/views/options/general_page_view.cc index a7964f6..d506fdc 100644 --- a/chrome/browser/views/options/general_page_view.cc +++ b/chrome/browser/views/options/general_page_view.cc @@ -15,10 +15,10 @@ #include "chrome/browser/dom_ui/new_tab_ui.h" #include "chrome/browser/history/history.h" #include "chrome/browser/profile.h" -#include "chrome/browser/session_startup_pref.h" -#include "chrome/browser/search_engines/template_url.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/shell_integration.h" +#include "chrome/browser/session_startup_pref.h" +#include "chrome/browser/template_url.h" +#include "chrome/browser/template_url_model.h" #include "chrome/browser/url_fixer_upper.h" #include "chrome/browser/views/keyword_editor_view.h" #include "chrome/browser/views/options/options_group_view.h" diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index 7791289..3232ec4 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -1470,17 +1470,8 @@ void TabStrip::StartResizeLayoutAnimation() { } void TabStrip::StartInsertTabAnimation(int index) { - // Don't shock users by letting all tabs move when they are focused - // on the tab-strip. Wait for later, when they aren't looking. - int last_tab_index = GetTabCount() - 2; - if (last_tab_index > 0) { - Tab* last_tab = GetTabAt(last_tab_index); - available_width_for_tabs_ = std::min( - GetAvailableWidthForTabs(last_tab) + last_tab->width(), - width() - (kNewTabButtonHOffset + newtab_button_size_.width())); - } else { - available_width_for_tabs_ = -1; - } + // The TabStrip can now use its entire width to lay out Tabs. + available_width_for_tabs_ = -1; if (active_animation_.get()) active_animation_->Stop(); active_animation_.reset(new InsertTabAnimation(this, index)); diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc index a3f8e55..d736ac4 100644 --- a/chrome/browser/webdata/web_data_service.cc +++ b/chrome/browser/webdata/web_data_service.cc @@ -10,7 +10,7 @@ #include "base/path_service.h" #include "base/scoped_ptr.h" #include "chrome/browser/password_manager/ie7_password.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/common/chrome_constants.h" #include "webkit/glue/password_form.h" #include "webkit/glue/autofill_form.h" diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc index af78244..5998282 100644 --- a/chrome/browser/webdata/web_database.cc +++ b/chrome/browser/webdata/web_database.cc @@ -15,7 +15,7 @@ #include "base/values.h" #include "chrome/browser/history/history_database.h" #include "chrome/browser/password_manager/encryptor.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/common/l10n_util.h" #include "chrome/common/scoped_vector.h" #include "webkit/glue/password_form.h" diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h index 54ec840..19059ee 100644 --- a/chrome/browser/webdata/web_database.h +++ b/chrome/browser/webdata/web_database.h @@ -10,7 +10,7 @@ #include "base/basictypes.h" #include "chrome/browser/meta_table_helper.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/common/sqlite_utils.h" #include "skia/include/SkBitmap.h" #include "webkit/glue/autofill_form.h" diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc index 8842e40..349b803 100644 --- a/chrome/browser/webdata/web_database_unittest.cc +++ b/chrome/browser/webdata/web_database_unittest.cc @@ -7,7 +7,7 @@ #include "base/string_util.h" #include "base/time.h" #include "base/values.h" -#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/template_url.h" #include "chrome/browser/webdata/web_database.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/stl_util-inl.h" diff --git a/chrome/chrome.xcodeproj/project.pbxproj b/chrome/chrome.xcodeproj/project.pbxproj index 364e272..4596bf2 100644 --- a/chrome/chrome.xcodeproj/project.pbxproj +++ b/chrome/chrome.xcodeproj/project.pbxproj @@ -287,6 +287,8 @@ E45075F70F150C0C003BE099 /* session_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = E45075F60F150C0C003BE099 /* session_id.cc */; }; E45075FA0F150C28003BE099 /* spellcheck_worditerator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9220E9D4839009A6919 /* spellcheck_worditerator.cc */; }; E45075FF0F150C84003BE099 /* ssl_error_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9280E9D4839009A6919 /* ssl_error_info.cc */; }; + E45076010F150C9D003BE099 /* template_url.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9420E9D4839009A6919 /* template_url.cc */; }; + E45076180F150DD2003BE099 /* template_url_model.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9460E9D4839009A6919 /* template_url_model.cc */; }; E450761A0F150DE9003BE099 /* url_fetcher.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9510E9D4839009A6919 /* url_fetcher.cc */; }; E45076200F150E0C003BE099 /* web_database.cc in Sources */ = {isa = PBXBuildFile; fileRef = E450761E0F150E0C003BE099 /* web_database.cc */; }; E45076850F1530CD003BE099 /* pref_service.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBEA0E9D4C9F009A6919 /* pref_service.cc */; }; @@ -319,6 +321,7 @@ E4F324600EE5D011002533CE /* url_database.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFA130E9D48F7009A6919 /* url_database.cc */; }; E4F324650EE5D082002533CE /* sdch_dictionary_fetcher.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFA720E9D4981009A6919 /* sdch_dictionary_fetcher.cc */; }; E4F3247A0EE5D17E002533CE /* referrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4F324790EE5D17E002533CE /* referrer.cc */; }; + E4F324860EE5D26F002533CE /* template_url_parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF9490E9D4839009A6919 /* template_url_parser.cc */; }; E4F324950EE5D758002533CE /* extension_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4F324420EE5CE94002533CE /* extension_unittest.cc */; }; E4F324980EE5D7DE002533CE /* snippet_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFA060E9D48F7009A6919 /* snippet_unittest.cc */; }; E4F3256E0EE82C83002533CE /* chrome_paths.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFB8F0E9D4C9F009A6919 /* chrome_paths.cc */; }; @@ -329,9 +332,6 @@ E4F3258C0EE83767002533CE /* libgoogleurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D7BFF6E0E9D540F009A6919 /* libgoogleurl.a */; }; E4F325C80EE83A45002533CE /* ipc_fuzzing_tests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBAD0E9D4C9F009A6919 /* ipc_fuzzing_tests.cc */; }; E4F325D10EE83B71002533CE /* ipc_tests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBBE0E9D4C9F009A6919 /* ipc_tests.cc */; }; - 9A1EE0F9187ACE2DCB8512E1 /* template_url.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3CCF8AA8A56FF8FE59F0C299 /* template_url.cc */; }; - C39F08C4FFD9C2F98384F56B /* template_url_model.cc in Sources */ = {isa = PBXBuildFile; fileRef = EA72C084DB3FC0FC595E525E /* template_url_model.cc */; }; - B9BF55F87A4BB2FD366B6DDC /* template_url_parser.cc in Sources */ = {isa = PBXBuildFile; fileRef = 28AA584AB2ECFB33C7C7FD8A /* template_url_parser.cc */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1189,12 +1189,17 @@ 4D7BF93F0E9D4839009A6919 /* task_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = task_manager.h; sourceTree = "<group>"; }; 4D7BF9400E9D4839009A6919 /* task_manager_resource_providers.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = task_manager_resource_providers.cc; sourceTree = "<group>"; }; 4D7BF9410E9D4839009A6919 /* task_manager_resource_providers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = task_manager_resource_providers.h; sourceTree = "<group>"; }; + 4D7BF9420E9D4839009A6919 /* template_url.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url.cc; sourceTree = "<group>"; }; 4D7BF9430E9D4839009A6919 /* template_url.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url.h; sourceTree = "<group>"; }; + 4D7BF9440E9D4839009A6919 /* template_url_fetcher.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_fetcher.cc; sourceTree = "<group>"; }; 4D7BF9450E9D4839009A6919 /* template_url_fetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_fetcher.h; sourceTree = "<group>"; }; + 4D7BF9460E9D4839009A6919 /* template_url_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_model.cc; sourceTree = "<group>"; }; 4D7BF9470E9D4839009A6919 /* template_url_model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_model.h; sourceTree = "<group>"; }; 4D7BF9480E9D4839009A6919 /* template_url_model_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_model_unittest.cc; sourceTree = "<group>"; }; + 4D7BF9490E9D4839009A6919 /* template_url_parser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_parser.cc; sourceTree = "<group>"; }; 4D7BF94A0E9D4839009A6919 /* template_url_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_parser.h; sourceTree = "<group>"; }; 4D7BF94B0E9D4839009A6919 /* template_url_parser_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_parser_unittest.cc; sourceTree = "<group>"; }; + 4D7BF94C0E9D4839009A6919 /* template_url_prepopulate_data.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_prepopulate_data.cc; sourceTree = "<group>"; }; 4D7BF94D0E9D4839009A6919 /* template_url_prepopulate_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = template_url_prepopulate_data.h; sourceTree = "<group>"; }; 4D7BF94E0E9D4839009A6919 /* template_url_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template_url_unittest.cc; sourceTree = "<group>"; }; 4D7BF94F0E9D4839009A6919 /* toolbar_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = toolbar_model.cc; sourceTree = "<group>"; }; @@ -1734,9 +1739,6 @@ E4F324420EE5CE94002533CE /* extension_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extension_unittest.cc; sourceTree = "<group>"; }; E4F324780EE5D17E002533CE /* referrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = referrer.h; sourceTree = "<group>"; }; E4F324790EE5D17E002533CE /* referrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = referrer.cc; sourceTree = "<group>"; }; - 3CCF8AA8A56FF8FE59F0C299 /* template_url.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = template_url.cc; path = browser/search_engines/template_url.cc; sourceTree = SOURCE_ROOT; }; - EA72C084DB3FC0FC595E525E /* template_url_model.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = template_url_model.cc; path = browser/search_engines/template_url_model.cc; sourceTree = SOURCE_ROOT; }; - 28AA584AB2ECFB33C7C7FD8A /* template_url_parser.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = template_url_parser.cc; path = browser/search_engines/template_url_parser.cc; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1944,9 +1946,6 @@ 4D7BFDD00E9D527E009A6919 /* Frameworks */, 4D7BFB090E9D4BA1009A6919 /* Projects */, 4D7BF3070E9D477E009A6919 /* Products */, - 3CCF8AA8A56FF8FE59F0C299 /* template_url.cc */, - EA72C084DB3FC0FC595E525E /* template_url_model.cc */, - 28AA584AB2ECFB33C7C7FD8A /* template_url_parser.cc */, ); sourceTree = "<group>"; }; @@ -2220,12 +2219,17 @@ 4D7BF93F0E9D4839009A6919 /* task_manager.h */, 4D7BF9400E9D4839009A6919 /* task_manager_resource_providers.cc */, 4D7BF9410E9D4839009A6919 /* task_manager_resource_providers.h */, + 4D7BF9420E9D4839009A6919 /* template_url.cc */, 4D7BF9430E9D4839009A6919 /* template_url.h */, + 4D7BF9440E9D4839009A6919 /* template_url_fetcher.cc */, 4D7BF9450E9D4839009A6919 /* template_url_fetcher.h */, + 4D7BF9460E9D4839009A6919 /* template_url_model.cc */, 4D7BF9470E9D4839009A6919 /* template_url_model.h */, 4D7BF9480E9D4839009A6919 /* template_url_model_unittest.cc */, + 4D7BF9490E9D4839009A6919 /* template_url_parser.cc */, 4D7BF94A0E9D4839009A6919 /* template_url_parser.h */, 4D7BF94B0E9D4839009A6919 /* template_url_parser_unittest.cc */, + 4D7BF94C0E9D4839009A6919 /* template_url_prepopulate_data.cc */, 4D7BF94D0E9D4839009A6919 /* template_url_prepopulate_data.h */, 4D640D1A0EAE87BD00EBCFC0 /* template_url_prepopulate_data_unittest.cc */, 4D7BF94E0E9D4839009A6919 /* template_url_unittest.cc */, @@ -3730,9 +3734,9 @@ E45075FF0F150C84003BE099 /* ssl_error_info.cc in Sources */, E4F3245D0EE5CFDF002533CE /* starred_url_database.cc in Sources */, E45075EE0F150ABA003BE099 /* sync_resource_handler.cc in Sources */, - 9A1EE0F9187ACE2DCB8512E1 /* template_url.cc in Sources */, - C39F08C4FFD9C2F98384F56B /* template_url_model.cc in Sources */, - B9BF55F87A4BB2FD366B6DDC /* template_url_parser.cc in Sources */, + E45076010F150C9D003BE099 /* template_url.cc in Sources */, + E45076180F150DD2003BE099 /* template_url_model.cc in Sources */, + E4F324860EE5D26F002533CE /* template_url_parser.cc in Sources */, 4D7BFA320E9D4912009A6919 /* text_database.cc in Sources */, 4D7BFA370E9D4915009A6919 /* text_database_manager.cc in Sources */, 4D7BFA390E9D4918009A6919 /* thumbnail_database.cc in Sources */, diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 2d622a7..37e6c17 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -12,8 +12,8 @@ #include "chrome/browser/browser_prefs.h" #include "chrome/browser/history/history.h" #include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/template_url_model.h" #include "chrome/common/pref_service.h" class TestingProfile : public Profile { diff --git a/chrome/test/unit/unit_tests.scons b/chrome/test/unit/unit_tests.scons index 9a06328..7d0c68a 100644 --- a/chrome/test/unit/unit_tests.scons +++ b/chrome/test/unit/unit_tests.scons @@ -213,10 +213,10 @@ if env.Bit('windows'): '$CHROME_DIR/browser/sessions/tab_restore_service_unittest.cc', '$CHROME_DIR/browser/site_instance_unittest.cc', '$CHROME_DIR/browser/tabs/tab_strip_model_unittest.cc', - '$CHROME_DIR/browser/search_engines/template_url_model_unittest.cc', - '$CHROME_DIR/browser/search_engines/template_url_parser_unittest.cc', - '$CHROME_DIR/browser/search_engines/template_url_prepopulate_data_unittest.cc', - '$CHROME_DIR/browser/search_engines/template_url_unittest.cc', + '$CHROME_DIR/browser/template_url_model_unittest.cc', + '$CHROME_DIR/browser/template_url_parser_unittest.cc', + '$CHROME_DIR/browser/template_url_prepopulate_data_unittest.cc', + '$CHROME_DIR/browser/template_url_unittest.cc', '$CHROME_DIR/browser/url_fixer_upper_unittest.cc', '$CHROME_DIR/browser/views/bookmark_editor_view_unittest.cc', '$CHROME_DIR/browser/views/keyword_editor_view_unittest.cc', diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj index 6b1a977..f00154e 100644 --- a/chrome/test/unit/unittests.vcproj +++ b/chrome/test/unit/unittests.vcproj @@ -687,19 +687,19 @@ > </File> <File - RelativePath="..\..\browser\search_engines\template_url_model_unittest.cc" + RelativePath="..\..\browser\template_url_model_unittest.cc" > </File> <File - RelativePath="..\..\browser\search_engines\template_url_parser_unittest.cc" + RelativePath="..\..\browser\template_url_parser_unittest.cc" > </File> <File - RelativePath="..\..\browser\search_engines\template_url_prepopulate_data_unittest.cc" + RelativePath="..\..\browser\template_url_prepopulate_data_unittest.cc" > </File> <File - RelativePath="..\..\browser\search_engines\template_url_unittest.cc" + RelativePath="..\..\browser\template_url_unittest.cc" > </File> <File |