Merge lp:~mhr3/unity-lens-shopping/secure-connection into lp:unity-lens-shopping

Proposed by Michal Hruby
Status: Merged
Approved by: Paweł Stołowski
Approved revision: 23
Merged at revision: 22
Proposed branch: lp:~mhr3/unity-lens-shopping/secure-connection
Merge into: lp:unity-lens-shopping
Diff against target: 309 lines (+141/-68)
5 files modified
configure.ac (+2/-0)
src/Makefile.am (+3/-0)
src/scope.vala (+123/-68)
vapi/Makefile.am (+5/-0)
vapi/libsoup-gnome-2.4.vapi (+8/-0)
To merge this branch: bzr merge lp:~mhr3/unity-lens-shopping/secure-connection
Reviewer Review Type Date Requested Status
Paweł Stołowski (community) Approve
Review via email: mp+126396@code.launchpad.net

Commit message

Use secure connection to the server

Description of the change

Use secure connection to the server.

To post a comment you must log in.
22. By Michal Hruby

Use strict certificate checking

23. By Michal Hruby

Merge trunk, add more error reporting

Revision history for this message
Paweł Stołowski (stolowski) wrote :

Cool, we have SSL now! Looks good and works fine!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2012-07-25 15:18:43 +0000
3+++ configure.ac 2012-09-26 11:13:24 +0000
4@@ -62,6 +62,7 @@
5 gio-unix-2.0 >= $GLIB_REQUIRED
6 dee-1.0 >= 1.0.7
7 gee-1.0
8+ libsoup-gnome-2.4
9 json-glib-1.0
10 unity >= 5.93.0)
11
12@@ -118,6 +119,7 @@
13 data/Makefile
14 src/Makefile
15 src/config.vala
16+ vapi/Makefile
17 po/Makefile.in
18 ])
19 AC_OUTPUT
20
21=== modified file 'src/Makefile.am'
22--- src/Makefile.am 2012-09-24 16:17:01 +0000
23+++ src/Makefile.am 2012-09-26 11:13:24 +0000
24@@ -28,7 +28,10 @@
25 --pkg gio-unix-2.0 \
26 --pkg glib-2.0 \
27 --pkg json-glib-1.0 \
28+ --pkg libsoup-2.4 \
29 --vapidir $(srcdir) \
30+ --vapidir $(top_srcdir)/vapi \
31+ --pkg libsoup-gnome-2.4 \
32 --target-glib=2.26 \
33 $(MAINTAINER_VALAFLAGS) \
34 $(NULL)
35
36=== modified file 'src/scope.vala'
37--- src/scope.vala 2012-09-25 10:05:54 +0000
38+++ src/scope.vala 2012-09-26 11:13:24 +0000
39@@ -23,10 +23,11 @@
40 {
41 public class ShoppingScope : Unity.Scope
42 {
43- private const string OFFERS_BASE_URI = "http://productsearch.ubuntu.com";
44+ private const string OFFERS_BASE_URI = "https://productsearch.ubuntu.com";
45
46 private HashTable<string, string> results_details_map;
47 private HashTable<string, string> global_results_details_map;
48+ private Soup.Session session;
49 private PreviewPlayerHandler player;
50
51 public ShoppingScope ()
52@@ -36,6 +37,12 @@
53
54 protected override void constructed ()
55 {
56+ session = new Soup.SessionAsync ();
57+ session.ssl_use_system_ca_file = true;
58+ session.ssl_strict = true;
59+ session.user_agent = "Unity Shopping Lens " + Config.VERSION;
60+ session.add_feature_by_type (typeof (SoupGNOME.ProxyResolverGNOME));
61+
62 /* Listen for filter changes */
63 filters_changed.connect (() => {
64 queue_search_changed (SearchType.DEFAULT);
65@@ -94,6 +101,7 @@
66 process_search_reply_json (parser, Category.TREAT_YOURSELF,
67 search.results_model);
68 }
69+ catch (IOError.CANCELLED canc_err) { /* ignore */ }
70 catch (Error err)
71 {
72 warning ("Error: %s", err.message);
73@@ -122,6 +130,62 @@
74 }
75 }
76
77+ private async Preview? process_preview_request (string details_uri)
78+ {
79+ Json.Parser parser;
80+ try
81+ {
82+ parser = yield get_json_reply_async (details_uri, null);
83+ }
84+ catch (Error err)
85+ {
86+ return new GenericPreview (Path.get_basename (details_uri),
87+ err.message, null);
88+ }
89+
90+ if (U1MSPreviewFactory.is_u1ms_details (parser))
91+ {
92+ var u1mspf = new U1MSPreviewFactory ();
93+ var preview = u1mspf.create_preview (parser);
94+ u1mspf.add_download_action (preview); // download will be handled by normal activation
95+ if (player == null)
96+ player = new PreviewPlayerHandler ();
97+ player.music_preview = preview;
98+ return preview;
99+ }
100+ else
101+ {
102+ var root = parser.get_root ().get_object ();
103+ unowned string title = root.get_string_member ("title");
104+ unowned string description = root.get_string_member ("description_html");
105+
106+ unowned string price = null;
107+ if (root.has_member ("formatted_price"))
108+ price = root.get_string_member ("formatted_price");
109+ else if (root.has_member ("price"))
110+ price = root.get_string_member ("price");
111+
112+ var img_obj = root.get_object_member ("images");
113+ string image_uri = extract_image_uri (img_obj, int.MAX);
114+
115+ Icon? image = null;
116+ if (image_uri != "")
117+ {
118+ image = new FileIcon (File.new_for_uri (image_uri));
119+ }
120+
121+ var preview = new GenericPreview (title, MarkupCleaner.html_to_pango_markup (description), image);
122+ var icon_dir = File.new_for_path (ICON_PATH);
123+ var icon = new FileIcon (icon_dir.get_child ("service-amazon.svg"));
124+ var buy_action = new PreviewAction ("buy", _("Buy"), icon);
125+ if (price != null) buy_action.extra_text = price;
126+ /* Leaving the activation on unity for now */
127+ // buy_action.activated.connect ((uri) => { });
128+ preview.add_action (buy_action);
129+ return preview;
130+ }
131+ }
132+
133 private Preview? generate_preview_for_uri (string uri)
134 {
135 string? details_uri =
136@@ -133,52 +197,13 @@
137 "No data available", null);
138 }
139
140- try
141- {
142- var parser = get_json_reply (details_uri, null);
143-
144- if (U1MSPreviewFactory.is_u1ms_details (parser))
145- {
146- var u1mspf = new U1MSPreviewFactory ();
147- var preview = u1mspf.create_preview (parser);
148- u1mspf.add_download_action (preview); // download will be handled by normal activation
149- if (player == null)
150- player = new PreviewPlayerHandler ();
151- player.music_preview = preview;
152- return preview;
153- }
154- else
155- {
156- var root = parser.get_root ().get_object ();
157- unowned string title = root.get_string_member ("title");
158- unowned string description = root.get_string_member ("description_html");
159- unowned string price = root.get_string_member ("formatted_price");
160- if (price == null) price = root.get_string_member ("price");
161-
162- var img_obj = root.get_object_member ("images");
163- string image_uri = extract_image_uri (img_obj, int.MAX);
164-
165- Icon? image = null;
166- if (image_uri != "")
167- {
168- image = new FileIcon (File.new_for_uri (image_uri));
169- }
170-
171- var preview = new GenericPreview (title, MarkupCleaner.html_to_pango_markup (description), image);
172- var icon_dir = File.new_for_path (ICON_PATH);
173- var icon = new FileIcon (icon_dir.get_child ("service-amazon.svg"));
174- var buy_action = new PreviewAction ("buy", _("Buy"), icon);
175- if (price != null) buy_action.extra_text = price;
176- /* Leaving the activation on unity for now */
177- // buy_action.activated.connect ((uri) => { });
178- preview.add_action (buy_action);
179- return preview;
180- }
181- }
182- catch (Error err)
183- {
184- return new GenericPreview (Path.get_basename (uri), err.message, null);
185- }
186+ var preview = new AsyncPreview ();
187+ process_preview_request.begin (details_uri, (obj, res) =>
188+ {
189+ var real_preview = process_preview_request.end (res);
190+ preview.preview_ready (real_preview);
191+ });
192+ return preview;
193 }
194
195 private string build_search_uri (string query, SearchType search_type)
196@@ -199,29 +224,55 @@
197 }
198
199 private async Json.Parser get_json_reply_async (string uri,
200- Cancellable cancellable)
201+ Cancellable? cancellable)
202 throws Error
203 {
204 message ("Sending request: %s", uri);
205
206- var file = File.new_for_uri (uri);
207- var stream = yield file.read_async (Priority.DEFAULT, cancellable);
208- var parser = new Json.Parser ();
209- yield parser.load_from_stream_async (stream);
210-
211- return parser;
212- }
213-
214- private Json.Parser get_json_reply (string uri,
215- Cancellable? cancellable)
216- throws Error
217- {
218- message ("Sending sync request: %s", uri);
219-
220- var file = File.new_for_uri (uri);
221- var stream = file.read (cancellable);
222- var parser = new Json.Parser ();
223- parser.load_from_stream (stream);
224+ var msg = new Soup.Message ("GET", uri);
225+ session.queue_message (msg, (session_, msg_) =>
226+ {
227+ msg = msg_;
228+ get_json_reply_async.callback ();
229+ });
230+
231+ var cancelled = false;
232+ ulong cancel_id = 0;
233+ if (cancellable != null)
234+ {
235+ cancel_id = cancellable.connect (() =>
236+ {
237+ cancelled = true;
238+ session.cancel_message (msg, Soup.KnownStatusCode.CANCELLED);
239+ });
240+ }
241+
242+ yield;
243+
244+ if (cancelled)
245+ {
246+ // we can't disconnect right away, as that would deadlock (cause
247+ // cancel_message doesn't return before invoking the callback)
248+ Idle.add (get_json_reply_async.callback);
249+ yield;
250+ cancellable.disconnect (cancel_id);
251+ throw new IOError.CANCELLED ("Cancelled");
252+ }
253+
254+ if (msg.status_code < 100)
255+ {
256+ throw new IOError.FAILED ("Request failed with error %u", msg.status_code);
257+ }
258+ else if (msg.status_code != 200)
259+ {
260+ warning ("Request returned status code %u", msg.status_code);
261+ }
262+
263+ if (msg.response_body.data == null)
264+ throw new IOError.FAILED ("Request didn't return any content");
265+
266+ var parser = new Json.Parser ();
267+ parser.load_from_data ((string) msg.response_body.data);
268
269 return parser;
270 }
271@@ -308,8 +359,12 @@
272 var image_obj = result.get_object_member ("images");
273 string image_uri = extract_image_uri (image_obj, 128*128);
274
275- unowned string price = result.get_string_member ("formatted_price");
276- if (price == null) price = result.get_string_member ("price");
277+ unowned string price = null;
278+ if (result.has_member ("formatted_price"))
279+ price = result.get_string_member ("formatted_price");
280+ else if (result.has_member ("price"))
281+ price = result.get_string_member ("price");
282+
283 if (image_uri != "")
284 {
285 // TODO: what to do if we have price but no icon?
286
287=== added directory 'vapi'
288=== added file 'vapi/Makefile.am'
289--- vapi/Makefile.am 1970-01-01 00:00:00 +0000
290+++ vapi/Makefile.am 2012-09-26 11:13:24 +0000
291@@ -0,0 +1,5 @@
292+NULL =
293+BUILT_SOURCES =
294+CLEANFILES =
295+EXTRA_DIST = libsoup-gnome-2.4.vapi
296+
297
298=== added file 'vapi/libsoup-gnome-2.4.vapi'
299--- vapi/libsoup-gnome-2.4.vapi 1970-01-01 00:00:00 +0000
300+++ vapi/libsoup-gnome-2.4.vapi 2012-09-26 11:13:24 +0000
301@@ -0,0 +1,8 @@
302+[CCode (cprefix = "Soup", gir_namespace = "SoupGNOME", gir_version = "2.4", lower_case_cprefix = "soup_")]
303+namespace SoupGNOME {
304+ [CCode (cheader_filename = "libsoup/soup-gnome.h", type_id = "soup_proxy_resolver_gnome_get_type ()")]
305+ public class ProxyResolverGNOME : Soup.ProxyResolverDefault, Soup.ProxyURIResolver, Soup.SessionFeature {
306+ [CCode (has_construct_function = false)]
307+ protected ProxyResolverGNOME ();
308+ }
309+}

Subscribers

People subscribed via source and target branches

to all changes: