s33r 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/bin/s3cli.rb +25 -16
  2. data/html/classes/MIME.html +120 -0
  3. data/html/classes/MIME/InvalidContentType.html +119 -0
  4. data/html/classes/MIME/Type.html +1173 -0
  5. data/html/classes/MIME/Types.html +566 -0
  6. data/html/classes/Net.html +108 -0
  7. data/html/classes/Net/HTTPGenericRequest.html +233 -0
  8. data/html/classes/Net/HTTPResponse.html +242 -0
  9. data/html/classes/S33r.html +743 -0
  10. data/html/classes/S33r/BucketListing.html +372 -0
  11. data/html/classes/S33r/Client.html +981 -0
  12. data/html/classes/S33r/NamedBucket.html +620 -0
  13. data/html/classes/S33r/S33rException.html +118 -0
  14. data/html/classes/S33r/S33rException/BucketListingMaxKeysError.html +111 -0
  15. data/html/classes/S33r/S33rException/InvalidBucketListing.html +111 -0
  16. data/html/classes/S33r/S33rException/MalformedBucketName.html +111 -0
  17. data/html/classes/S33r/S33rException/MethodNotAvailable.html +111 -0
  18. data/html/classes/S33r/S33rException/MissingRequiredHeaders.html +111 -0
  19. data/html/classes/S33r/S33rException/MissingResource.html +111 -0
  20. data/html/classes/S33r/S33rException/UnsupportedCannedACL.html +111 -0
  21. data/html/classes/S33r/S33rException/UnsupportedHTTPMethod.html +111 -0
  22. data/html/classes/S33r/S3Object.html +307 -0
  23. data/html/classes/S33r/S3User.html +171 -0
  24. data/html/classes/S33r/Sync.html +151 -0
  25. data/html/classes/XML.html +200 -0
  26. data/html/classes/XML/Document.html +125 -0
  27. data/html/classes/XML/Node.html +124 -0
  28. data/html/created.rid +1 -0
  29. data/html/files/CHANGELOG.html +101 -0
  30. data/html/files/MIT-LICENSE.html +129 -0
  31. data/html/files/README_txt.html +209 -0
  32. data/html/files/lib/s33r/bucket_listing_rb.html +116 -0
  33. data/html/files/lib/s33r/client_rb.html +110 -0
  34. data/html/files/lib/s33r/core_rb.html +113 -0
  35. data/html/files/lib/s33r/libxml_extensions_rb.html +107 -0
  36. data/html/files/lib/s33r/mimetypes_rb.html +120 -0
  37. data/html/files/lib/s33r/named_bucket_rb.html +101 -0
  38. data/html/files/lib/s33r/s33r_exception_rb.html +101 -0
  39. data/html/files/lib/s33r/s33r_http_rb.html +108 -0
  40. data/html/files/lib/s33r/sync_rb.html +101 -0
  41. data/html/files/lib/s33r_rb.html +101 -0
  42. data/html/fr_class_index.html +52 -0
  43. data/html/fr_file_index.html +39 -0
  44. data/html/fr_method_index.html +126 -0
  45. data/html/index.html +24 -0
  46. data/html/rdoc-style.css +208 -0
  47. data/lib/s33r/bucket_listing.rb +69 -60
  48. data/lib/s33r/client.rb +150 -73
  49. data/lib/s33r/core.rb +56 -44
  50. data/lib/s33r/libxml_extensions.rb +10 -5
  51. data/lib/s33r/mimetypes.rb +3 -2
  52. data/lib/s33r/named_bucket.rb +89 -24
  53. data/lib/s33r/{s3_exception.rb → s33r_exception.rb} +2 -2
  54. data/lib/s33r/{net_http_overrides.rb → s33r_http.rb} +29 -21
  55. data/lib/s33r/sync.rb +4 -2
  56. data/test/cases/spec_bucket_listing.rb +10 -13
  57. data/test/cases/spec_client.rb +65 -0
  58. data/test/cases/spec_core.rb +16 -11
  59. data/test/cases/spec_namedbucket.rb +32 -0
  60. data/test/cases/spec_sync.rb +6 -5
  61. data/test/cases/spec_xml.rb +1 -1
  62. data/test/files/client_config.yml +6 -0
  63. data/test/files/namedbucket_config.yml +12 -0
  64. data/test/{s3_test_constants.rb → test_setup.rb} +7 -6
  65. metadata +63 -11
  66. data/LICENSE.txt +0 -22
  67. data/MIT-LICENSE +0 -21
  68. data/README.txt +0 -19
  69. data/bin/config.yml +0 -5
  70. data/test/cases/unit_client.rb +0 -40
  71. data/test/cases/unit_named_bucket.rb +0 -12
@@ -0,0 +1,743 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Module: S33r</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="classHeader">
50
+ <table class="header-table">
51
+ <tr class="top-aligned-row">
52
+ <td><strong>Module</strong></td>
53
+ <td class="class-name-in-header">S33r</td>
54
+ </tr>
55
+ <tr class="top-aligned-row">
56
+ <td><strong>In:</strong></td>
57
+ <td>
58
+ <a href="../files/lib/s33r/sync_rb.html">
59
+ lib/s33r/sync.rb
60
+ </a>
61
+ <br />
62
+ <a href="../files/lib/s33r/client_rb.html">
63
+ lib/s33r/client.rb
64
+ </a>
65
+ <br />
66
+ <a href="../files/lib/s33r/bucket_listing_rb.html">
67
+ lib/s33r/bucket_listing.rb
68
+ </a>
69
+ <br />
70
+ <a href="../files/lib/s33r/core_rb.html">
71
+ lib/s33r/core.rb
72
+ </a>
73
+ <br />
74
+ <a href="../files/lib/s33r/named_bucket_rb.html">
75
+ lib/s33r/named_bucket.rb
76
+ </a>
77
+ <br />
78
+ <a href="../files/lib/s33r/s33r_exception_rb.html">
79
+ lib/s33r/s33r_exception.rb
80
+ </a>
81
+ <br />
82
+ </td>
83
+ </tr>
84
+
85
+ </table>
86
+ </div>
87
+ <!-- banner header -->
88
+
89
+ <div id="bodyContent">
90
+
91
+
92
+
93
+ <div id="contextContent">
94
+
95
+ <div id="description">
96
+ <p>
97
+ Module to handle S3 operations which don&#8217;t require an internet
98
+ connection, i.e. data validation and request-building operations; also
99
+ holds all the constants relating to S3.
100
+ </p>
101
+ <p>
102
+ Parts of this code are heavily based on Amazon&#8217;s code. Here&#8217;s
103
+ their license:
104
+ </p>
105
+ <pre>
106
+ This software code is made available &quot;AS IS&quot; without warranties of any
107
+ kind. You may copy, display, modify and redistribute the software
108
+ code either by itself or as incorporated into your code; provided that
109
+ you do not remove any proprietary notices. Your use of this software
110
+ code is at your own risk and you waive any claim against Amazon
111
+ Digital Services, Inc. or its affiliates with respect to your use of
112
+ this software code. (c) 2006 Amazon Digital Services, Inc. or its
113
+ affiliates.
114
+ </pre>
115
+
116
+ </div>
117
+
118
+
119
+ </div>
120
+
121
+ <div id="method-list">
122
+ <h3 class="section-bar">Methods</h3>
123
+
124
+ <div class="name-list">
125
+ <a href="#M000043">add_default_headers</a>&nbsp;&nbsp;
126
+ <a href="#M000047">bucket_name_valid?</a>&nbsp;&nbsp;
127
+ <a href="#M000045">canned_acl_header</a>&nbsp;&nbsp;
128
+ <a href="#M000041">generate_auth_header_value</a>&nbsp;&nbsp;
129
+ <a href="#M000040">generate_canonical_string</a>&nbsp;&nbsp;
130
+ <a href="#M000048">generate_querystring</a>&nbsp;&nbsp;
131
+ <a href="#M000042">generate_signature</a>&nbsp;&nbsp;
132
+ <a href="#M000046">guess_mime_type</a>&nbsp;&nbsp;
133
+ <a href="#M000052">keys_to_symbols</a>&nbsp;&nbsp;
134
+ <a href="#M000044">metadata_headers</a>&nbsp;&nbsp;
135
+ <a href="#M000051">s3_authenticated_url</a>&nbsp;&nbsp;
136
+ <a href="#M000050">s3_public_url</a>&nbsp;&nbsp;
137
+ <a href="#M000049">url_join</a>&nbsp;&nbsp;
138
+ </div>
139
+ </div>
140
+
141
+ </div>
142
+
143
+
144
+ <!-- if includes -->
145
+ <div id="includes">
146
+ <h3 class="section-bar">Included Modules</h3>
147
+
148
+ <div id="includes-list">
149
+ <span class="include-name"><a href="Net.html">Net</a></span>
150
+ </div>
151
+ </div>
152
+
153
+ <div id="section">
154
+
155
+ <div id="class-list">
156
+ <h3 class="section-bar">Classes and Modules</h3>
157
+
158
+ Module <a href="S33r/S33rException.html" class="link">S33r::S33rException</a><br />
159
+ Module <a href="S33r/Sync.html" class="link">S33r::Sync</a><br />
160
+ Class <a href="S33r/BucketListing.html" class="link">S33r::BucketListing</a><br />
161
+ Class <a href="S33r/Client.html" class="link">S33r::Client</a><br />
162
+ Class <a href="S33r/NamedBucket.html" class="link">S33r::NamedBucket</a><br />
163
+ Class <a href="S33r/S3Object.html" class="link">S33r::S3Object</a><br />
164
+ Class <a href="S33r/S3User.html" class="link">S33r::S3User</a><br />
165
+
166
+ </div>
167
+
168
+ <div id="constants-list">
169
+ <h3 class="section-bar">Constants</h3>
170
+
171
+ <div class="name-list">
172
+ <table summary="Constants">
173
+ <tr class="top-aligned-row context-row">
174
+ <td class="context-item-name">HOST</td>
175
+ <td>=</td>
176
+ <td class="context-item-value">'s3.amazonaws.com'</td>
177
+ </tr>
178
+ <tr class="top-aligned-row context-row">
179
+ <td class="context-item-name">PORT</td>
180
+ <td>=</td>
181
+ <td class="context-item-value">443</td>
182
+ </tr>
183
+ <tr class="top-aligned-row context-row">
184
+ <td class="context-item-name">NON_SSL_PORT</td>
185
+ <td>=</td>
186
+ <td class="context-item-value">80</td>
187
+ </tr>
188
+ <tr class="top-aligned-row context-row">
189
+ <td class="context-item-name">METADATA_PREFIX</td>
190
+ <td>=</td>
191
+ <td class="context-item-value">'x-amz-meta-'</td>
192
+ </tr>
193
+ <tr class="top-aligned-row context-row">
194
+ <td class="context-item-name">DEFAULT_CHUNK_SIZE</td>
195
+ <td>=</td>
196
+ <td class="context-item-value">1048576</td>
197
+ <td width="3em">&nbsp;</td>
198
+ <td class="context-item-desc">
199
+ Size of each chunk (in bytes) to be sent per request when putting files.
200
+
201
+ </td>
202
+ </tr>
203
+ <tr class="top-aligned-row context-row">
204
+ <td class="context-item-name">AWS_HEADER_PREFIX</td>
205
+ <td>=</td>
206
+ <td class="context-item-value">'x-amz-'</td>
207
+ </tr>
208
+ <tr class="top-aligned-row context-row">
209
+ <td class="context-item-name">AWS_AUTH_HEADER_VALUE</td>
210
+ <td>=</td>
211
+ <td class="context-item-value">&quot;AWS %s:%s&quot;</td>
212
+ </tr>
213
+ <tr class="top-aligned-row context-row">
214
+ <td class="context-item-name">INTERESTING_HEADERS</td>
215
+ <td>=</td>
216
+ <td class="context-item-value">['content-md5', 'content-type', 'date']</td>
217
+ </tr>
218
+ <tr class="top-aligned-row context-row">
219
+ <td class="context-item-name">REQUIRED_HEADERS</td>
220
+ <td>=</td>
221
+ <td class="context-item-value">['Content-Type', 'Date']</td>
222
+ <td width="3em">&nbsp;</td>
223
+ <td class="context-item-desc">
224
+ Headers which must be included with every request to S3.
225
+
226
+ </td>
227
+ </tr>
228
+ <tr class="top-aligned-row context-row">
229
+ <td class="context-item-name">CANNED_ACLS</td>
230
+ <td>=</td>
231
+ <td class="context-item-value">['private', 'public-read', 'public-read-write', 'authenticated-read']</td>
232
+ </tr>
233
+ <tr class="top-aligned-row context-row">
234
+ <td class="context-item-name">METHOD_VERBS</td>
235
+ <td>=</td>
236
+ <td class="context-item-value">['GET', 'PUT', 'HEAD', 'POST', 'DELETE']</td>
237
+ <td width="3em">&nbsp;</td>
238
+ <td class="context-item-desc">
239
+ HTTP methods which S3 will respond to.
240
+
241
+ </td>
242
+ </tr>
243
+ <tr class="top-aligned-row context-row">
244
+ <td class="context-item-name">BUCKET_LIST_MAX_MAX_KEYS</td>
245
+ <td>=</td>
246
+ <td class="context-item-value">1000</td>
247
+ <td width="3em">&nbsp;</td>
248
+ <td class="context-item-desc">
249
+ Maximum number which can be passed in max-keys parameter when GETting
250
+ bucket list.
251
+
252
+ </td>
253
+ </tr>
254
+ <tr class="top-aligned-row context-row">
255
+ <td class="context-item-name">DEFAULT_EXPIRY_SECS</td>
256
+ <td>=</td>
257
+ <td class="context-item-value">60 * 15</td>
258
+ <td width="3em">&nbsp;</td>
259
+ <td class="context-item-desc">
260
+ Default number of seconds an authenticated URL will last for (15 minutes).
261
+
262
+ </td>
263
+ </tr>
264
+ </table>
265
+ </div>
266
+ </div>
267
+
268
+
269
+
270
+
271
+
272
+
273
+ <!-- if method_list -->
274
+ <div id="methods">
275
+ <h3 class="section-bar">Public Class methods</h3>
276
+
277
+ <div id="method-M000052" class="method-detail">
278
+ <a name="M000052"></a>
279
+
280
+ <div class="method-heading">
281
+ <a href="#M000052" class="method-signature">
282
+ <span class="method-name">keys_to_symbols</span><span class="method-args">(hsh)</span>
283
+ </a>
284
+ </div>
285
+
286
+ <div class="method-description">
287
+ <p>
288
+ Turn keys in a hash hsh into symbols. Returns a hash with
289
+ &#8216;symbolised&#8217; keys.
290
+ </p>
291
+ <p><a class="source-toggle" href="#"
292
+ onclick="toggleCode('M000052-source');return false;">[Source]</a></p>
293
+ <div class="method-source-code" id="M000052-source">
294
+ <pre>
295
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 215</span>
296
+ 215: <span class="ruby-keyword kw">def</span> <span class="ruby-constant">S33r</span>.<span class="ruby-identifier">keys_to_symbols</span>(<span class="ruby-identifier">hsh</span>)
297
+ 216: <span class="ruby-identifier">symbolised</span> = <span class="ruby-identifier">hsh</span>.<span class="ruby-identifier">inject</span>({}) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">symbolised</span>, <span class="ruby-identifier">key_value</span><span class="ruby-operator">|</span>
298
+ 217: <span class="ruby-identifier">symbolised</span>.<span class="ruby-identifier">merge</span>({<span class="ruby-identifier">key_value</span>[<span class="ruby-value">0</span>].<span class="ruby-identifier">to_sym</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">key_value</span>[<span class="ruby-value">1</span>]})
299
+ 218: <span class="ruby-keyword kw">end</span>
300
+ 219: <span class="ruby-identifier">symbolised</span>
301
+ 220: <span class="ruby-keyword kw">end</span>
302
+ </pre>
303
+ </div>
304
+ </div>
305
+ </div>
306
+
307
+ <h3 class="section-bar">Public Instance methods</h3>
308
+
309
+ <div id="method-M000043" class="method-detail">
310
+ <a name="M000043"></a>
311
+
312
+ <div class="method-heading">
313
+ <a href="#M000043" class="method-signature">
314
+ <span class="method-name">add_default_headers</span><span class="method-args">(headers, options={})</span>
315
+ </a>
316
+ </div>
317
+
318
+ <div class="method-description">
319
+ <p>
320
+ Build the headers required with every S3 request (Date and Content-Type);
321
+ options hash can contain extra header settings, as follows: :date and
322
+ :content_type are required headers, and set to defaults if not supplied
323
+ </p>
324
+ <p><a class="source-toggle" href="#"
325
+ onclick="toggleCode('M000043-source');return false;">[Source]</a></p>
326
+ <div class="method-source-code" id="M000043-source">
327
+ <pre>
328
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 111</span>
329
+ 111: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">add_default_headers</span>(<span class="ruby-identifier">headers</span>, <span class="ruby-identifier">options</span>={})
330
+ 112: <span class="ruby-comment cmt"># set the default headers required by AWS</span>
331
+ 113: <span class="ruby-identifier">missing_headers</span> = <span class="ruby-constant">REQUIRED_HEADERS</span> <span class="ruby-operator">-</span> <span class="ruby-identifier">headers</span>.<span class="ruby-identifier">keys</span>
332
+ 114:
333
+ 115: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">missing_headers</span>.<span class="ruby-identifier">include?</span>(<span class="ruby-value str">'Content-Type'</span>)
334
+ 116: <span class="ruby-identifier">headers</span>[<span class="ruby-value str">'Content-Type'</span>] = <span class="ruby-identifier">options</span>[<span class="ruby-identifier">:content_type</span>] <span class="ruby-operator">||</span> <span class="ruby-value str">''</span>
335
+ 117: <span class="ruby-keyword kw">end</span>
336
+ 118:
337
+ 119: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">missing_headers</span>.<span class="ruby-identifier">include?</span>(<span class="ruby-value str">'Date'</span>)
338
+ 120: <span class="ruby-identifier">date</span> = <span class="ruby-identifier">options</span>[<span class="ruby-identifier">:date</span>] <span class="ruby-operator">||</span> <span class="ruby-constant">Time</span>.<span class="ruby-identifier">now</span>
339
+ 121: <span class="ruby-identifier">headers</span>[<span class="ruby-value str">'Date'</span>] = <span class="ruby-identifier">date</span>.<span class="ruby-identifier">httpdate</span>
340
+ 122: <span class="ruby-keyword kw">end</span>
341
+ 123:
342
+ 124: <span class="ruby-identifier">headers</span>
343
+ 125: <span class="ruby-keyword kw">end</span>
344
+ </pre>
345
+ </div>
346
+ </div>
347
+ </div>
348
+
349
+ <div id="method-M000047" class="method-detail">
350
+ <a name="M000047"></a>
351
+
352
+ <div class="method-heading">
353
+ <a href="#M000047" class="method-signature">
354
+ <span class="method-name">bucket_name_valid?</span><span class="method-args">(bucket_name)</span>
355
+ </a>
356
+ </div>
357
+
358
+ <div class="method-description">
359
+ <p>
360
+ Ensure that a bucket_name is well-formed (no leading or trailing slash).
361
+ </p>
362
+ <p><a class="source-toggle" href="#"
363
+ onclick="toggleCode('M000047-source');return false;">[Source]</a></p>
364
+ <div class="method-source-code" id="M000047-source">
365
+ <pre>
366
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 156</span>
367
+ 156: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">bucket_name_valid?</span>(<span class="ruby-identifier">bucket_name</span>)
368
+ 157: <span class="ruby-keyword kw">if</span> (<span class="ruby-value str">'/'</span> <span class="ruby-operator">==</span> <span class="ruby-identifier">bucket_name</span>[<span class="ruby-value">0</span>,<span class="ruby-value">1</span>] <span class="ruby-operator">||</span> <span class="ruby-value str">'/'</span> <span class="ruby-operator">==</span> <span class="ruby-identifier">bucket_name</span>[<span class="ruby-value">-1</span>,<span class="ruby-value">1</span>])
369
+ 158: <span class="ruby-identifier">raise</span> <span class="ruby-constant">S33rException</span><span class="ruby-operator">::</span><span class="ruby-constant">MalformedBucketName</span>, <span class="ruby-value str">&quot;Bucket name cannot have a leading or trailing slash&quot;</span>
370
+ 159: <span class="ruby-keyword kw">end</span>
371
+ 160: <span class="ruby-keyword kw">end</span>
372
+ </pre>
373
+ </div>
374
+ </div>
375
+ </div>
376
+
377
+ <div id="method-M000045" class="method-detail">
378
+ <a name="M000045"></a>
379
+
380
+ <div class="method-heading">
381
+ <a href="#M000045" class="method-signature">
382
+ <span class="method-name">canned_acl_header</span><span class="method-args">(canned_acl, headers={})</span>
383
+ </a>
384
+ </div>
385
+
386
+ <div class="method-description">
387
+ <p>
388
+ Add a canned ACL setter header.
389
+ </p>
390
+ <p><a class="source-toggle" href="#"
391
+ onclick="toggleCode('M000045-source');return false;">[Source]</a></p>
392
+ <div class="method-source-code" id="M000045-source">
393
+ <pre>
394
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 137</span>
395
+ 137: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">canned_acl_header</span>(<span class="ruby-identifier">canned_acl</span>, <span class="ruby-identifier">headers</span>={})
396
+ 138: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">canned_acl</span>.<span class="ruby-identifier">nil?</span>
397
+ 139: <span class="ruby-keyword kw">unless</span> <span class="ruby-constant">CANNED_ACLS</span>.<span class="ruby-identifier">include?</span>(<span class="ruby-identifier">canned_acl</span>)
398
+ 140: <span class="ruby-identifier">raise</span> <span class="ruby-constant">S33rException</span><span class="ruby-operator">::</span><span class="ruby-constant">UnsupportedCannedACL</span>, <span class="ruby-node">&quot;The canned ACL #{canned_acl} is not supported&quot;</span>
399
+ 141: <span class="ruby-keyword kw">end</span>
400
+ 142: <span class="ruby-identifier">headers</span>[<span class="ruby-constant">AWS_HEADER_PREFIX</span> <span class="ruby-operator">+</span> <span class="ruby-value str">'acl'</span>] = <span class="ruby-identifier">canned_acl</span>
401
+ 143: <span class="ruby-keyword kw">end</span>
402
+ 144: <span class="ruby-identifier">headers</span>
403
+ 145: <span class="ruby-keyword kw">end</span>
404
+ </pre>
405
+ </div>
406
+ </div>
407
+ </div>
408
+
409
+ <div id="method-M000041" class="method-detail">
410
+ <a name="M000041"></a>
411
+
412
+ <div class="method-heading">
413
+ <a href="#M000041" class="method-signature">
414
+ <span class="method-name">generate_auth_header_value</span><span class="method-args">(method, path, headers, aws_access_key, aws_secret_access_key)</span>
415
+ </a>
416
+ </div>
417
+
418
+ <div class="method-description">
419
+ <p>
420
+ Get the value for the AWS authentication header.
421
+ </p>
422
+ <p><a class="source-toggle" href="#"
423
+ onclick="toggleCode('M000041-source');return false;">[Source]</a></p>
424
+ <div class="method-source-code" id="M000041-source">
425
+ <pre>
426
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 85</span>
427
+ 85: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">generate_auth_header_value</span>(<span class="ruby-identifier">method</span>, <span class="ruby-identifier">path</span>, <span class="ruby-identifier">headers</span>, <span class="ruby-identifier">aws_access_key</span>, <span class="ruby-identifier">aws_secret_access_key</span>)
428
+ 86: <span class="ruby-identifier">raise</span> <span class="ruby-constant">S33rException</span><span class="ruby-operator">::</span><span class="ruby-constant">MethodNotAvailable</span>, <span class="ruby-value str">&quot;Method %s not available&quot;</span> <span class="ruby-operator">%</span> <span class="ruby-identifier">method</span> <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span><span class="ruby-constant">METHOD_VERBS</span>.<span class="ruby-identifier">include?</span>(<span class="ruby-identifier">method</span>)
429
+ 87:
430
+ 88: <span class="ruby-comment cmt"># check the headers needed for authentication have been set</span>
431
+ 89: <span class="ruby-identifier">missing_headers</span> = <span class="ruby-constant">REQUIRED_HEADERS</span> <span class="ruby-operator">-</span> <span class="ruby-identifier">headers</span>.<span class="ruby-identifier">keys</span>
432
+ 90: <span class="ruby-keyword kw">if</span> <span class="ruby-operator">!</span>(<span class="ruby-identifier">missing_headers</span>.<span class="ruby-identifier">empty?</span>)
433
+ 91: <span class="ruby-identifier">raise</span> <span class="ruby-constant">S33rException</span><span class="ruby-operator">::</span><span class="ruby-constant">MissingRequiredHeaders</span>,
434
+ 92: <span class="ruby-value str">&quot;Headers required for AWS auth value are missing: &quot;</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">missing_headers</span>.<span class="ruby-identifier">join</span>(<span class="ruby-value str">', '</span>)
435
+ 93: <span class="ruby-keyword kw">end</span>
436
+ 94:
437
+ 95: <span class="ruby-comment cmt"># get the AWS header</span>
438
+ 96: <span class="ruby-identifier">canonical_string</span> = <span class="ruby-identifier">generate_canonical_string</span>(<span class="ruby-identifier">method</span>, <span class="ruby-identifier">path</span>, <span class="ruby-identifier">headers</span>)
439
+ 97: <span class="ruby-identifier">signature</span> = <span class="ruby-identifier">generate_signature</span>(<span class="ruby-identifier">aws_secret_access_key</span>, <span class="ruby-identifier">canonical_string</span>)
440
+ 98: <span class="ruby-constant">AWS_AUTH_HEADER_VALUE</span> <span class="ruby-operator">%</span> [<span class="ruby-identifier">aws_access_key</span>, <span class="ruby-identifier">signature</span>]
441
+ 99: <span class="ruby-keyword kw">end</span>
442
+ </pre>
443
+ </div>
444
+ </div>
445
+ </div>
446
+
447
+ <div id="method-M000040" class="method-detail">
448
+ <a name="M000040"></a>
449
+
450
+ <div class="method-heading">
451
+ <a href="#M000040" class="method-signature">
452
+ <span class="method-name">generate_canonical_string</span><span class="method-args">(method, path, headers={}, expires=nil)</span>
453
+ </a>
454
+ </div>
455
+
456
+ <div class="method-description">
457
+ <p>
458
+ Build canonical string for signing; modified (slightly) from the Amazon
459
+ sample code.
460
+ </p>
461
+ <p><a class="source-toggle" href="#"
462
+ onclick="toggleCode('M000040-source');return false;">[Source]</a></p>
463
+ <div class="method-source-code" id="M000040-source">
464
+ <pre>
465
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 44</span>
466
+ 44: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">generate_canonical_string</span>(<span class="ruby-identifier">method</span>, <span class="ruby-identifier">path</span>, <span class="ruby-identifier">headers</span>={}, <span class="ruby-identifier">expires</span>=<span class="ruby-keyword kw">nil</span>)
467
+ 45: <span class="ruby-identifier">interesting_headers</span> = {}
468
+ 46: <span class="ruby-identifier">headers</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
469
+ 47: <span class="ruby-identifier">lk</span> = <span class="ruby-identifier">key</span>.<span class="ruby-identifier">downcase</span>
470
+ 48: <span class="ruby-keyword kw">if</span> (<span class="ruby-constant">INTERESTING_HEADERS</span>.<span class="ruby-identifier">include?</span>(<span class="ruby-identifier">lk</span>) <span class="ruby-keyword kw">or</span> <span class="ruby-identifier">lk</span> <span class="ruby-operator">=~</span> <span class="ruby-node">/^#{AWS_HEADER_PREFIX}/o</span>)
471
+ 49: <span class="ruby-identifier">interesting_headers</span>[<span class="ruby-identifier">lk</span>] = <span class="ruby-identifier">value</span>
472
+ 50: <span class="ruby-keyword kw">end</span>
473
+ 51: <span class="ruby-keyword kw">end</span>
474
+ 52:
475
+ 53: <span class="ruby-comment cmt"># these fields get empty strings if they don't exist.</span>
476
+ 54: <span class="ruby-identifier">interesting_headers</span>[<span class="ruby-value str">'content-type'</span>] <span class="ruby-operator">||=</span> <span class="ruby-value str">''</span>
477
+ 55: <span class="ruby-identifier">interesting_headers</span>[<span class="ruby-value str">'content-md5'</span>] <span class="ruby-operator">||=</span> <span class="ruby-value str">''</span>
478
+ 56:
479
+ 57: <span class="ruby-comment cmt"># if you're using expires for query string auth, then it trumps date</span>
480
+ 58: <span class="ruby-keyword kw">if</span> <span class="ruby-keyword kw">not</span> <span class="ruby-identifier">expires</span>.<span class="ruby-identifier">nil?</span>
481
+ 59: <span class="ruby-identifier">interesting_headers</span>[<span class="ruby-value str">'date'</span>] = <span class="ruby-identifier">expires</span>
482
+ 60: <span class="ruby-keyword kw">end</span>
483
+ 61:
484
+ 62: <span class="ruby-identifier">buf</span> = <span class="ruby-node">&quot;#{method}\n&quot;</span>
485
+ 63: <span class="ruby-identifier">interesting_headers</span>.<span class="ruby-identifier">sort</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">a</span>, <span class="ruby-identifier">b</span><span class="ruby-operator">|</span> <span class="ruby-identifier">a</span>[<span class="ruby-value">0</span>] <span class="ruby-operator">&lt;=&gt;</span> <span class="ruby-identifier">b</span>[<span class="ruby-value">0</span>] }.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>
486
+ 64: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">key</span> <span class="ruby-operator">=~</span> <span class="ruby-node">/^#{AWS_HEADER_PREFIX}/o</span>
487
+ 65: <span class="ruby-identifier">buf</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-node">&quot;#{key}:#{value}\n&quot;</span>
488
+ 66: <span class="ruby-keyword kw">else</span>
489
+ 67: <span class="ruby-identifier">buf</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-node">&quot;#{value}\n&quot;</span>
490
+ 68: <span class="ruby-keyword kw">end</span>
491
+ 69: <span class="ruby-keyword kw">end</span>
492
+ 70:
493
+ 71: <span class="ruby-comment cmt"># ignore everything after the question mark...</span>
494
+ 72: <span class="ruby-identifier">buf</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">path</span>.<span class="ruby-identifier">gsub</span>(<span class="ruby-regexp re">/\?.*$/</span>, <span class="ruby-value str">''</span>)
495
+ 73:
496
+ 74: <span class="ruby-comment cmt"># ...unless there is an acl or torrent parameter</span>
497
+ 75: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">path</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/[&amp;?]acl($|&amp;|=)/</span>
498
+ 76: <span class="ruby-identifier">buf</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'?acl'</span>
499
+ 77: <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">path</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/[&amp;?]torrent($|&amp;|=)/</span>
500
+ 78: <span class="ruby-identifier">buf</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-value str">'?torrent'</span>
501
+ 79: <span class="ruby-keyword kw">end</span>
502
+ 80:
503
+ 81: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">buf</span>
504
+ 82: <span class="ruby-keyword kw">end</span>
505
+ </pre>
506
+ </div>
507
+ </div>
508
+ </div>
509
+
510
+ <div id="method-M000048" class="method-detail">
511
+ <a name="M000048"></a>
512
+
513
+ <div class="method-heading">
514
+ <a href="#M000048" class="method-signature">
515
+ <span class="method-name">generate_querystring</span><span class="method-args">(pairs={})</span>
516
+ </a>
517
+ </div>
518
+
519
+ <div class="method-description">
520
+ <p>
521
+ Convert a hash of name/value pairs to querystring variables. Name for a
522
+ variable can be a string or symbol.
523
+ </p>
524
+ <p><a class="source-toggle" href="#"
525
+ onclick="toggleCode('M000048-source');return false;">[Source]</a></p>
526
+ <div class="method-source-code" id="M000048-source">
527
+ <pre>
528
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 164</span>
529
+ 164: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">generate_querystring</span>(<span class="ruby-identifier">pairs</span>={})
530
+ 165: <span class="ruby-identifier">str</span> = <span class="ruby-value str">''</span>
531
+ 166: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">pairs</span>.<span class="ruby-identifier">size</span> <span class="ruby-operator">&gt;</span> <span class="ruby-value">0</span>
532
+ 167: <span class="ruby-identifier">str</span> <span class="ruby-operator">+=</span> <span class="ruby-value str">&quot;?&quot;</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">pairs</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-node">&quot;#{key}=#{CGI::escape(value.to_s)}&quot;</span> }.<span class="ruby-identifier">join</span>(<span class="ruby-value str">'&amp;'</span>)
533
+ 168: <span class="ruby-keyword kw">end</span>
534
+ 169: <span class="ruby-identifier">str</span>
535
+ 170: <span class="ruby-keyword kw">end</span>
536
+ </pre>
537
+ </div>
538
+ </div>
539
+ </div>
540
+
541
+ <div id="method-M000042" class="method-detail">
542
+ <a name="M000042"></a>
543
+
544
+ <div class="method-heading">
545
+ <a href="#M000042" class="method-signature">
546
+ <span class="method-name">generate_signature</span><span class="method-args">(aws_secret_access_key, str)</span>
547
+ </a>
548
+ </div>
549
+
550
+ <div class="method-description">
551
+ <p>
552
+ Encode the given string with the aws_secret_access_key, by taking the hmac
553
+ sha1 sum, and then base64 encoding it.
554
+ </p>
555
+ <p><a class="source-toggle" href="#"
556
+ onclick="toggleCode('M000042-source');return false;">[Source]</a></p>
557
+ <div class="method-source-code" id="M000042-source">
558
+ <pre>
559
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 103</span>
560
+ 103: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">generate_signature</span>(<span class="ruby-identifier">aws_secret_access_key</span>, <span class="ruby-identifier">str</span>)
561
+ 104: <span class="ruby-identifier">digest</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">HMAC</span><span class="ruby-operator">::</span><span class="ruby-identifier">digest</span>(<span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">Digest</span><span class="ruby-operator">::</span><span class="ruby-constant">Digest</span>.<span class="ruby-identifier">new</span>(<span class="ruby-value str">&quot;SHA1&quot;</span>), <span class="ruby-identifier">aws_secret_access_key</span>, <span class="ruby-identifier">str</span>)
562
+ 105: <span class="ruby-constant">Base64</span>.<span class="ruby-identifier">encode64</span>(<span class="ruby-identifier">digest</span>).<span class="ruby-identifier">strip</span>
563
+ 106: <span class="ruby-keyword kw">end</span>
564
+ </pre>
565
+ </div>
566
+ </div>
567
+ </div>
568
+
569
+ <div id="method-M000046" class="method-detail">
570
+ <a name="M000046"></a>
571
+
572
+ <div class="method-heading">
573
+ <a href="#M000046" class="method-signature">
574
+ <span class="method-name">guess_mime_type</span><span class="method-args">(file_name)</span>
575
+ </a>
576
+ </div>
577
+
578
+ <div class="method-description">
579
+ <p>
580
+ Guess a file&#8217;s mime type. If the mime_type for a file cannot be
581
+ guessed, &quot;text/plain&quot; is used.
582
+ </p>
583
+ <p><a class="source-toggle" href="#"
584
+ onclick="toggleCode('M000046-source');return false;">[Source]</a></p>
585
+ <div class="method-source-code" id="M000046-source">
586
+ <pre>
587
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 149</span>
588
+ 149: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">guess_mime_type</span>(<span class="ruby-identifier">file_name</span>)
589
+ 150: <span class="ruby-identifier">mime_type</span> = <span class="ruby-constant">MIME</span><span class="ruby-operator">::</span><span class="ruby-constant">Types</span>.<span class="ruby-identifier">type_for</span>(<span class="ruby-identifier">file_name</span>)[<span class="ruby-value">0</span>]
590
+ 151: <span class="ruby-identifier">mime_type</span> <span class="ruby-operator">||=</span> <span class="ruby-constant">MIME</span><span class="ruby-operator">::</span><span class="ruby-constant">Types</span>[<span class="ruby-value str">'text/plain'</span>][<span class="ruby-value">0</span>]
591
+ 152: <span class="ruby-identifier">mime_type</span>
592
+ 153: <span class="ruby-keyword kw">end</span>
593
+ </pre>
594
+ </div>
595
+ </div>
596
+ </div>
597
+
598
+ <div id="method-M000044" class="method-detail">
599
+ <a name="M000044"></a>
600
+
601
+ <div class="method-heading">
602
+ <a href="#M000044" class="method-signature">
603
+ <span class="method-name">metadata_headers</span><span class="method-args">(headers, metadata={})</span>
604
+ </a>
605
+ </div>
606
+
607
+ <div class="method-description">
608
+ <p>
609
+ Add metadata headers, correctly prefixing them first. Returns headers with
610
+ the metadata headers appended.
611
+ </p>
612
+ <p><a class="source-toggle" href="#"
613
+ onclick="toggleCode('M000044-source');return false;">[Source]</a></p>
614
+ <div class="method-source-code" id="M000044-source">
615
+ <pre>
616
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 129</span>
617
+ 129: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">metadata_headers</span>(<span class="ruby-identifier">headers</span>, <span class="ruby-identifier">metadata</span>={})
618
+ 130: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">metadata</span>.<span class="ruby-identifier">empty?</span>
619
+ 131: <span class="ruby-identifier">metadata</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">headers</span>[<span class="ruby-constant">METADATA_PREFIX</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span> }
620
+ 132: <span class="ruby-keyword kw">end</span>
621
+ 133: <span class="ruby-identifier">headers</span>
622
+ 134: <span class="ruby-keyword kw">end</span>
623
+ </pre>
624
+ </div>
625
+ </div>
626
+ </div>
627
+
628
+ <div id="method-M000051" class="method-detail">
629
+ <a name="M000051"></a>
630
+
631
+ <div class="method-heading">
632
+ <a href="#M000051" class="method-signature">
633
+ <span class="method-name">s3_authenticated_url</span><span class="method-args">(aws_access_key, aws_secret_access_key, bucket_name, resource_key, expires)</span>
634
+ </a>
635
+ </div>
636
+
637
+ <div class="method-description">
638
+ <p>
639
+ Generate a get-able URL for an S3 resource key which passes authentication
640
+ in querystring. int expires: when the URL expires (seconds since the epoch)
641
+ </p>
642
+ <p><a class="source-toggle" href="#"
643
+ onclick="toggleCode('M000051-source');return false;">[Source]</a></p>
644
+ <div class="method-source-code" id="M000051-source">
645
+ <pre>
646
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 200</span>
647
+ 200: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">s3_authenticated_url</span>(<span class="ruby-identifier">aws_access_key</span>, <span class="ruby-identifier">aws_secret_access_key</span>, <span class="ruby-identifier">bucket_name</span>, <span class="ruby-identifier">resource_key</span>,
648
+ 201: <span class="ruby-identifier">expires</span>)
649
+ 202: <span class="ruby-identifier">path</span> = <span class="ruby-value str">'/'</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">bucket_name</span> <span class="ruby-operator">+</span> <span class="ruby-value str">'/'</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">resource_key</span>
650
+ 203:
651
+ 204: <span class="ruby-identifier">canonical_string</span> = <span class="ruby-identifier">generate_canonical_string</span>(<span class="ruby-value str">'GET'</span>, <span class="ruby-identifier">path</span>, {}, <span class="ruby-identifier">expires</span>)
652
+ 205: <span class="ruby-identifier">signature</span> = <span class="ruby-identifier">generate_signature</span>(<span class="ruby-identifier">aws_secret_access_key</span>, <span class="ruby-identifier">canonical_string</span>)
653
+ 206:
654
+ 207: <span class="ruby-identifier">querystring</span> = <span class="ruby-identifier">generate_querystring</span>({ <span class="ruby-value str">'Signature'</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">signature</span>, <span class="ruby-value str">'Expires'</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">expires</span>,
655
+ 208: <span class="ruby-value str">'AWSAccessKeyId'</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">aws_access_key</span> })
656
+ 209:
657
+ 210: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">s3_public_url</span>(<span class="ruby-identifier">bucket_name</span>, <span class="ruby-identifier">resource_key</span>) <span class="ruby-operator">+</span> <span class="ruby-identifier">querystring</span>
658
+ 211: <span class="ruby-keyword kw">end</span>
659
+ </pre>
660
+ </div>
661
+ </div>
662
+ </div>
663
+
664
+ <div id="method-M000050" class="method-detail">
665
+ <a name="M000050"></a>
666
+
667
+ <div class="method-heading">
668
+ <a href="#M000050" class="method-signature">
669
+ <span class="method-name">s3_public_url</span><span class="method-args">(bucket_name, resource_key)</span>
670
+ </a>
671
+ </div>
672
+
673
+ <div class="method-description">
674
+ <p>
675
+ The public URL for this key (which only works if public-read ACL is set).
676
+ </p>
677
+ <p><a class="source-toggle" href="#"
678
+ onclick="toggleCode('M000050-source');return false;">[Source]</a></p>
679
+ <div class="method-source-code" id="M000050-source">
680
+ <pre>
681
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 194</span>
682
+ 194: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">s3_public_url</span>(<span class="ruby-identifier">bucket_name</span>, <span class="ruby-identifier">resource_key</span>)
683
+ 195: <span class="ruby-value str">&quot;http://&quot;</span> <span class="ruby-operator">+</span> <span class="ruby-constant">HOST</span> <span class="ruby-operator">+</span> <span class="ruby-value str">'/'</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">bucket_name</span> <span class="ruby-operator">+</span> <span class="ruby-value str">'/'</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">resource_key</span>
684
+ 196: <span class="ruby-keyword kw">end</span>
685
+ </pre>
686
+ </div>
687
+ </div>
688
+ </div>
689
+
690
+ <div id="method-M000049" class="method-detail">
691
+ <a name="M000049"></a>
692
+
693
+ <div class="method-heading">
694
+ <a href="#M000049" class="method-signature">
695
+ <span class="method-name">url_join</span><span class="method-args">(*args)</span>
696
+ </a>
697
+ </div>
698
+
699
+ <div class="method-description">
700
+ <p>
701
+ Build URLs from fragments. Does similar job to File.join but puts forward
702
+ slash between arguments (only if it&#8217;s not already there).
703
+ </p>
704
+ <p><a class="source-toggle" href="#"
705
+ onclick="toggleCode('M000049-source');return false;">[Source]</a></p>
706
+ <div class="method-source-code" id="M000049-source">
707
+ <pre>
708
+ <span class="ruby-comment cmt"># File lib/s33r/core.rb, line 175</span>
709
+ 175: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">url_join</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">args</span>)
710
+ 176: <span class="ruby-identifier">url_start</span> = <span class="ruby-value str">''</span>
711
+ 177: <span class="ruby-identifier">url_end</span> = <span class="ruby-identifier">args</span>.<span class="ruby-identifier">join</span>(<span class="ruby-value str">'/'</span>)
712
+ 178:
713
+ 179: <span class="ruby-comment cmt"># string index where the scheme of the URL (xxxx://) ends</span>
714
+ 180: <span class="ruby-identifier">scheme_ends_at</span> = (<span class="ruby-identifier">url_end</span> <span class="ruby-operator">=~</span> <span class="ruby-regexp re">/:\/\//</span>)
715
+ 181: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">scheme_ends_at</span>.<span class="ruby-identifier">nil?</span>
716
+ 182: <span class="ruby-identifier">scheme_ends_at</span> = <span class="ruby-identifier">scheme_ends_at</span> <span class="ruby-operator">+</span> <span class="ruby-value">1</span>
717
+ 183: <span class="ruby-identifier">url_start</span> = <span class="ruby-identifier">url_end</span>[<span class="ruby-value">0</span><span class="ruby-operator">..</span><span class="ruby-identifier">scheme_ends_at</span>]
718
+ 184: <span class="ruby-identifier">url_end</span> = <span class="ruby-identifier">url_end</span>[(<span class="ruby-identifier">scheme_ends_at</span> <span class="ruby-operator">+</span> <span class="ruby-value">1</span>)<span class="ruby-operator">..</span><span class="ruby-value">-1</span>]
719
+ 185: <span class="ruby-keyword kw">end</span>
720
+ 186:
721
+ 187: <span class="ruby-comment cmt"># replace any multiple forward slashes (except those in the scheme)</span>
722
+ 188: <span class="ruby-identifier">url_end</span> = <span class="ruby-identifier">url_end</span>.<span class="ruby-identifier">gsub</span>(<span class="ruby-regexp re">/\/{2,}/</span>, <span class="ruby-value str">'/'</span>)
723
+ 189:
724
+ 190: <span class="ruby-identifier">url_start</span> <span class="ruby-operator">+</span> <span class="ruby-identifier">url_end</span>
725
+ 191: <span class="ruby-keyword kw">end</span>
726
+ </pre>
727
+ </div>
728
+ </div>
729
+ </div>
730
+
731
+
732
+ </div>
733
+
734
+
735
+ </div>
736
+
737
+
738
+ <div id="validator-badges">
739
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
740
+ </div>
741
+
742
+ </body>
743
+ </html>