1 // Copyright (c) 2012 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/browser/extensions/api/streams_private/streams_private_api.h"
7 #include "base/lazy_instance.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/extension_tab_util.h"
10 #include "chrome/common/extensions/api/streams_private.h"
11 #include "content/public/browser/stream_handle.h"
12 #include "content/public/browser/stream_info.h"
13 #include "extensions/browser/event_router.h"
14 #include "extensions/browser/extension_function_registry.h"
15 #include "extensions/browser/extension_registry.h"
16 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
17 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
18 #include "extensions/common/manifest_handlers/mime_types_handler.h"
19 #include "net/http/http_response_headers.h"
21 namespace extensions
{
24 void CreateResponseHeadersDictionary(const net::HttpResponseHeaders
* headers
,
25 base::DictionaryValue
* result
) {
30 std::string header_name
;
31 std::string header_value
;
32 while (headers
->EnumerateHeaderLines(&iter
, &header_name
, &header_value
)) {
33 base::Value
* existing_value
= NULL
;
34 if (result
->Get(header_name
, &existing_value
)) {
35 base::StringValue
* existing_string_value
=
36 static_cast<base::StringValue
*>(existing_value
);
37 existing_string_value
->GetString()->append(", ").append(header_value
);
39 result
->SetString(header_name
, header_value
);
46 namespace streams_private
= api::streams_private
;
49 StreamsPrivateAPI
* StreamsPrivateAPI::Get(content::BrowserContext
* context
) {
50 return GetFactoryInstance()->Get(context
);
53 StreamsPrivateAPI::StreamsPrivateAPI(content::BrowserContext
* context
)
54 : browser_context_(context
),
55 extension_registry_observer_(this),
56 weak_ptr_factory_(this) {
57 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
60 StreamsPrivateAPI::~StreamsPrivateAPI() {
63 void StreamsPrivateAPI::ExecuteMimeTypeHandler(
64 const std::string
& extension_id
,
65 content::WebContents
* web_contents
,
66 scoped_ptr
<content::StreamInfo
> stream
,
67 const std::string
& view_id
,
68 int64 expected_content_size
,
70 int render_process_id
,
71 int render_frame_id
) {
72 const Extension
* extension
= ExtensionRegistry::Get(browser_context_
)
73 ->enabled_extensions()
74 .GetByID(extension_id
);
78 MimeTypesHandler
* handler
= MimeTypesHandler::GetHandler(extension
);
79 // If the mime handler uses MimeHandlerViewGuest, the MimeHandlerViewGuest
80 // will take ownership of the stream. Otherwise, store the stream handle in
81 // |streams_| and fire an event notifying the extension.
82 if (handler
->HasPlugin()) {
83 GURL
handler_url(Extension::GetBaseURLFromExtensionId(extension_id
).spec() +
84 handler
->handler_url());
85 auto tab_id
= ExtensionTabUtil::GetTabId(web_contents
);
86 scoped_ptr
<StreamContainer
> stream_container(new StreamContainer(
87 stream
.Pass(), tab_id
, embedded
, handler_url
, extension_id
));
88 MimeHandlerStreamManager::Get(browser_context_
)
89 ->AddStream(view_id
, stream_container
.Pass(), render_process_id
,
93 // Create the event's arguments value.
94 streams_private::StreamInfo info
;
95 info
.mime_type
= stream
->mime_type
;
96 info
.original_url
= stream
->original_url
.spec();
97 info
.stream_url
= stream
->handle
->GetURL().spec();
98 info
.tab_id
= ExtensionTabUtil::GetTabId(web_contents
);
99 info
.embedded
= embedded
;
101 if (!view_id
.empty()) {
102 info
.view_id
.reset(new std::string(view_id
));
106 if (expected_content_size
<= INT_MAX
)
107 size
= expected_content_size
;
108 info
.expected_content_size
= size
;
110 CreateResponseHeadersDictionary(stream
->response_headers
.get(),
111 &info
.response_headers
.additional_properties
);
113 scoped_ptr
<Event
> event(
114 new Event(events::STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER
,
115 streams_private::OnExecuteMimeTypeHandler::kEventName
,
116 streams_private::OnExecuteMimeTypeHandler::Create(info
)));
118 EventRouter::Get(browser_context_
)
119 ->DispatchEventToExtension(extension_id
, event
.Pass());
121 GURL url
= stream
->handle
->GetURL();
122 streams_
[extension_id
][url
] = make_linked_ptr(stream
->handle
.release());
125 void StreamsPrivateAPI::AbortStream(const std::string
& extension_id
,
126 const GURL
& stream_url
,
127 const base::Closure
& callback
) {
128 StreamMap::iterator extension_it
= streams_
.find(extension_id
);
129 if (extension_it
== streams_
.end()) {
134 StreamMap::mapped_type
* url_map
= &extension_it
->second
;
135 StreamMap::mapped_type::iterator url_it
= url_map
->find(stream_url
);
136 if (url_it
== url_map
->end()) {
141 url_it
->second
->AddCloseListener(callback
);
142 url_map
->erase(url_it
);
145 void StreamsPrivateAPI::OnExtensionUnloaded(
146 content::BrowserContext
* browser_context
,
147 const Extension
* extension
,
148 UnloadedExtensionInfo::Reason reason
) {
149 streams_
.erase(extension
->id());
152 StreamsPrivateAbortFunction::StreamsPrivateAbortFunction() {
155 ExtensionFunction::ResponseAction
StreamsPrivateAbortFunction::Run() {
156 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
157 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &stream_url_
));
158 StreamsPrivateAPI::Get(browser_context())->AbortStream(
159 extension_id(), GURL(stream_url_
), base::Bind(
160 &StreamsPrivateAbortFunction::OnClose
, this));
161 return RespondLater();
164 void StreamsPrivateAbortFunction::OnClose() {
165 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
166 Respond(NoArguments());
169 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<StreamsPrivateAPI
> >
170 g_factory
= LAZY_INSTANCE_INITIALIZER
;
173 BrowserContextKeyedAPIFactory
<StreamsPrivateAPI
>*
174 StreamsPrivateAPI::GetFactoryInstance() {
175 return g_factory
.Pointer();
178 } // namespace extensions