• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/translate/core/browser/translate_script.h"
6 
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "components/translate/core/browser/translate_url_fetcher.h"
15 #include "components/translate/core/browser/translate_url_util.h"
16 #include "components/translate/core/common/translate_switches.h"
17 #include "components/translate/core/common/translate_util.h"
18 #include "google_apis/google_api_keys.h"
19 #include "grit/components_resources.h"
20 #include "net/base/escape.h"
21 #include "net/base/url_util.h"
22 #include "ui/base/resource/resource_bundle.h"
23 
24 namespace translate {
25 
26 namespace {
27 
28 const int kExpirationDelayDays = 1;
29 
30 }  // namespace
31 
32 const char TranslateScript::kScriptURL[] =
33     "https://translate.google.com/translate_a/element.js";
34 const char TranslateScript::kRequestHeader[] =
35     "Google-Translate-Element-Mode: library";
36 const char TranslateScript::kAlwaysUseSslQueryName[] = "aus";
37 const char TranslateScript::kAlwaysUseSslQueryValue[] = "true";
38 const char TranslateScript::kCallbackQueryName[] = "cb";
39 const char TranslateScript::kCallbackQueryValue[] =
40     "cr.googleTranslate.onTranslateElementLoad";
41 const char TranslateScript::kCssLoaderCallbackQueryName[] = "clc";
42 const char TranslateScript::kCssLoaderCallbackQueryValue[] =
43     "cr.googleTranslate.onLoadCSS";
44 const char TranslateScript::kJavascriptLoaderCallbackQueryName[] = "jlc";
45 const char TranslateScript::kJavascriptLoaderCallbackQueryValue[] =
46     "cr.googleTranslate.onLoadJavascript";
47 
TranslateScript()48 TranslateScript::TranslateScript()
49     : expiration_delay_(base::TimeDelta::FromDays(kExpirationDelayDays)),
50       weak_method_factory_(this) {
51 }
52 
~TranslateScript()53 TranslateScript::~TranslateScript() {
54 }
55 
Request(const RequestCallback & callback)56 void TranslateScript::Request(const RequestCallback& callback) {
57   DCHECK(data_.empty()) << "Do not fetch the script if it is already fetched";
58   callback_list_.push_back(callback);
59 
60   if (fetcher_.get() != NULL) {
61     // If there is already a request in progress, do nothing. |callback| will be
62     // run on completion.
63     return;
64   }
65 
66   GURL translate_script_url;
67   // Check if command-line contains an alternative URL for translate service.
68   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
69   if (command_line.HasSwitch(translate::switches::kTranslateScriptURL)) {
70     translate_script_url = GURL(command_line.GetSwitchValueASCII(
71         translate::switches::kTranslateScriptURL));
72     if (!translate_script_url.is_valid() ||
73         !translate_script_url.query().empty()) {
74       LOG(WARNING) << "The following translate URL specified at the "
75                    << "command-line is invalid: "
76                    << translate_script_url.spec();
77       translate_script_url = GURL();
78     }
79   }
80 
81   // Use default URL when command-line argument is not specified, or specified
82   // URL is invalid.
83   if (translate_script_url.is_empty())
84     translate_script_url = GURL(kScriptURL);
85 
86   translate_script_url = net::AppendQueryParameter(
87       translate_script_url,
88       kCallbackQueryName,
89       kCallbackQueryValue);
90   translate_script_url = net::AppendQueryParameter(
91       translate_script_url,
92       kAlwaysUseSslQueryName,
93       kAlwaysUseSslQueryValue);
94 #if !defined(OS_IOS)
95   // iOS doesn't need to use specific loaders for the isolated world.
96   translate_script_url = net::AppendQueryParameter(
97       translate_script_url,
98       kCssLoaderCallbackQueryName,
99       kCssLoaderCallbackQueryValue);
100   translate_script_url = net::AppendQueryParameter(
101       translate_script_url,
102       kJavascriptLoaderCallbackQueryName,
103       kJavascriptLoaderCallbackQueryValue);
104 #endif  // !defined(OS_IOS)
105 
106   translate_script_url = AddHostLocaleToUrl(translate_script_url);
107   translate_script_url = AddApiKeyToUrl(translate_script_url);
108 
109   fetcher_.reset(new TranslateURLFetcher(kFetcherId));
110   fetcher_->set_extra_request_header(kRequestHeader);
111   fetcher_->Request(
112       translate_script_url,
113       base::Bind(&TranslateScript::OnScriptFetchComplete,
114                  base::Unretained(this)));
115 }
116 
117 
OnScriptFetchComplete(int id,bool success,const std::string & data)118 void TranslateScript::OnScriptFetchComplete(
119     int id, bool success, const std::string& data) {
120   DCHECK_EQ(kFetcherId, id);
121 
122   scoped_ptr<const TranslateURLFetcher> delete_ptr(fetcher_.release());
123 
124   if (success) {
125     DCHECK(data_.empty());
126     // Insert variable definitions on API Key and security origin.
127     data_ = base::StringPrintf("var translateApiKey = '%s';\n",
128                                google_apis::GetAPIKey().c_str());
129 
130     GURL security_origin = translate::GetTranslateSecurityOrigin();
131     base::StringAppendF(
132         &data_, "var securityOrigin = '%s';", security_origin.spec().c_str());
133 
134     // Append embedded translate.js and a remote element library.
135     base::StringPiece str = ResourceBundle::GetSharedInstance().
136         GetRawDataResource(IDR_TRANSLATE_JS);
137     str.AppendToString(&data_);
138     data_ += data;
139 
140     // We'll expire the cached script after some time, to make sure long
141     // running browsers still get fixes that might get pushed with newer
142     // scripts.
143     base::MessageLoop::current()->PostDelayedTask(
144         FROM_HERE,
145         base::Bind(&TranslateScript::Clear,
146                    weak_method_factory_.GetWeakPtr()),
147         expiration_delay_);
148   }
149 
150   for (RequestCallbackList::iterator it = callback_list_.begin();
151        it != callback_list_.end();
152        ++it) {
153     it->Run(success, data);
154   }
155   callback_list_.clear();
156 }
157 
158 }  // namespace translate
159