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_util.h" 12 #include "chrome/browser/translate/translate_url_fetcher.h" 13 #include "chrome/browser/translate/translate_url_util.h" 14 #include "chrome/common/chrome_switches.h" 15 #include "google_apis/google_api_keys.h" 16 #include "grit/browser_resources.h" 17 #include "net/base/escape.h" 18 #include "net/base/url_util.h" 19 #include "ui/base/resource/resource_bundle.h" 20 21 namespace { 22 23 const int kExpirationDelayDays = 1; 24 25 const char kScriptURL[] = 26 "https://translate.google.com/translate_a/element.js"; 27 const char kRequestHeader[] = "Google-Translate-Element-Mode: library"; 28 29 // Used in kTranslateScriptURL to specify a callback function name. 30 const char kCallbackQueryName[] = "cb"; 31 const char kCallbackQueryValue[] = 32 "cr.googleTranslate.onTranslateElementLoad"; 33 34 } // namespace 35 36 TranslateScript::TranslateScript() 37 : weak_method_factory_(this), 38 expiration_delay_(base::TimeDelta::FromDays(kExpirationDelayDays)) { 39 } 40 41 TranslateScript::~TranslateScript() { 42 weak_method_factory_.InvalidateWeakPtrs(); 43 } 44 45 void TranslateScript::Request(const Callback& callback) { 46 if (fetcher_.get() != NULL) { 47 NOTREACHED(); 48 return; 49 } 50 51 callback_ = callback; 52 53 GURL translate_script_url; 54 // Check if command-line contains an alternative URL for translate service. 55 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 56 if (command_line.HasSwitch(switches::kTranslateScriptURL)) { 57 translate_script_url = GURL( 58 command_line.GetSwitchValueASCII(switches::kTranslateScriptURL)); 59 if (!translate_script_url.is_valid() || 60 !translate_script_url.query().empty()) { 61 LOG(WARNING) << "The following translate URL specified at the " 62 << "command-line is invalid: " 63 << translate_script_url.spec(); 64 translate_script_url = GURL(); 65 } 66 } 67 68 // Use default URL when command-line argument is not specified, or specified 69 // URL is invalid. 70 if (translate_script_url.is_empty()) 71 translate_script_url = GURL(kScriptURL); 72 73 translate_script_url = net::AppendQueryParameter( 74 translate_script_url, 75 kCallbackQueryName, 76 kCallbackQueryValue); 77 78 translate_script_url = 79 TranslateURLUtil::AddHostLocaleToUrl(translate_script_url); 80 translate_script_url = 81 TranslateURLUtil::AddApiKeyToUrl(translate_script_url); 82 83 fetcher_.reset(new TranslateURLFetcher(kFetcherId)); 84 fetcher_->set_extra_request_header(kRequestHeader); 85 fetcher_->Request( 86 translate_script_url, 87 base::Bind(&TranslateScript::OnScriptFetchComplete, 88 base::Unretained(this))); 89 } 90 91 92 void TranslateScript::OnScriptFetchComplete( 93 int id, bool success, const std::string& data) { 94 DCHECK_EQ(kFetcherId, id); 95 96 scoped_ptr<const TranslateURLFetcher> delete_ptr(fetcher_.release()); 97 98 if (success) { 99 base::StringPiece str = ResourceBundle::GetSharedInstance(). 100 GetRawDataResource(IDR_TRANSLATE_JS); 101 DCHECK(data_.empty()); 102 str.CopyToString(&data_); 103 std::string argument = "('"; 104 std::string api_key = google_apis::GetAPIKey(); 105 argument += net::EscapeQueryParamValue(api_key, true); 106 argument += "');\n"; 107 data_ += argument + data; 108 109 // We'll expire the cached script after some time, to make sure long 110 // running browsers still get fixes that might get pushed with newer 111 // scripts. 112 base::MessageLoop::current()->PostDelayedTask( 113 FROM_HERE, 114 base::Bind(&TranslateScript::Clear, 115 weak_method_factory_.GetWeakPtr()), 116 expiration_delay_); 117 } 118 119 callback_.Run(success, data); 120 } 121