~ubuntu-branches/debian/squeeze/f-spot/squeeze

« back to all changes in this revision

Viewing changes to extensions/Exporters/TabbloExport/Tabblo/Connection.cs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane, Mirco Bauer, Iain Lane
  • Date: 2009-02-07 20:23:32 UTC
  • mfrom: (1.1.18 upstream)
  • Revision ID: james.westby@ubuntu.com-20090207202332-oc93rfjo1st0571s
Tags: 0.5.0.3-2
[ Mirco Bauer]
* Upload to unstable.
* debian/control:
  + Lowered GNOME# build-deps to 2.0 ABI as that transition didn't happen
    yet in unstable.

[ Iain Lane ]
* debian/patches/svn-r4545_locales-import.dpatch: Patch backported from SVN
  trunk revision 4545 - initialize the translation catalog earlier (LP: #293305)
  (Closes: #514457). Thanks to Florian Heinle for finding the patch and to
  Chris Coulson for preparing the update.
* debian/control: Build-depend on libmono-dev (>= 1.2.4) to match configure
  checks.
* debian/rules: Pass CSC=/usr/bin/csc to configure for gio-sharp to fix FTBFS

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Mono.Tabblo.Connection
 
3
//
 
4
// Authors:
 
5
//      Wojciech Dzierzanowski (wojciech.dzierzanowski@gmail.com)
 
6
//
 
7
// (C) Copyright 2008 Wojciech Dzierzanowski
 
8
//
 
9
 
 
10
// Permission is hereby granted, free of charge, to any person obtaining
 
11
// a copy of this software and associated documentation files (the
 
12
// "Software"), to deal in the Software without restriction, including
 
13
// without limitation the rights to use, copy, modify, merge, publish,
 
14
// distribute, sublicense, and/or sell copies of the Software, and to
 
15
// permit persons to whom the Software is furnished to do so, subject to
 
16
// the following conditions:
 
17
//
 
18
// The above copyright notice and this permission notice shall be
 
19
// included in all copies or substantial portions of the Software.
 
20
//
 
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
22
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
23
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
24
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
25
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
26
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
27
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
28
//
 
29
 
 
30
using Mono.Unix;
 
31
 
 
32
using System;
 
33
using System.Diagnostics;
 
34
using System.IO;
 
35
using System.Net;
 
36
using System.Text;
 
37
 
 
38
using FSpot.Utils;
 
39
 
 
40
namespace Mono.Tabblo {
 
41
 
 
42
        public class Connection {
 
43
 
 
44
                private const string LoginUrl =
 
45
                                "https://store.tabblo.com:443/studio/authtoken";
 
46
                private const string AuthorizeUrl = "https://store.tabblo.com"
 
47
                                + ":443/studio/upload/getposturl";
 
48
                private const string RedirUrl = "http://www.tabblo.com/studio"
 
49
                                + "/token/{0}/?url=/studio"
 
50
                                + "/report_upload_session";
 
51
 
 
52
                private readonly IPreferences preferences;
 
53
 
 
54
                private string auth_token = null;
 
55
                private string session_upload_url = null;
 
56
 
 
57
                private CookieCollection cookies;
 
58
 
 
59
 
 
60
                public Connection (IPreferences preferences)
 
61
                {
 
62
                        if (null == preferences) {
 
63
                                throw new ArgumentNullException ("preferences");
 
64
                        }
 
65
                        this.preferences = preferences;
 
66
                        this.cookies = new CookieCollection ();
 
67
                }
 
68
 
 
69
 
 
70
                public void UploadFile (string name, Stream data_stream,
 
71
                                        string mime_type, string [,] arguments)
 
72
                {
 
73
                        if (!IsAuthenticated ()) {
 
74
                                Login ();
 
75
                        }
 
76
 
 
77
                        Log.DebugFormat ("Uploading " + mime_type + " file " + name);
 
78
                        DoUploadFile (name, data_stream, mime_type, arguments);
 
79
                }
 
80
 
 
81
 
 
82
                private void DoUploadFile (string name, Stream data_stream,
 
83
                                           string mime_type,
 
84
                                           string [,] arguments)
 
85
                {
 
86
                        string upload_url = GetUploadUrl (arguments);
 
87
                        HttpWebRequest http_request = CreateHttpRequest (
 
88
                                        upload_url, "POST", true);
 
89
                        MultipartRequest request =
 
90
                                        new MultipartRequest (http_request);
 
91
 
 
92
                        MemoryStream mem_stream = null;
 
93
                        if (null != UploadProgressHandler) {
 
94
                                // "Manual buffering" using a MemoryStream.
 
95
                                request.Request.AllowWriteStreamBuffering =
 
96
                                                false;
 
97
                                mem_stream = new MemoryStream ();
 
98
                                request.OutputStream = mem_stream;
 
99
                        }
 
100
 
 
101
                        request.BeginPart (true);
 
102
                        request.AddHeader ("Content-Disposition",
 
103
                                        "form-data; name=\"filename0\"; "
 
104
                                                        + "filename=\"" + name
 
105
                                                        + '"',
 
106
                                        false);
 
107
                        request.AddHeader ("Content-Type", mime_type, true);
 
108
 
 
109
                        byte [] data_buffer = new byte [8192];
 
110
                        int read_count;
 
111
                        while ((read_count = data_stream.Read (
 
112
                                        data_buffer, 0, data_buffer.Length))
 
113
                                                        > 0) {
 
114
                                request.WritePartialContent (
 
115
                                                data_buffer, 0, read_count);
 
116
                        }
 
117
                        request.EndPartialContent ();
 
118
                        request.EndPart (true);
 
119
 
 
120
                        if (null != UploadProgressHandler) {
 
121
 
 
122
                                int total = (int) request.OutputStream.Length;
 
123
                                request.Request.ContentLength = total;
 
124
 
 
125
                                string progress_title = String.Format (
 
126
                                                Catalog.GetString ("Uploading "
 
127
                                                                + "photo "
 
128
                                                                + "\"{0}\""),
 
129
                                                name);
 
130
 
 
131
                                using (Stream request_stream = request.Request
 
132
                                                .GetRequestStream ()) {
 
133
                                        byte [] buffer =
 
134
                                                        mem_stream.GetBuffer ();
 
135
                                        int write_count = 0;
 
136
                                        for (int offset = 0; offset < total;
 
137
                                                        offset += write_count) {
 
138
                                                FireUploadProgress (
 
139
                                                                progress_title,
 
140
                                                                offset, total);
 
141
                                                write_count = System.Math.Min (
 
142
                                                                16384,
 
143
                                                                total - offset);
 
144
                                                request_stream.Write (buffer,
 
145
                                                                offset,
 
146
                                                                write_count);
 
147
                                        }
 
148
                                        FireUploadProgress (progress_title,
 
149
                                                        total, total);
 
150
                                }
 
151
                        }
 
152
 
 
153
                        SendRequest ("upload", request.Request, true);
 
154
                }
 
155
 
 
156
 
 
157
                public event UploadProgressEventHandler UploadProgressHandler;
 
158
 
 
159
                private void FireUploadProgress (string title, int sent,
 
160
                                                 int total)
 
161
                {
 
162
                        if (null != UploadProgressHandler) {
 
163
                                UploadProgressEventArgs args =
 
164
                                                new UploadProgressEventArgs (
 
165
                                                                title, sent,
 
166
                                                                total);
 
167
                                UploadProgressHandler (this, args);
 
168
                        }
 
169
                }
 
170
 
 
171
 
 
172
                private bool IsAuthenticated ()
 
173
                {
 
174
                        return null != auth_token;
 
175
                }
 
176
 
 
177
 
 
178
                private void Login ()
 
179
                {
 
180
                        FireUploadProgress (Catalog.GetString (
 
181
                                                "Logging into Tabblo"),
 
182
                                        0, 0);
 
183
 
 
184
                        auth_token = null;
 
185
 
 
186
                        HttpWebRequest request = CreateHttpRequest (
 
187
                                        LoginUrl, "POST");
 
188
                        request.ContentType =
 
189
                                        "application/x-www-form-urlencoded";
 
190
 
 
191
                        string [,] arguments = {
 
192
                                {"username", preferences.Username},
 
193
                                {"password", preferences.Password}
 
194
                        };
 
195
 
 
196
                        try {
 
197
                                WriteRequestContent (request,
 
198
                                                FormatRequestArguments (
 
199
                                                                arguments));
 
200
                                string response = SendRequest (
 
201
                                                "login", request);
 
202
                                if ("BAD".Equals (response)) {
 
203
                                        Log.DebugFormat ("Invalid username or password");
 
204
                                        throw new TabbloException (
 
205
                                                "Login failed: Invalid username"
 
206
                                                + " or password");
 
207
                                }
 
208
 
 
209
                                auth_token = response;
 
210
 
 
211
                        } catch (TabbloException e) {
 
212
                                // Here's us trying to produce a more
 
213
                                // descriptive message when we have... trust
 
214
                                // issues.  This doesn't work, though, at least
 
215
                                // as long as Mono bug #346635 is not fixed.
 
216
                                //
 
217
                                // TODO: When it _starts_ to work, we should
 
218
                                // think about doing the same for
 
219
                                // `GetUploadUrl()'.
 
220
                                WebException we = e.InnerException
 
221
                                                as WebException;
 
222
                                if (null != we)
 
223
                                        Log.DebugFormat ("Caught a WebException, status=" + we.Status);
 
224
                                if (null != we
 
225
                                        && WebExceptionStatus.TrustFailure
 
226
                                                        == we.Status) {
 
227
                                        throw new TabbloException (
 
228
                                                        "Trust failure", we);
 
229
                                }
 
230
                                throw;
 
231
                        }
 
232
 
 
233
                        if  (null != auth_token)
 
234
                                Log.DebugFormat  ("Login successful. Token: " + auth_token);
 
235
                }
 
236
 
 
237
 
 
238
                private string GetUploadUrl (string [,] arguments)
 
239
                {
 
240
                        FireUploadProgress (Catalog.GetString (
 
241
                                                "Obtaining URL for upload"),
 
242
                                        0, 0);
 
243
 
 
244
                        if (! IsAuthenticated ())
 
245
                                Log.DebugFormat ("Not authenticated");
 
246
 
 
247
                        if (null == session_upload_url) {
 
248
 
 
249
                                string [,] auth_arguments =
 
250
                                                { {"auth_token", auth_token} };
 
251
                                string url = AuthorizeUrl + "/?"
 
252
                                                + FormatRequestArguments (
 
253
                                                                auth_arguments);
 
254
 
 
255
                                HttpWebRequest request =
 
256
                                                CreateHttpRequest (url, "GET");
 
257
 
 
258
                                string response = SendRequest (
 
259
                                                "getposturl", request);
 
260
 
 
261
                                if (response.StartsWith ("@")) {
 
262
                                        session_upload_url =
 
263
                                                        response.Substring (1);
 
264
                                } else {
 
265
                                        throw new TabbloException (
 
266
                                                        "Session upload URL "
 
267
                                                        + "retrieval failed");
 
268
                                }
 
269
                        }
 
270
 
 
271
                        string upload_url = session_upload_url;
 
272
                        upload_url += "&redir=" + String.Format (
 
273
                                        RedirUrl, auth_token);
 
274
                        if (null != arguments && arguments.GetLength (0) > 0) {
 
275
                                upload_url += '&' + FormatRequestArguments (
 
276
                                                arguments);
 
277
                        }
 
278
 
 
279
                        Log.DebugFormat ("Upload URL: " + upload_url);
 
280
                        return upload_url;
 
281
                }
 
282
 
 
283
 
 
284
                private HttpWebRequest CreateHttpRequest (string url,
 
285
                                                          string method)
 
286
                {
 
287
                        return CreateHttpRequest (url, method, false);
 
288
                }
 
289
 
 
290
                private HttpWebRequest CreateHttpRequest (string url,
 
291
                                                          string method,
 
292
                                                          bool with_cookies)
 
293
                {
 
294
                        HttpWebRequest request = (HttpWebRequest)
 
295
                                        WebRequest.Create (url);
 
296
                        // For some reason, POST requests are _really_ slow with
 
297
                        // HTTP 1.1.
 
298
                        request.ProtocolVersion = HttpVersion.Version10;
 
299
                        request.Method = method;
 
300
                        if (with_cookies) {
 
301
                                HandleRequestCookies (request);
 
302
                        }
 
303
                        return request;
 
304
                }
 
305
 
 
306
 
 
307
                private void HandleRequestCookies (HttpWebRequest request)
 
308
                {
 
309
                        request.CookieContainer = new CookieContainer ();
 
310
                        // Instead of just doing a
 
311
                        // `request.CookieContainer.Add(cookies)', add cookies
 
312
                        // mannually to work around the fact that some cookies
 
313
                        // are not properly formatted as they are received from
 
314
                        // the server.
 
315
                        foreach (Cookie c in cookies) {
 
316
                                Cookie new_cookie = new Cookie (c.Name, c.Value,
 
317
                                                "/", ".tabblo.com");
 
318
                                request.CookieContainer.Add (new_cookie);
 
319
                        }
 
320
 
 
321
                        string cookie_header = request.CookieContainer
 
322
                                        .GetCookieHeader (request.RequestUri);
 
323
                        if (cookie_header.Length > 0)
 
324
                                Log.DebugFormat ("Cookie: " + cookie_header);
 
325
                }
 
326
 
 
327
 
 
328
                private static void WriteRequestContent (HttpWebRequest request,
 
329
                                                         string content)
 
330
                {
 
331
                        byte [] content_bytes =
 
332
                                        Encoding.UTF8.GetBytes (content);
 
333
 
 
334
                        request.ContentLength = content_bytes.Length;
 
335
 
 
336
                        try {
 
337
                                using (Stream request_stream =
 
338
                                                request.GetRequestStream ()) {
 
339
                                        request_stream.Write (content_bytes, 0,
 
340
                                                        content_bytes.Length);
 
341
                                }
 
342
                        } catch (WebException e) {
 
343
                                Log.Exception (e);
 
344
                                throw new TabbloException (
 
345
                                                "HTTP request failure: "
 
346
                                                                + e.Message,
 
347
                                                e);
 
348
                        }
 
349
 
 
350
                        char [] content_chars = new char [content_bytes.Length];
 
351
                        content_bytes.CopyTo (content_chars, 0);
 
352
                        Log.DebugFormat ("Request content: " + new string (content_chars));
 
353
                }
 
354
 
 
355
 
 
356
                private static string FormatRequestArguments (
 
357
                                string [,] arguments)
 
358
                {
 
359
                        StringBuilder content = new StringBuilder ();
 
360
 
 
361
                        for (int i = 0; i < arguments.GetLength (0); ++i) {
 
362
                                content.AppendFormat( "{0}={1}&",
 
363
                                                arguments [i, 0],
 
364
                                                arguments [i, 1]);
 
365
                        }
 
366
 
 
367
                        if (content.Length > 0) {
 
368
                                content.Remove (content.Length - 1, 1);
 
369
                        }
 
370
 
 
371
                        byte [] content_bytes = Encoding.UTF8.GetBytes (
 
372
                                        content.ToString ());
 
373
                        char [] content_chars = new char [content_bytes.Length];
 
374
                        content_bytes.CopyTo (content_chars, 0);
 
375
 
 
376
                        return new string (content_chars);
 
377
                }
 
378
 
 
379
 
 
380
                private string SendRequest (string description,
 
381
                                            HttpWebRequest request)
 
382
                {
 
383
                        return SendRequest (description, request, false);
 
384
                }
 
385
 
 
386
                /// <summary>
 
387
                /// Sends an HTTP request.
 
388
                /// </summary>
 
389
                /// <param name="description"></param>
 
390
                /// <param name="request"></param>
 
391
                /// <returns>the HTTP response as string</returns>
 
392
                private string SendRequest (string description,
 
393
                                            HttpWebRequest request,
 
394
                                            bool keep_cookies)
 
395
                {
 
396
                        Log.DebugFormat ("Sending " + description + ' ' + request.Method + " request to " + request.Address);
 
397
 
 
398
                        HttpWebResponse response = null;
 
399
                        try {
 
400
                                response = (HttpWebResponse)
 
401
                                                request.GetResponse ();
 
402
                                if (keep_cookies) {
 
403
                                        cookies.Add (response.Cookies);
 
404
                                        Log.DebugFormat (response.Cookies.Count + " cookie(s)");
 
405
                                        foreach (Cookie c in response.Cookies) {
 
406
                                                Log.DebugFormat ("Set-Cookie: " + c.Name + '=' + c.Value + "; Domain=" + c.Domain + "; expires=" + c.Expires);
 
407
                                        }
 
408
                                }
 
409
                                return GetResponseAsString (response);
 
410
                        } catch (WebException e) {
 
411
                                Log.Exception (e);
 
412
                                HttpWebResponse error_response =
 
413
                                                e.Response as HttpWebResponse;
 
414
                                string response_string = null != error_response
 
415
                                                ? GetResponseAsString (
 
416
                                                                error_response)
 
417
                                                : "reason unknown";
 
418
                                throw new TabbloException (description
 
419
                                                        + " failed: "
 
420
                                                        + response_string,
 
421
                                                e);
 
422
                        } finally {
 
423
                                if (null != response) {
 
424
                                        response.Close ();
 
425
                                }
 
426
                        }
 
427
                }
 
428
 
 
429
 
 
430
                private static string GetResponseAsString (HttpWebResponse response)
 
431
                {
 
432
                        Log.DebugFormat ("Response: ");
 
433
 
 
434
                        Encoding encoding = Encoding.UTF8;
 
435
                        if (response.ContentEncoding.Length > 0) {
 
436
                                try {
 
437
                                        encoding = Encoding.GetEncoding (
 
438
                                                        response
 
439
                                                        .ContentEncoding);
 
440
                                } catch (ArgumentException) {
 
441
                                        // Swallow invalid encoding exception
 
442
                                        // and use the default one.
 
443
                                }
 
444
                        }
 
445
 
 
446
                        string response_string = null;
 
447
 
 
448
                        using (Stream stream = response.GetResponseStream ()) {
 
449
                                StreamReader reader = new StreamReader (
 
450
                                                stream, encoding);
 
451
                                response_string = reader.ReadToEnd ();
 
452
                                stream.Close ();
 
453
                        }
 
454
 
 
455
                        if (null != response_string)
 
456
                                try {
 
457
                                        Log.DebugFormat (response_string);
 
458
                                } catch (System.FormatException e) {
 
459
                                        Log.DebugFormat ("Unable to print respose string: not in correct format");
 
460
                                }
 
461
                        return response_string;
 
462
                }
 
463
        }
 
464
}