• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 "chrome/browser/translate/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 "chrome/browser/translate/translate_url_fetcher.h"
15 #include "chrome/browser/translate/translate_url_util.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "components/translate/common/translate_util.h"
18 #include "google_apis/google_api_keys.h"
19 #include "grit/browser_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 {
25 
26 const int kExpirationDelayDays = 1;
27 
28 }  // namespace
29 
30 const char TranslateScript::kScriptURL[] =
31     "https://translate.google.com/translate_a/element.js";
32 const char TranslateScript::kRequestHeader[] =
33     "Google-Translate-Element-Mode: library";
34 const char TranslateScript::kAlwaysUseSslQueryName[] = "aus";
35 const char TranslateScript::kAlwaysUseSslQueryValue[] = "true";
36 const char TranslateScript::kCallbackQueryName[] = "cb";
37 const char TranslateScript::kCallbackQueryValue[] =
38     "cr.googleTranslate.onTranslateElementLoad";
39 const char TranslateScript::kCssLoaderCallbackQueryName[] = "clc";
40 const char TranslateScript::kCssLoaderCallbackQueryValue[] =
41     "cr.googleTranslate.onLoadCSS";
42 const char TranslateScript::kJavascriptLoaderCallbackQueryName[] = "jlc";
43 const char TranslateScript::kJavascriptLoaderCallbackQueryValue[] =
44     "cr.googleTranslate.onLoadJavascript";
45 
TranslateScript()46 TranslateScript::TranslateScript()
47     : expiration_delay_(base::TimeDelta::FromDays(kExpirationDelayDays)),
48       weak_method_factory_(this) {
49 }
50 
~TranslateScript()51 TranslateScript::~TranslateScript() {
52 }
53 
Request(const Callback & callback)54 void TranslateScript::Request(const Callback& callback) {
55   if (fetcher_.get() != NULL) {
56     NOTREACHED();
57     return;
58   }
59 
60   callback_ = callback;
61 
62   GURL translate_script_url;
63   // Check if command-line contains an alternative URL for translate service.
64   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
65   if (command_line.HasSwitch(switches::kTranslateScriptURL)) {
66     translate_script_url = GURL(
67         command_line.GetSwitchValueASCII(switches::kTranslateScriptURL));
68     if (!translate_script_url.is_valid() ||
69         !translate_script_url.query().empty()) {
70       LOG(WARNING) << "The following translate URL specified at the "
71                    << "command-line is invalid: "
72                    << translate_script_url.spec();
73       translate_script_url = GURL();
74     }
75   }
76 
77   // Use default URL when command-line argument is not specified, or specified
78   // URL is invalid.
79   if (translate_script_url.is_empty())
80     translate_script_url = GURL(kScriptURL);
81 
82   translate_script_url = net::AppendQueryParameter(
83       translate_script_url,
84       kCallbackQueryName,
85       kCallbackQueryValue);
86   translate_script_url = net::AppendQueryParameter(
87       translate_script_url,
88       kAlwaysUseSslQueryName,
89       kAlwaysUseSslQueryValue);
90 #if !defined(OS_IOS)
91   // iOS doesn't need to use specific loaders for the isolated world.
92   translate_script_url = net::AppendQueryParameter(
93       translate_script_url,
94       kCssLoaderCallbackQueryName,
95       kCssLoaderCallbackQueryValue);
96   translate_script_url = net::AppendQueryParameter(
97       translate_script_url,
98       kJavascriptLoaderCallbackQueryName,
99       kJavascriptLoaderCallbackQueryValue);
100 #endif  // !defined(OS_IOS)
101 
102   translate_script_url =
103       TranslateURLUtil::AddHostLocaleToUrl(translate_script_url);
104   translate_script_url =
105       TranslateURLUtil::AddApiKeyToUrl(translate_script_url);
106 
107   fetcher_.reset(new TranslateURLFetcher(kFetcherId));
108   fetcher_->set_extra_request_header(kRequestHeader);
109   fetcher_->Request(
110       translate_script_url,
111       base::Bind(&TranslateScript::OnScriptFetchComplete,
112                  base::Unretained(this)));
113 }
114 
115 
OnScriptFetchComplete(int id,bool success,const std::string & data)116 void TranslateScript::OnScriptFetchComplete(
117     int id, bool success, const std::string& data) {
118   DCHECK_EQ(kFetcherId, id);
119 
120   scoped_ptr<const TranslateURLFetcher> delete_ptr(fetcher_.release());
121 
122   if (success) {
123     DCHECK(data_.empty());
124     // Insert variable definitions on API Key and security origin.
125     data_ = base::StringPrintf("var translateApiKey = '%s';\n",
126                                google_apis::GetAPIKey().c_str());
127 
128     GURL security_origin = translate::GetTranslateSecurityOrigin();
129     base::StringAppendF(
130         &data_, "var securityOrigin = '%s';", security_origin.spec().c_str());
131 
132     // Append embedded translate.js and a remote element library.
133     base::StringPiece str = ResourceBundle::GetSharedInstance().
134         GetRawDataResource(IDR_TRANSLATE_JS);
135     str.AppendToString(&data_);
136     data_ += data;
137 
138     // We'll expire the cached script after some time, to make sure long
139     // running browsers still get fixes that might get pushed with newer
140     // scripts.
141     base::MessageLoop::current()->PostDelayedTask(
142         FROM_HERE,
143         base::Bind(&TranslateScript::Clear,
144                    weak_method_factory_.GetWeakPtr()),
145         expiration_delay_);
146   }
147 
148   callback_.Run(success, data);
149 }
150