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. 4 5 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h" 6 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 "extensions/browser/event_router.h" 13 #include "extensions/browser/extension_function_registry.h" 14 #include "extensions/browser/extension_registry.h" 15 #include "net/http/http_response_headers.h" 16 17 namespace { 18 19 void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers, 20 base::DictionaryValue* result) { 21 if (!headers) 22 return; 23 24 void* iter = NULL; 25 std::string header_name; 26 std::string header_value; 27 while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { 28 base::Value* existing_value = NULL; 29 if (result->Get(header_name, &existing_value)) { 30 base::StringValue* existing_string_value = 31 static_cast<base::StringValue*>(existing_value); 32 existing_string_value->GetString()->append(", ").append(header_value); 33 } else { 34 result->SetString(header_name, header_value); 35 } 36 } 37 } 38 39 } // namespace 40 41 namespace extensions { 42 43 namespace streams_private = api::streams_private; 44 45 // static 46 StreamsPrivateAPI* StreamsPrivateAPI::Get(content::BrowserContext* context) { 47 return GetFactoryInstance()->Get(context); 48 } 49 50 StreamsPrivateAPI::StreamsPrivateAPI(content::BrowserContext* context) 51 : browser_context_(context), 52 weak_ptr_factory_(this), 53 extension_registry_observer_(this) { 54 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 55 } 56 57 StreamsPrivateAPI::~StreamsPrivateAPI() { 58 } 59 60 void StreamsPrivateAPI::ExecuteMimeTypeHandler( 61 const std::string& extension_id, 62 content::WebContents* web_contents, 63 scoped_ptr<content::StreamHandle> stream, 64 const std::string& view_id, 65 int64 expected_content_size) { 66 // Create the event's arguments value. 67 streams_private::StreamInfo info; 68 info.mime_type = stream->GetMimeType(); 69 info.original_url = stream->GetOriginalURL().spec(); 70 info.stream_url = stream->GetURL().spec(); 71 info.tab_id = ExtensionTabUtil::GetTabId(web_contents); 72 73 if (!view_id.empty()) { 74 info.view_id.reset(new std::string(view_id)); 75 } 76 77 int size = -1; 78 if (expected_content_size <= INT_MAX) 79 size = expected_content_size; 80 info.expected_content_size = size; 81 82 CreateResponseHeadersDictionary(stream->GetResponseHeaders().get(), 83 &info.response_headers.additional_properties); 84 85 scoped_ptr<Event> event( 86 new Event(streams_private::OnExecuteMimeTypeHandler::kEventName, 87 streams_private::OnExecuteMimeTypeHandler::Create(info))); 88 89 EventRouter::Get(browser_context_) 90 ->DispatchEventToExtension(extension_id, event.Pass()); 91 92 GURL url = stream->GetURL(); 93 streams_[extension_id][url] = make_linked_ptr(stream.release()); 94 } 95 96 void StreamsPrivateAPI::AbortStream(const std::string& extension_id, 97 const GURL& stream_url, 98 const base::Closure& callback) { 99 StreamMap::iterator extension_it = streams_.find(extension_id); 100 if (extension_it == streams_.end()) { 101 callback.Run(); 102 return; 103 } 104 105 StreamMap::mapped_type* url_map = &extension_it->second; 106 StreamMap::mapped_type::iterator url_it = url_map->find(stream_url); 107 if (url_it == url_map->end()) { 108 callback.Run(); 109 return; 110 } 111 112 url_it->second->AddCloseListener(callback); 113 url_map->erase(url_it); 114 } 115 116 void StreamsPrivateAPI::OnExtensionUnloaded( 117 content::BrowserContext* browser_context, 118 const Extension* extension, 119 UnloadedExtensionInfo::Reason reason) { 120 streams_.erase(extension->id()); 121 } 122 123 StreamsPrivateAbortFunction::StreamsPrivateAbortFunction() { 124 } 125 126 ExtensionFunction::ResponseAction StreamsPrivateAbortFunction::Run() { 127 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 128 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &stream_url_)); 129 StreamsPrivateAPI::Get(browser_context())->AbortStream( 130 extension_id(), GURL(stream_url_), base::Bind( 131 &StreamsPrivateAbortFunction::OnClose, this)); 132 return RespondLater(); 133 } 134 135 void StreamsPrivateAbortFunction::OnClose() { 136 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 137 Respond(NoArguments()); 138 } 139 140 static base::LazyInstance<BrowserContextKeyedAPIFactory<StreamsPrivateAPI> > 141 g_factory = LAZY_INSTANCE_INITIALIZER; 142 143 // static 144 BrowserContextKeyedAPIFactory<StreamsPrivateAPI>* 145 StreamsPrivateAPI::GetFactoryInstance() { 146 return g_factory.Pointer(); 147 } 148 149 } // namespace extensions 150