• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "base/compiler_specific.h"
6 #include "base/message_loop/message_loop.h"
7 #include "base/strings/string_tokenizer.h"
8 #include "mojo/public/cpp/application/application.h"
9 #include "mojo/services/public/cpp/view_manager/types.h"
10 #include "mojo/services/public/interfaces/launcher/launcher.mojom.h"
11 #include "mojo/services/public/interfaces/network/network_service.mojom.h"
12 #include "mojo/services/public/interfaces/network/url_loader.mojom.h"
13 #include "url/gurl.h"
14 
15 namespace mojo {
16 namespace launcher {
17 
18 class LauncherApp;
19 
20 class LauncherConnection : public InterfaceImpl<Launcher> {
21  public:
LauncherConnection(LauncherApp * app)22   explicit LauncherConnection(LauncherApp* app) : app_(app) {}
~LauncherConnection()23   virtual ~LauncherConnection() {}
24 
25  private:
26   // Overridden from Launcher:
27   virtual void Launch(const String& url) OVERRIDE;
28 
29   LauncherApp* app_;
30 
31   DISALLOW_COPY_AND_ASSIGN(LauncherConnection);
32 };
33 
34 class LaunchInstance : public URLLoaderClient {
35  public:
36   LaunchInstance(LauncherApp* app,
37                  LauncherClient* client,
38                  const String& url);
~LaunchInstance()39   virtual ~LaunchInstance() {}
40 
41  private:
42   // Overridden from URLLoaderClient:
OnReceivedRedirect(URLResponsePtr response,const String & new_url,const String & new_method)43   virtual void OnReceivedRedirect(URLResponsePtr response,
44                                   const String& new_url,
45                                   const String& new_method) OVERRIDE {
46   }
47   virtual void OnReceivedResponse(URLResponsePtr response) OVERRIDE;
OnReceivedError(NetworkErrorPtr error)48   virtual void OnReceivedError(NetworkErrorPtr error) OVERRIDE {
49     ScheduleDestroy();
50   }
OnReceivedEndOfResponseBody()51   virtual void OnReceivedEndOfResponseBody() OVERRIDE {
52     ScheduleDestroy();
53   }
54 
GetContentType(const Array<String> & headers)55   std::string GetContentType(const Array<String>& headers) {
56     for (size_t i = 0; i < headers.size(); ++i) {
57       base::StringTokenizer t(headers[i], ": ;=");
58       while (t.GetNext()) {
59         if (!t.token_is_delim() && t.token() == "Content-Type") {
60           while (t.GetNext()) {
61             if (!t.token_is_delim())
62               return t.token();
63           }
64         }
65       }
66     }
67     return "";
68   }
69 
ScheduleDestroy()70   void ScheduleDestroy() {
71     if (destroy_scheduled_)
72       return;
73     destroy_scheduled_ = true;
74     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
75   }
76 
77   LauncherApp* app_;
78   bool destroy_scheduled_;
79   LauncherClient* client_;
80   URLLoaderPtr url_loader_;
81   ScopedDataPipeConsumerHandle response_body_stream_;
82 
83   DISALLOW_COPY_AND_ASSIGN(LaunchInstance);
84 };
85 
86 class LauncherApp : public Application {
87  public:
LauncherApp()88   LauncherApp() {
89     handler_map_["text/html"] = "mojo:mojo_html_viewer";
90     handler_map_["image/png"] = "mojo:mojo_image_viewer";
91   }
~LauncherApp()92   virtual ~LauncherApp() {}
93 
CreateURLLoader()94   URLLoaderPtr CreateURLLoader() {
95     URLLoaderPtr loader;
96     network_service_->CreateURLLoader(Get(&loader));
97     return loader.Pass();
98   }
99 
GetHandlerForContentType(const std::string & content_type)100   std::string GetHandlerForContentType(const std::string& content_type) {
101     HandlerMap::const_iterator it = handler_map_.find(content_type);
102     return it != handler_map_.end() ? it->second : "";
103   }
104 
105  private:
106   typedef std::map<std::string, std::string> HandlerMap;
107 
108   // Overridden from Application:
Initialize()109   virtual void Initialize() OVERRIDE {
110     AddService<LauncherConnection>(this);
111     ConnectTo("mojo:mojo_network_service", &network_service_);
112   }
113 
114   HandlerMap handler_map_;
115 
116   NetworkServicePtr network_service_;
117 
118   DISALLOW_COPY_AND_ASSIGN(LauncherApp);
119 };
120 
Launch(const String & url_string)121 void LauncherConnection::Launch(const String& url_string) {
122   GURL url(url_string.To<std::string>());
123 
124   // For Mojo URLs, the handler can always be found at the origin.
125   // TODO(aa): Return error for invalid URL?
126   if (url.is_valid() && url.SchemeIs("mojo")) {
127     client()->OnLaunch(url_string,
128                        url.GetOrigin().spec(),
129                        navigation::ResponseDetailsPtr());
130     return;
131   }
132 
133   new LaunchInstance(app_, client(), url_string);
134 }
135 
LaunchInstance(LauncherApp * app,LauncherClient * client,const String & url)136 LaunchInstance::LaunchInstance(LauncherApp* app,
137                                LauncherClient* client,
138                                const String& url)
139     : app_(app),
140       destroy_scheduled_(false),
141       client_(client) {
142   url_loader_ = app_->CreateURLLoader();
143   url_loader_.set_client(this);
144 
145   URLRequestPtr request(URLRequest::New());
146   request->url = url;
147   request->method = "GET";
148   request->auto_follow_redirects = true;
149 
150   DataPipe data_pipe;
151   response_body_stream_ = data_pipe.consumer_handle.Pass();
152 
153   url_loader_->Start(request.Pass(), data_pipe.producer_handle.Pass());
154 }
155 
OnReceivedResponse(URLResponsePtr response)156 void LaunchInstance::OnReceivedResponse(URLResponsePtr response) {
157   std::string content_type = GetContentType(response->headers);
158   std::string handler_url = app_->GetHandlerForContentType(content_type);
159   if (!handler_url.empty()) {
160     navigation::ResponseDetailsPtr nav_response(
161         navigation::ResponseDetails::New());
162     nav_response->response = response.Pass();
163     nav_response->response_body_stream = response_body_stream_.Pass();
164     client_->OnLaunch(nav_response->response->url, handler_url,
165                       nav_response.Pass());
166   }
167 }
168 
169 }  // namespace launcher
170 
171 // static
Create()172 Application* Application::Create() {
173   return new launcher::LauncherApp;
174 }
175 
176 }  // namespace mojo
177