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.
5 #include "chrome/renderer/extensions/extension_localization_peer.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_util.h"
9 #include "chrome/common/url_constants.h"
10 #include "extensions/common/constants.h"
11 #include "extensions/common/extension_messages.h"
12 #include "extensions/common/message_bundle.h"
13 #include "ipc/ipc_sender.h"
14 #include "net/base/net_errors.h"
15 #include "net/http/http_response_headers.h"
19 class StringData final
: public content::RequestPeer::ReceivedData
{
21 explicit StringData(const std::string
& data
) : data_(data
) {}
22 void Append(const char* data
, int length
) { data_
.append(data
, length
); }
24 const char* payload() const override
{ return data_
.data(); }
25 int length() const override
{ return data_
.size(); }
26 int encoded_length() const override
{ return -1; }
31 DISALLOW_COPY_AND_ASSIGN(StringData
);
36 ExtensionLocalizationPeer::ExtensionLocalizationPeer(
37 content::RequestPeer
* peer
,
38 IPC::Sender
* message_sender
,
39 const GURL
& request_url
)
40 : original_peer_(peer
),
41 message_sender_(message_sender
),
42 request_url_(request_url
) {
45 ExtensionLocalizationPeer::~ExtensionLocalizationPeer() {
49 ExtensionLocalizationPeer
*
50 ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
51 content::RequestPeer
* peer
,
52 IPC::Sender
* message_sender
,
53 const std::string
& mime_type
,
54 const GURL
& request_url
) {
55 // Return NULL if content is not text/css or it doesn't belong to extension
57 return (request_url
.SchemeIs(extensions::kExtensionScheme
) &&
58 base::StartsWith(mime_type
, "text/css",
59 base::CompareCase::INSENSITIVE_ASCII
))
60 ? new ExtensionLocalizationPeer(peer
, message_sender
, request_url
)
64 void ExtensionLocalizationPeer::OnUploadProgress(
65 uint64 position
, uint64 size
) {
69 bool ExtensionLocalizationPeer::OnReceivedRedirect(
70 const net::RedirectInfo
& redirect_info
,
71 const content::ResourceResponseInfo
& info
) {
76 void ExtensionLocalizationPeer::OnReceivedResponse(
77 const content::ResourceResponseInfo
& info
) {
78 response_info_
= info
;
81 void ExtensionLocalizationPeer::OnReceivedData(scoped_ptr
<ReceivedData
> data
) {
82 data_
.append(data
->payload(), data
->length());
85 void ExtensionLocalizationPeer::OnCompletedRequest(
87 bool was_ignored_by_handler
,
88 bool stale_copy_in_cache
,
89 const std::string
& security_info
,
90 const base::TimeTicks
& completion_time
,
91 int64 total_transfer_size
) {
92 // Make sure we delete ourselves at the end of this call.
93 scoped_ptr
<ExtensionLocalizationPeer
> this_deleter(this);
94 // Give sub-classes a chance at altering the data.
95 if (error_code
!= net::OK
) {
96 // We failed to load the resource.
97 original_peer_
->OnReceivedCompletedResponse(
98 response_info_
, nullptr, net::ERR_ABORTED
, false, stale_copy_in_cache
,
99 security_info
, completion_time
, total_transfer_size
);
105 scoped_ptr
<StringData
> data_to_pass(data_
.empty() ? nullptr
106 : new StringData(data_
));
107 original_peer_
->OnReceivedCompletedResponse(
108 response_info_
, data_to_pass
.Pass(), error_code
, was_ignored_by_handler
,
109 stale_copy_in_cache
, security_info
, completion_time
, total_transfer_size
);
112 void ExtensionLocalizationPeer::OnReceivedCompletedResponse(
113 const content::ResourceResponseInfo
& info
,
114 scoped_ptr
<ReceivedData
> data
,
116 bool was_ignored_by_handler
,
117 bool stale_copy_in_cache
,
118 const std::string
& security_info
,
119 const base::TimeTicks
& completion_time
,
120 int64 total_transfer_size
) {
121 // Make sure we delete ourselves at the end of this call.
122 scoped_ptr
<ExtensionLocalizationPeer
> this_deleter(this);
123 original_peer_
->OnReceivedCompletedResponse(
124 info
, data
.Pass(), error_code
, was_ignored_by_handler
,
125 stale_copy_in_cache
, security_info
, completion_time
, total_transfer_size
);
128 void ExtensionLocalizationPeer::ReplaceMessages() {
129 if (!message_sender_
|| data_
.empty())
132 if (!request_url_
.is_valid())
135 std::string extension_id
= request_url_
.host();
136 extensions::L10nMessagesMap
* l10n_messages
=
137 extensions::GetL10nMessagesMap(extension_id
);
138 if (!l10n_messages
) {
139 extensions::L10nMessagesMap messages
;
140 message_sender_
->Send(new ExtensionHostMsg_GetMessageBundle(
141 extension_id
, &messages
));
143 // Save messages we got, so we don't have to ask again.
144 // Messages map is never empty, it contains at least @@extension_id value.
145 extensions::ExtensionToL10nMessagesMap
& l10n_messages_map
=
146 *extensions::GetExtensionToL10nMessagesMap();
147 l10n_messages_map
[extension_id
] = messages
;
149 l10n_messages
= extensions::GetL10nMessagesMap(extension_id
);
153 if (extensions::MessageBundle::ReplaceMessagesWithExternalDictionary(
154 *l10n_messages
, &data_
, &error
)) {
155 data_
.resize(data_
.size());