Merge lp:~phablet-team/media-hub/fix-1449790 into lp:media-hub

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
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_

Subscribers

People subscribed via source and target branches

to all changes: