Merge lp:~phablet-team/media-hub/fix-1449790 into lp:media-hub
- fix-1449790
- Merge into trunk
Proposed by
Jim Hodapp
Status: | Merged |
---|---|
Approved by: | Alfonso Sanchez-Beato |
Approved revision: | 170 |
Merged at revision: | 170 |
Proposed branch: | lp:~phablet-team/media-hub/fix-1449790 |
Merge into: | lp:media-hub |
Diff against target: |
780 lines (+429/-67) 13 files modified
include/core/media/player.h (+5/-0) src/core/media/gstreamer/engine.cpp (+6/-3) src/core/media/gstreamer/playbin.cpp (+129/-28) src/core/media/gstreamer/playbin.h (+3/-0) src/core/media/mpris/player.h (+8/-0) src/core/media/player.cpp (+6/-0) src/core/media/player_implementation.cpp (+2/-2) src/core/media/player_skeleton.cpp (+57/-22) src/core/media/player_stub.cpp (+2/-0) src/core/media/track_list_implementation.cpp (+0/-1) src/core/media/track_list_skeleton.cpp (+46/-11) src/core/media/track_list_stub.cpp (+5/-0) src/core/media/util/uri_check.h (+160/-0) |
To merge this branch: | bzr merge lp:~phablet-team/media-hub/fix-1449790 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alfonso Sanchez-Beato | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+285813@code.launchpad.net |
Commit message
Make sure to interpret the incoming path as a URI which makes sure media-hub will always be able to open the track with an encoded URI
Description of the change
Make sure to interpret the incoming path as a URI which makes sure media-hub will always be able to open the track with an encoded URI
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
LGTM
review:
Approve
- 171. By Jim Hodapp
-
Do the percent encoding and checking only from media-hub and don't involve qtubuntu-media
- 172. By Jim Hodapp
-
Get rid of some debug statements
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
See comments below.
review:
Needs Fixing
Revision history for this message
Jim Hodapp (jhodapp) : | # |
- 173. By Jim Hodapp
-
Make sure other tracks can still be added to the tracklist after an invalid URI is determined. Also make sure to free all gchar strings
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Still some comments, see below.
review:
Needs Fixing
- 174. By Jim Hodapp
-
Address review comments
- 175. By Jim Hodapp
-
One last comment addressed
- 176. By Jim Hodapp
-
Make sure to not crash during std::string:
:assign( gchar*)
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
LGTM
review:
Approve
- 177. By Jim Hodapp
-
Removed no longer needed debug statement
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'include/core/media/player.h' |
2 | --- include/core/media/player.h 2016-01-14 19:47:40 +0000 |
3 | +++ include/core/media/player.h 2016-02-22 18:59:27 +0000 |
4 | @@ -61,6 +61,11 @@ |
5 | { |
6 | InsufficientAppArmorPermissions(const std::string& err); |
7 | }; |
8 | + |
9 | + struct UriNotFound : public std::runtime_error |
10 | + { |
11 | + UriNotFound(const std::string& err); |
12 | + }; |
13 | }; |
14 | |
15 | struct Configuration; |
16 | |
17 | === modified file 'src/core/media/gstreamer/engine.cpp' |
18 | --- src/core/media/gstreamer/engine.cpp 2015-09-04 18:46:08 +0000 |
19 | +++ src/core/media/gstreamer/engine.cpp 2016-02-22 18:59:27 +0000 |
20 | @@ -400,7 +400,8 @@ |
21 | d->state = media::Engine::State::no_media; |
22 | } |
23 | |
24 | -const std::shared_ptr<media::Engine::MetaDataExtractor>& gstreamer::Engine::meta_data_extractor() const |
25 | +const std::shared_ptr<media::Engine::MetaDataExtractor>& |
26 | + gstreamer::Engine::meta_data_extractor() const |
27 | { |
28 | return d->meta_data_extractor; |
29 | } |
30 | @@ -410,13 +411,15 @@ |
31 | return d->state; |
32 | } |
33 | |
34 | -bool gstreamer::Engine::open_resource_for_uri(const media::Track::UriType& uri, bool do_pipeline_reset) |
35 | +bool gstreamer::Engine::open_resource_for_uri(const media::Track::UriType& uri, |
36 | + bool do_pipeline_reset) |
37 | { |
38 | d->playbin.set_uri(uri, core::ubuntu::media::Player::HeadersType{}, do_pipeline_reset); |
39 | return true; |
40 | } |
41 | |
42 | -bool gstreamer::Engine::open_resource_for_uri(const media::Track::UriType& uri, const core::ubuntu::media::Player::HeadersType& headers) |
43 | +bool gstreamer::Engine::open_resource_for_uri(const media::Track::UriType& uri, |
44 | + const core::ubuntu::media::Player::HeadersType& headers) |
45 | { |
46 | d->playbin.set_uri(uri, headers); |
47 | return true; |
48 | |
49 | === modified file 'src/core/media/gstreamer/playbin.cpp' |
50 | --- src/core/media/gstreamer/playbin.cpp 2015-12-16 16:55:51 +0000 |
51 | +++ src/core/media/gstreamer/playbin.cpp 2016-02-22 18:59:27 +0000 |
52 | @@ -17,7 +17,6 @@ |
53 | */ |
54 | |
55 | #include <core/media/gstreamer/playbin.h> |
56 | - |
57 | #include <core/media/gstreamer/engine.h> |
58 | |
59 | #include <gst/pbutils/missing-plugins.h> |
60 | @@ -26,8 +25,12 @@ |
61 | #include <hybris/media/surface_texture_client_hybris.h> |
62 | #include <hybris/media/media_codec_layer.h> |
63 | |
64 | +#include "../util/uri_check.h" |
65 | + |
66 | #include <utility> |
67 | |
68 | +//#define VERBOSE_DEBUG |
69 | + |
70 | namespace |
71 | { |
72 | void setup_video_sink_for_buffer_streaming(GstElement* pipeline) |
73 | @@ -464,10 +467,23 @@ |
74 | if (current_uri and do_pipeline_reset) |
75 | reset_pipeline(); |
76 | |
77 | - g_object_set(pipeline, "uri", uri.c_str(), NULL); |
78 | - if (is_video_file(uri)) |
79 | + std::string encoded_uri; |
80 | + media::UriCheck::Ptr uri_check{std::make_shared<media::UriCheck>(uri)}; |
81 | + if (uri_check->is_encoded()) |
82 | + { |
83 | + encoded_uri = decode_uri(uri); |
84 | +#ifdef VERBOSE_DEBUG |
85 | + std::cout << "File URI was encoded, now decoded: " << encoded_uri << std::endl; |
86 | +#endif |
87 | + encoded_uri = encode_uri(encoded_uri); |
88 | + } |
89 | + else |
90 | + encoded_uri = encode_uri(uri); |
91 | + |
92 | + g_object_set(pipeline, "uri", encoded_uri.c_str(), NULL); |
93 | + if (is_video_file(encoded_uri)) |
94 | file_type = MEDIA_FILE_TYPE_VIDEO; |
95 | - else if (is_audio_file(uri)) |
96 | + else if (is_audio_file(encoded_uri)) |
97 | file_type = MEDIA_FILE_TYPE_AUDIO; |
98 | |
99 | request_headers = headers; |
100 | @@ -607,25 +623,13 @@ |
101 | signals.on_video_dimensions_changed(new_dimensions); |
102 | } |
103 | |
104 | -std::string gstreamer::Playbin::get_file_content_type(const std::string& uri) const |
105 | +std::string gstreamer::Playbin::file_info_from_uri(const std::string& uri) const |
106 | { |
107 | - if (uri.empty()) |
108 | - return std::string(); |
109 | - |
110 | - std::string filename(uri); |
111 | - size_t pos = uri.find("file://"); |
112 | - if (pos != std::string::npos) |
113 | - filename = uri.substr(pos + 7, std::string::npos); |
114 | - else |
115 | - // Anything other than a file, for now claim that the type |
116 | - // is both audio and video. |
117 | - // FIXME: implement true net stream sampling and get the type from GstCaps |
118 | - return std::string("audio/video/"); |
119 | - |
120 | - |
121 | GError *error = nullptr; |
122 | + // Open the URI and get the mime type from it. This will currently only work for |
123 | + // a local file |
124 | std::unique_ptr<GFile, void(*)(void *)> file( |
125 | - g_file_new_for_path(filename.c_str()), g_object_unref); |
126 | + g_file_new_for_uri(uri.c_str()), g_object_unref); |
127 | std::unique_ptr<GFileInfo, void(*)(void *)> info( |
128 | g_file_query_info( |
129 | file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
130 | @@ -633,17 +637,114 @@ |
131 | /* cancellable */ NULL, &error), |
132 | g_object_unref); |
133 | if (!info) |
134 | - { |
135 | - std::string error_str(error->message); |
136 | - g_error_free(error); |
137 | - |
138 | - std::cout << "Failed to query the URI for the presence of video content: " |
139 | - << error_str << std::endl; |
140 | return std::string(); |
141 | - } |
142 | |
143 | - std::string content_type(g_file_info_get_attribute_string( |
144 | + return std::string(g_file_info_get_attribute_string( |
145 | info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE)); |
146 | +} |
147 | + |
148 | +std::string gstreamer::Playbin::encode_uri(const std::string& uri) const |
149 | +{ |
150 | + if (uri.empty()) |
151 | + return std::string(); |
152 | + |
153 | + std::string encoded_uri; |
154 | + media::UriCheck::Ptr uri_check{std::make_shared<media::UriCheck>(uri)}; |
155 | + gchar *uri_scheme = g_uri_parse_scheme(uri.c_str()); |
156 | + // We have a URI and it is already percent encoded |
157 | + if (uri_scheme and strlen(uri_scheme) > 0 and uri_check->is_encoded()) |
158 | + { |
159 | +#ifdef VERBOSE_DEBUG |
160 | + std::cout << "Is a URI and is already percent encoded" << std::endl; |
161 | +#endif |
162 | + encoded_uri = uri; |
163 | + } |
164 | + // We have a URI but it's not already percent encoded |
165 | + else if (uri_scheme and strlen(uri_scheme) > 0 and !uri_check->is_encoded()) |
166 | + { |
167 | +#ifdef VERBOSE_DEBUG |
168 | + std::cout << "Is a URI and is not already percent encoded" << std::endl; |
169 | +#endif |
170 | + gchar *encoded = g_uri_escape_string(uri.c_str(), |
171 | + "!$&'()*+,;=:/?[]@", // reserved chars |
172 | + TRUE); // Allow UTF-8 chars |
173 | + if (!encoded) |
174 | + { |
175 | + g_free(uri_scheme); |
176 | + return std::string(); |
177 | + } |
178 | + encoded_uri.assign(encoded); |
179 | + g_free(encoded); |
180 | + } |
181 | + else // We have a path and not a URI. Turn it into a full URI and encode it |
182 | + { |
183 | + GError *error = nullptr; |
184 | +#ifdef VERBOSE_DEBUG |
185 | + std::cout << "Is a path and is not already percent encoded" << std::endl; |
186 | +#endif |
187 | + gchar *str = g_filename_to_uri(uri.c_str(), nullptr, &error); |
188 | + if (!str) |
189 | + { |
190 | + g_free(uri_scheme); |
191 | + return std::string(); |
192 | + } |
193 | + encoded_uri.assign(str); |
194 | + g_free(str); |
195 | + if (error != nullptr) |
196 | + { |
197 | + std::cerr << "Warning: failed to get actual track content type: " << error->message |
198 | + << std::endl; |
199 | + g_error_free(error); |
200 | + g_free(str); |
201 | + g_free(uri_scheme); |
202 | + return std::string("audio/video/"); |
203 | + } |
204 | + gchar *escaped = g_uri_escape_string(encoded_uri.c_str(), |
205 | + "!$&'()*+,;=:/?[]@", // reserved chars |
206 | + TRUE); // Allow UTF-8 chars |
207 | + if (!escaped) |
208 | + { |
209 | + g_free(uri_scheme); |
210 | + return std::string(); |
211 | + } |
212 | + encoded_uri.assign(escaped); |
213 | + g_free(escaped); |
214 | + } |
215 | + |
216 | + g_free(uri_scheme); |
217 | + |
218 | + return encoded_uri; |
219 | +} |
220 | + |
221 | +std::string gstreamer::Playbin::decode_uri(const std::string& uri) const |
222 | +{ |
223 | + if (uri.empty()) |
224 | + return std::string(); |
225 | + |
226 | + gchar *decoded_gchar = g_uri_unescape_string(uri.c_str(), nullptr); |
227 | + if (!decoded_gchar) |
228 | + return std::string(); |
229 | + |
230 | + const std::string decoded{decoded_gchar}; |
231 | + g_free(decoded_gchar); |
232 | + return decoded; |
233 | +} |
234 | + |
235 | +std::string gstreamer::Playbin::get_file_content_type(const std::string& uri) const |
236 | +{ |
237 | + if (uri.empty()) |
238 | + return std::string(); |
239 | + |
240 | + const std::string encoded_uri{encode_uri(uri)}; |
241 | + |
242 | + const std::string content_type {file_info_from_uri(encoded_uri)}; |
243 | + if (content_type.empty()) |
244 | + { |
245 | + std::cerr << "Warning: failed to get actual track content type" << std::endl; |
246 | + return std::string("audio/video/"); |
247 | + } |
248 | + |
249 | + std::cout << "Found content type: " << content_type << std::endl; |
250 | |
251 | return content_type; |
252 | } |
253 | |
254 | === modified file 'src/core/media/gstreamer/playbin.h' |
255 | --- src/core/media/gstreamer/playbin.h 2015-09-23 11:17:26 +0000 |
256 | +++ src/core/media/gstreamer/playbin.h 2016-02-22 18:59:27 +0000 |
257 | @@ -104,6 +104,9 @@ |
258 | core::ubuntu::media::video::Dimensions get_video_dimensions() const; |
259 | void emit_video_dimensions_changed_if_changed(const core::ubuntu::media::video::Dimensions &new_dimensions); |
260 | |
261 | + std::string file_info_from_uri(const std::string& uri) const; |
262 | + std::string encode_uri(const std::string& uri) const; |
263 | + std::string decode_uri(const std::string& uri) const; |
264 | std::string get_file_content_type(const std::string& uri) const; |
265 | |
266 | bool is_audio_file(const std::string& uri) const; |
267 | |
268 | === modified file 'src/core/media/mpris/player.h' |
269 | --- src/core/media/mpris/player.h 2016-01-14 19:47:40 +0000 |
270 | +++ src/core/media/mpris/player.h 2016-02-22 18:59:27 +0000 |
271 | @@ -124,6 +124,14 @@ |
272 | "mpris.Player.Error.InsufficientAppArmorPermissions" |
273 | }; |
274 | }; |
275 | + |
276 | + struct UriNotFound |
277 | + { |
278 | + static constexpr const char* name |
279 | + { |
280 | + "mpris.Player.Error.UriNotFound" |
281 | + }; |
282 | + }; |
283 | }; |
284 | |
285 | typedef std::map<std::string, core::dbus::types::Variant> Dictionary; |
286 | |
287 | === modified file 'src/core/media/player.cpp' |
288 | --- src/core/media/player.cpp 2016-01-14 19:47:40 +0000 |
289 | +++ src/core/media/player.cpp 2016-02-22 18:59:27 +0000 |
290 | @@ -33,6 +33,12 @@ |
291 | { |
292 | } |
293 | |
294 | +media::Player::Errors::UriNotFound::UriNotFound |
295 | + (const std::string &e) |
296 | + : std::runtime_error{e} |
297 | +{ |
298 | +} |
299 | + |
300 | const media::Player::Configuration& media::Player::Client::default_configuration() |
301 | { |
302 | static const media::Player::Configuration config |
303 | |
304 | === modified file 'src/core/media/player_implementation.cpp' |
305 | --- src/core/media/player_implementation.cpp 2015-11-18 15:55:23 +0000 |
306 | +++ src/core/media/player_implementation.cpp 2016-02-22 18:59:27 +0000 |
307 | @@ -292,8 +292,8 @@ |
308 | const Track::UriType uri = track_list->query_uri_for_track(id); |
309 | if (!uri.empty()) |
310 | { |
311 | - // Using a TrackList for playback, added tracks via add_track(), but open_uri hasn't been called yet |
312 | - // to load a media resource |
313 | + // Using a TrackList for playback, added tracks via add_track(), but open_uri hasn't |
314 | + // been called yet to load a media resource |
315 | std::cout << "Calling d->engine->open_resource_for_uri() for first track added only: " |
316 | << uri << std::endl; |
317 | std::cout << "\twith a Track::Id: " << id << std::endl; |
318 | |
319 | === modified file 'src/core/media/player_skeleton.cpp' |
320 | --- src/core/media/player_skeleton.cpp 2016-01-14 20:08:38 +0000 |
321 | +++ src/core/media/player_skeleton.cpp 2016-02-22 18:59:27 +0000 |
322 | @@ -31,6 +31,7 @@ |
323 | #include "mpris/metadata.h" |
324 | #include "mpris/player.h" |
325 | #include "mpris/playlists.h" |
326 | +#include "util/uri_check.h" |
327 | |
328 | #include <core/dbus/object.h> |
329 | #include <core/dbus/property.h> |
330 | @@ -54,6 +55,7 @@ |
331 | object(session), |
332 | request_context_resolver{request_context_resolver}, |
333 | request_authenticator{request_authenticator}, |
334 | + uri_check(std::make_shared<UriCheck>()), |
335 | skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}}, |
336 | signals |
337 | { |
338 | @@ -180,22 +182,38 @@ |
339 | in->reader() >> uri; |
340 | |
341 | auto reply = dbus::Message::make_method_return(in); |
342 | - // Make sure the client has adequate apparmor permissions to open the URI |
343 | - const auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
344 | - if (std::get<0>(result)) |
345 | - { |
346 | - reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false); |
347 | - } |
348 | - else |
349 | - { |
350 | - const std::string err_str = {"Warning: Failed to authenticate necessary " |
351 | - "apparmor permissions to open uri: " + std::get<1>(result)}; |
352 | + uri_check->set(uri); |
353 | + const bool valid_uri = !uri_check->is_local_file() or |
354 | + (uri_check->is_local_file() and uri_check->file_exists()); |
355 | + if (!valid_uri) |
356 | + { |
357 | + const std::string err_str = {"Warning: Failed to open uri " + uri + |
358 | + " because it can't be found."}; |
359 | std::cerr << err_str << std::endl; |
360 | reply = dbus::Message::make_error( |
361 | in, |
362 | - mpris::Player::Error::InsufficientAppArmorPermissions::name, |
363 | + mpris::Player::Error::UriNotFound::name, |
364 | err_str); |
365 | } |
366 | + else |
367 | + { |
368 | + // Make sure the client has adequate apparmor permissions to open the URI |
369 | + const auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
370 | + if (std::get<0>(result)) |
371 | + { |
372 | + reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false); |
373 | + } |
374 | + else |
375 | + { |
376 | + const std::string err_str = {"Warning: Failed to authenticate necessary " |
377 | + "apparmor permissions to open uri: " + std::get<1>(result)}; |
378 | + std::cerr << err_str << std::endl; |
379 | + reply = dbus::Message::make_error( |
380 | + in, |
381 | + mpris::Player::Error::InsufficientAppArmorPermissions::name, |
382 | + err_str); |
383 | + } |
384 | + } |
385 | |
386 | bus->send(reply); |
387 | }); |
388 | @@ -211,22 +229,38 @@ |
389 | in->reader() >> uri >> headers; |
390 | |
391 | auto reply = dbus::Message::make_method_return(in); |
392 | - // Make sure the client has adequate apparmor permissions to open the URI |
393 | - const auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
394 | - if (std::get<0>(result)) |
395 | - { |
396 | - reply->writer() << (std::get<0>(result) ? impl->open_uri(uri, headers) : false); |
397 | - } |
398 | - else |
399 | - { |
400 | - const std::string err_str = {"Warning: Failed to authenticate necessary " |
401 | - "apparmor permissions to open uri: " + std::get<1>(result)}; |
402 | + uri_check->set(uri); |
403 | + const bool valid_uri = !uri_check->is_local_file() or |
404 | + (uri_check->is_local_file() and uri_check->file_exists()); |
405 | + if (!valid_uri) |
406 | + { |
407 | + const std::string err_str = {"Warning: Failed to open uri " + uri + |
408 | + " because it can't be found."}; |
409 | std::cerr << err_str << std::endl; |
410 | reply = dbus::Message::make_error( |
411 | in, |
412 | - mpris::Player::Error::InsufficientAppArmorPermissions::name, |
413 | + mpris::Player::Error::UriNotFound::name, |
414 | err_str); |
415 | } |
416 | + else |
417 | + { |
418 | + // Make sure the client has adequate apparmor permissions to open the URI |
419 | + const auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
420 | + if (std::get<0>(result)) |
421 | + { |
422 | + reply->writer() << (std::get<0>(result) ? impl->open_uri(uri, headers) : false); |
423 | + } |
424 | + else |
425 | + { |
426 | + const std::string err_str = {"Warning: Failed to authenticate necessary " |
427 | + "apparmor permissions to open uri: " + std::get<1>(result)}; |
428 | + std::cerr << err_str << std::endl; |
429 | + reply = dbus::Message::make_error( |
430 | + in, |
431 | + mpris::Player::Error::InsufficientAppArmorPermissions::name, |
432 | + err_str); |
433 | + } |
434 | + } |
435 | |
436 | bus->send(reply); |
437 | }); |
438 | @@ -258,6 +292,7 @@ |
439 | dbus::Object::Ptr object; |
440 | media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; |
441 | media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator; |
442 | + media::UriCheck::Ptr uri_check; |
443 | |
444 | mpris::Player::Skeleton skeleton; |
445 | |
446 | |
447 | === modified file 'src/core/media/player_stub.cpp' |
448 | --- src/core/media/player_stub.cpp 2016-01-14 19:47:40 +0000 |
449 | +++ src/core/media/player_stub.cpp 2016-02-22 18:59:27 +0000 |
450 | @@ -266,6 +266,8 @@ |
451 | { |
452 | if (op.error().name() == mpris::Player::Error::InsufficientAppArmorPermissions::name) |
453 | throw media::Player::Errors::InsufficientAppArmorPermissions{op.error().print()}; |
454 | + else if (op.error().name() == mpris::Player::Error::UriNotFound::name) |
455 | + throw media::Player::Errors::UriNotFound{op.error().print()}; |
456 | else |
457 | throw std::runtime_error{op.error().print()}; |
458 | } |
459 | |
460 | === modified file 'src/core/media/track_list_implementation.cpp' |
461 | --- src/core/media/track_list_implementation.cpp 2015-11-18 18:33:31 +0000 |
462 | +++ src/core/media/track_list_implementation.cpp 2016-02-22 18:59:27 +0000 |
463 | @@ -140,7 +140,6 @@ |
464 | { |
465 | auto it = std::find(container.begin(), container.end(), position); |
466 | container.insert(it, id); |
467 | - std::cout << "container.size(): " << container.size() << std::endl; |
468 | |
469 | return true; |
470 | }); |
471 | |
472 | === modified file 'src/core/media/track_list_skeleton.cpp' |
473 | --- src/core/media/track_list_skeleton.cpp 2015-11-18 18:33:31 +0000 |
474 | +++ src/core/media/track_list_skeleton.cpp 2016-02-22 18:59:27 +0000 |
475 | @@ -27,7 +27,9 @@ |
476 | #include "track_list_traits.h" |
477 | #include "the_session_bus.h" |
478 | |
479 | +#include "mpris/player.h" |
480 | #include "mpris/track_list.h" |
481 | +#include "util/uri_check.h" |
482 | |
483 | #include <core/dbus/object.h> |
484 | #include <core/dbus/property.h> |
485 | @@ -56,6 +58,7 @@ |
486 | object(object), |
487 | request_context_resolver(request_context_resolver), |
488 | request_authenticator(request_authenticator), |
489 | + uri_check(std::make_shared<UriCheck>()), |
490 | skeleton(mpris::TrackList::Skeleton::Configuration{object, mpris::TrackList::Skeleton::Configuration::Defaults{}}), |
491 | current_track(skeleton.properties.tracks->get().begin()), |
492 | empty_iterator(skeleton.properties.tracks->get().begin()), |
493 | @@ -112,23 +115,39 @@ |
494 | |
495 | // Make sure the client has adequate apparmor permissions to open the URI |
496 | const auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
497 | - |
498 | auto reply = dbus::Message::make_method_return(msg); |
499 | - // Only add the track to the TrackList if it passes the apparmor permissions check |
500 | - if (std::get<0>(result)) |
501 | - { |
502 | - impl->add_track_with_uri_at(uri, after, make_current); |
503 | - } |
504 | - else |
505 | + |
506 | + uri_check->set(uri); |
507 | + const bool valid_uri = !uri_check->is_local_file() or |
508 | + (uri_check->is_local_file() and uri_check->file_exists()); |
509 | + if (!valid_uri) |
510 | { |
511 | const std::string err_str = {"Warning: Not adding track " + uri + |
512 | - " to TrackList because of inadequate client apparmor permissions."}; |
513 | + " to TrackList because it can't be found."}; |
514 | std::cerr << err_str << std::endl; |
515 | reply = dbus::Message::make_error( |
516 | msg, |
517 | - mpris::TrackList::Error::InsufficientPermissionsToAddTrack::name, |
518 | + mpris::Player::Error::UriNotFound::name, |
519 | err_str); |
520 | } |
521 | + else |
522 | + { |
523 | + // Only add the track to the TrackList if it passes the apparmor permissions check |
524 | + if (std::get<0>(result)) |
525 | + { |
526 | + impl->add_track_with_uri_at(uri, after, make_current); |
527 | + } |
528 | + else |
529 | + { |
530 | + const std::string err_str = {"Warning: Not adding track " + uri + |
531 | + " to TrackList because of inadequate client apparmor permissions."}; |
532 | + std::cerr << err_str << std::endl; |
533 | + reply = dbus::Message::make_error( |
534 | + msg, |
535 | + mpris::TrackList::Error::InsufficientPermissionsToAddTrack::name, |
536 | + err_str); |
537 | + } |
538 | + } |
539 | |
540 | bus->send(reply); |
541 | }); |
542 | @@ -144,10 +163,26 @@ |
543 | media::Track::Id after; |
544 | msg->reader() >> uris >> after; |
545 | |
546 | + bool valid_uri = false; |
547 | media::apparmor::ubuntu::RequestAuthenticator::Result result; |
548 | - std::string err_str; |
549 | + std::string uri_err_str, err_str; |
550 | + core::dbus::Message::Ptr reply; |
551 | for (const auto uri : uris) |
552 | { |
553 | + uri_check->set(uri); |
554 | + valid_uri = !uri_check->is_local_file() or |
555 | + (uri_check->is_local_file() and uri_check->file_exists()); |
556 | + if (!valid_uri) |
557 | + { |
558 | + uri_err_str = {"Warning: Not adding track " + uri + |
559 | + " to TrackList because it can't be found."}; |
560 | + std::cerr << uri_err_str << std::endl; |
561 | + reply = dbus::Message::make_error( |
562 | + msg, |
563 | + mpris::Player::Error::UriNotFound::name, |
564 | + err_str); |
565 | + } |
566 | + |
567 | // Make sure the client has adequate apparmor permissions to open the URI |
568 | result = request_authenticator->authenticate_open_uri_request(context, uri); |
569 | if (not std::get<0>(result)) |
570 | @@ -158,7 +193,6 @@ |
571 | } |
572 | } |
573 | |
574 | - core::dbus::Message::Ptr reply; |
575 | // Only add the track to the TrackList if it passes the apparmor permissions check |
576 | if (std::get<0>(result)) |
577 | { |
578 | @@ -312,6 +346,7 @@ |
579 | dbus::Object::Ptr object; |
580 | media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; |
581 | media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator; |
582 | + media::UriCheck::Ptr uri_check; |
583 | |
584 | mpris::TrackList::Skeleton skeleton; |
585 | TrackList::ConstIterator current_track; |
586 | |
587 | === modified file 'src/core/media/track_list_stub.cpp' |
588 | --- src/core/media/track_list_stub.cpp 2015-11-18 15:55:23 +0000 |
589 | +++ src/core/media/track_list_stub.cpp 2016-02-22 18:59:27 +0000 |
590 | @@ -25,6 +25,7 @@ |
591 | #include "track_list_traits.h" |
592 | #include "the_session_bus.h" |
593 | |
594 | +#include "mpris/player.h" |
595 | #include "mpris/track_list.h" |
596 | |
597 | #include <core/dbus/property.h> |
598 | @@ -239,6 +240,8 @@ |
599 | if (op.error().name() == |
600 | mpris::TrackList::Error::InsufficientPermissionsToAddTrack::name) |
601 | throw media::TrackList::Errors::InsufficientPermissionsToAddTrack{}; |
602 | + else if (op.error().name() == mpris::Player::Error::UriNotFound::name) |
603 | + throw media::Player::Errors::UriNotFound{op.error().print()}; |
604 | else |
605 | throw std::runtime_error{op.error().print()}; |
606 | } |
607 | @@ -255,6 +258,8 @@ |
608 | if (op.error().name() == |
609 | mpris::TrackList::Error::InsufficientPermissionsToAddTrack::name) |
610 | throw media::TrackList::Errors::InsufficientPermissionsToAddTrack{}; |
611 | + else if (op.error().name() == mpris::Player::Error::UriNotFound::name) |
612 | + throw media::Player::Errors::UriNotFound{op.error().print()}; |
613 | else |
614 | throw std::runtime_error{op.error().print()}; |
615 | } |
616 | |
617 | === added file 'src/core/media/util/uri_check.h' |
618 | --- src/core/media/util/uri_check.h 1970-01-01 00:00:00 +0000 |
619 | +++ src/core/media/util/uri_check.h 2016-02-22 18:59:27 +0000 |
620 | @@ -0,0 +1,160 @@ |
621 | +/* |
622 | + * |
623 | + * This program is free software: you can redistribute it and/or modify it |
624 | + * under the terms of the GNU Lesser General Public License version 3, |
625 | + * as published by the Free Software Foundation. |
626 | + * |
627 | + * This program is distributed in the hope that it will be useful, |
628 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
629 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
630 | + * GNU Lesser General Public License for more details. |
631 | + * |
632 | + * You should have received a copy of the GNU Lesser General Public License |
633 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
634 | + * |
635 | + * Authored by: Jim Hodapp <jim.hodapp@canonical.com> |
636 | + * |
637 | + */ |
638 | + |
639 | +#ifndef URI_CHECK_H_ |
640 | +#define URI_CHECK_H_ |
641 | + |
642 | +#include <gio/gio.h> |
643 | + |
644 | +#include <memory> |
645 | +#include <iostream> |
646 | + |
647 | +namespace core |
648 | +{ |
649 | +namespace ubuntu |
650 | +{ |
651 | +namespace media |
652 | +{ |
653 | + |
654 | +class UriCheck |
655 | +{ |
656 | +public: |
657 | + typedef std::shared_ptr<UriCheck> Ptr; |
658 | + |
659 | + UriCheck() |
660 | + : is_encoded_(false), |
661 | + is_local_file_(false), |
662 | + local_file_exists_(false) |
663 | + { |
664 | + } |
665 | + |
666 | + UriCheck(const std::string& uri) |
667 | + : uri_(uri), |
668 | + is_encoded_(determine_if_encoded()), |
669 | + is_local_file_(determine_if_local_file()), |
670 | + local_file_exists_(determine_if_file_exists()) |
671 | + { |
672 | + } |
673 | + |
674 | + virtual ~UriCheck() |
675 | + { |
676 | + } |
677 | + |
678 | + void set(const std::string& uri) |
679 | + { |
680 | + if (uri.empty()) |
681 | + return; |
682 | + |
683 | + uri_ = uri; |
684 | + is_encoded_ = determine_if_encoded(); |
685 | + is_local_file_ = determine_if_local_file(); |
686 | + local_file_exists_ = determine_if_file_exists(); |
687 | + } |
688 | + |
689 | + void clear() |
690 | + { |
691 | + uri_.clear(); |
692 | + } |
693 | + |
694 | + bool is_encoded() const |
695 | + { |
696 | + return is_encoded_; |
697 | + } |
698 | + |
699 | + bool is_local_file() const |
700 | + { |
701 | + return is_local_file_; |
702 | + } |
703 | + |
704 | + bool file_exists() const |
705 | + { |
706 | + return local_file_exists_; |
707 | + } |
708 | + |
709 | +protected: |
710 | + UriCheck(const UriCheck&) = delete; |
711 | + UriCheck& operator=(const UriCheck&) = delete; |
712 | + |
713 | +private: |
714 | + bool determine_if_encoded() |
715 | + { |
716 | + if (uri_.empty()) |
717 | + return false; |
718 | + |
719 | + gchar *tmp = g_uri_unescape_string(uri_.c_str(), nullptr); |
720 | + if (!tmp) |
721 | + return false; |
722 | + |
723 | + const std::string unescaped_uri{tmp}; |
724 | + g_free(tmp); |
725 | + return unescaped_uri.length() < uri_.length(); |
726 | + } |
727 | + |
728 | + bool determine_if_local_file() |
729 | + { |
730 | + if (uri_.empty()) |
731 | + return false; |
732 | + |
733 | + gchar *tmp = g_uri_parse_scheme(uri_.c_str()); |
734 | + std::string uri_scheme; |
735 | + if (tmp) |
736 | + uri_scheme.assign(tmp); |
737 | + g_free(tmp); |
738 | + try { |
739 | + return uri_.at(0) == '/' or |
740 | + (uri_.at(0) == '.' and uri_.at(1) == '/') or |
741 | + uri_scheme == "file"; |
742 | + } |
743 | + catch (const std::out_of_range &e) { |
744 | + std::cerr << "Invalid URI string provided: " << uri_ << std::endl; |
745 | + return false; |
746 | + } |
747 | + } |
748 | + |
749 | + bool determine_if_file_exists() |
750 | + { |
751 | + if (!is_local_file_) |
752 | + return false; |
753 | + |
754 | + GError *error = nullptr; |
755 | + // Open the URI and get the mime type from it. This will currently only work for |
756 | + // a local file |
757 | + std::unique_ptr<GFile, void(*)(void *)> file( |
758 | + g_file_new_for_uri(uri_.c_str()), g_object_unref); |
759 | + std::unique_ptr<GFileInfo, void(*)(void *)> info( |
760 | + g_file_query_info( |
761 | + file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
762 | + G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE, |
763 | + /* cancellable */ NULL, &error), |
764 | + g_object_unref); |
765 | + |
766 | + return info.get() != nullptr; |
767 | + } |
768 | + |
769 | +private: |
770 | + std::string uri_; |
771 | + bool is_encoded_; |
772 | + bool is_local_file_; |
773 | + bool local_file_exists_; |
774 | +}; |
775 | + |
776 | +} |
777 | +} |
778 | +} |
779 | + |
780 | +#endif // URI_CHECK_H_ |
PASSED: Continuous integration, rev:170 jenkins. qa.ubuntu. com/job/ media-hub- ci/394/ jenkins. qa.ubuntu. com/job/ media-hub- vivid-amd64- ci/234 jenkins. qa.ubuntu. com/job/ media-hub- vivid-armhf- ci/234 jenkins. qa.ubuntu. com/job/ media-hub- vivid-armhf- ci/234/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ media-hub- vivid-i386- ci/234
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/media- hub-ci/ 394/rebuild
http://