lyrics 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +17 -0
  5. data/Rakefile +45 -0
  6. data/VERSION +1 -0
  7. data/bin/lyrics +66 -0
  8. data/lib/lyrics.rb +4 -0
  9. data/lib/lyrics/cli/application.rb +99 -0
  10. data/lib/lyrics/cli/optionsparser.rb +228 -0
  11. data/lib/lyrics/cli/pluginadapter.rb +56 -0
  12. data/lib/lyrics/cli/plugins.rb +79 -0
  13. data/lib/lyrics/cli/wikipluginadapter.rb +139 -0
  14. data/lib/lyrics/i18n/README +1 -0
  15. data/lib/lyrics/i18n/en.rb +181 -0
  16. data/lib/lyrics/i18n/es.rb +181 -0
  17. data/lib/lyrics/i18n/i18n.rb +126 -0
  18. data/lib/lyrics/i18n/sk.rb +174 -0
  19. data/lib/lyrics/itrans/COPYRIGHT +31 -0
  20. data/lib/lyrics/itrans/itrans +0 -0
  21. data/lib/lyrics/itrans/itrans.txt +8 -0
  22. data/lib/lyrics/itrans/lyric.txt +23 -0
  23. data/lib/lyrics/itrans/udvng.ifm +206 -0
  24. data/lib/lyrics/lyrics.rb +567 -0
  25. data/lib/lyrics/lyrics_AZLyrics.rb +113 -0
  26. data/lib/lyrics/lyrics_DarkLyrics.rb +124 -0
  27. data/lib/lyrics/lyrics_Giitaayan.rb +124 -0
  28. data/lib/lyrics/lyrics_Jamendo.rb +166 -0
  29. data/lib/lyrics/lyrics_LeosLyrics.rb +142 -0
  30. data/lib/lyrics/lyrics_LoudSongs.rb +135 -0
  31. data/lib/lyrics/lyrics_LyricWiki.rb +328 -0
  32. data/lib/lyrics/lyrics_LyricsDownload.rb +118 -0
  33. data/lib/lyrics/lyrics_LyricsMania.rb +141 -0
  34. data/lib/lyrics/lyrics_Lyriki.rb +286 -0
  35. data/lib/lyrics/lyrics_SeekLyrics.rb +108 -0
  36. data/lib/lyrics/lyrics_Sing365.rb +103 -0
  37. data/lib/lyrics/lyrics_TerraLetras.rb +126 -0
  38. data/lib/lyrics/mediawikilyrics.rb +1417 -0
  39. data/lib/lyrics/utils/formdata.rb +56 -0
  40. data/lib/lyrics/utils/htmlentities.rb +291 -0
  41. data/lib/lyrics/utils/http.rb +198 -0
  42. data/lib/lyrics/utils/itrans.rb +160 -0
  43. data/lib/lyrics/utils/logger.rb +123 -0
  44. data/lib/lyrics/utils/strings.rb +378 -0
  45. data/lib/lyrics/utils/xmlhash.rb +111 -0
  46. data/lyrics.gemspec +98 -0
  47. data/spec/lyrics_spec.rb +7 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +9 -0
  50. metadata +137 -0
@@ -0,0 +1,56 @@
1
+ # Copyright (C) 2006-2008 by Sergio Pistone
2
+ # sergio_pistone@yahoo.com.ar
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the
16
+ # Free Software Foundation, Inc.,
17
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
+
19
+ require "cgi"
20
+
21
+ module URLEncodedFormData
22
+
23
+ def URLEncodedFormData.prepare_query( params )
24
+ query = params.collect { |name, value| "#{name}=#{CGI.escape( value.to_s() )}" }.join( "&" )
25
+ header = { "Content-type" => "application/x-www-form-urlencoded" }
26
+ return query, header
27
+ end
28
+
29
+ end
30
+
31
+ module MultipartFormData
32
+
33
+ @@boundary = "----------nOtA5FcjrNZuZ3TMioysxHGGCO69vA5iYysdBTL2osuNwOjcCfU7uiN"
34
+
35
+ def MultipartFormData.text_param( name, value )
36
+ return "Content-Disposition: form-data; name=\"#{CGI.escape(name)}\"\r\n" \
37
+ "\r\n" \
38
+ "#{value}\r\n"
39
+ end
40
+
41
+ def MultipartFormData.file_param( name, file, mime_type, content )
42
+ return "Content-Disposition: form-data; name=\"#{CGI.escape(name)}\"; filename=\"#{file}\"\r\n" \
43
+ "Content-Transfer-Encoding: binary\r\n" \
44
+ "Content-Type: #{mime_type}\r\n" \
45
+ "\r\n" \
46
+ "#{content}\r\n"
47
+ end
48
+
49
+ def MultipartFormData.prepare_query( params )
50
+ query = params.collect { |param| "--#{@@boundary}\r\n#{param}" }.join( "" ) + "--#{@@boundary}--"
51
+ header = { "Content-type" => "multipart/form-data; boundary=" + @@boundary }
52
+ return query, header
53
+ end
54
+
55
+ end
56
+
@@ -0,0 +1,291 @@
1
+ # Copyright (C) 2006-2008 by Sergio Pistone
2
+ # sergio_pistone@yahoo.com.ar
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the
16
+ # Free Software Foundation, Inc.,
17
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
+
19
+ module HTMLEntities
20
+
21
+ def HTMLEntities.decode!( text )
22
+ aux1 = text.gsub!( /&([a-zA-Z]+);/ ) { (n = @@named_entities[$1]) ? [n].pack( "U" ) : $0 }
23
+ aux2 = text.gsub!( /&#(\d{2,4});/ ) { [$1.to_i()].pack( "U" ) }
24
+ aux3 = text.gsub!( /&#x([0-9a-fA-F]{2,4});/ ) { [s.to_i(16)].pack( "U" ) }
25
+ return (aux1||aux2||aux3) ? text : nil
26
+ end
27
+
28
+ def HTMLEntities.decode( text )
29
+ text = String.new( text )
30
+ HTMLEntities.decode!( text )
31
+ return text
32
+ end
33
+
34
+ @@named_entities = {
35
+ "quot" => 34,
36
+ "amp" => 38,
37
+ "lt" => 60,
38
+ "gt" => 62,
39
+ "OElig" => 338,
40
+ "oelig" => 339,
41
+ "Scaron" => 352,
42
+ "scaron" => 353,
43
+ "Yuml" => 376,
44
+ "circ" => 710,
45
+ "tilde" => 732,
46
+ "ensp" => 8194,
47
+ "emsp" => 8195,
48
+ "thinsp" => 8201,
49
+ "zwnj" => 8204,
50
+ "zwj" => 8205,
51
+ "lrm" => 8206,
52
+ "rlm" => 8207,
53
+ "ndash" => 8211,
54
+ "mdash" => 8212,
55
+ "lsquo" => 8216,
56
+ "rsquo" => 8217,
57
+ "sbquo" => 8218,
58
+ "ldquo" => 8220,
59
+ "rdquo" => 8221,
60
+ "bdquo" => 8222,
61
+ "dagger" => 8224,
62
+ "Dagger" => 8225,
63
+ "permil" => 8240,
64
+ "lsaquo" => 8249,
65
+ "rsaquo" => 8250,
66
+ "euro" => 8364,
67
+
68
+ "fnof" => 402,
69
+ "Alpha" => 913,
70
+ "Beta" => 914,
71
+ "Gamma" => 915,
72
+ "Delta" => 916,
73
+ "Epsilon" => 917,
74
+ "Zeta" => 918,
75
+ "Eta" => 919,
76
+ "Theta" => 920,
77
+ "Iota" => 921,
78
+ "Kappa" => 922,
79
+ "Lambda" => 923,
80
+ "Mu" => 924,
81
+ "Nu" => 925,
82
+ "Xi" => 926,
83
+ "Omicron" => 927,
84
+ "Pi" => 928,
85
+ "Rho" => 929,
86
+ "Sigma" => 931,
87
+ "Tau" => 932,
88
+ "Upsilon" => 933,
89
+ "Phi" => 934,
90
+ "Chi" => 935,
91
+ "Psi" => 936,
92
+ "Omega" => 937,
93
+ "alpha" => 945,
94
+ "beta" => 946,
95
+ "gamma" => 947,
96
+ "delta" => 948,
97
+ "epsilon" => 949,
98
+ "zeta" => 950,
99
+ "eta" => 951,
100
+ "theta" => 952,
101
+ "iota" => 953,
102
+ "kappa" => 954,
103
+ "lambda" => 955,
104
+ "mu" => 956,
105
+ "nu" => 957,
106
+ "xi" => 958,
107
+ "omicron" => 959,
108
+ "pi" => 960,
109
+ "rho" => 961,
110
+ "sigmaf" => 962,
111
+ "sigma" => 963,
112
+ "tau" => 964,
113
+ "upsilon" => 965,
114
+ "phi" => 966,
115
+ "chi" => 967,
116
+ "psi" => 968,
117
+ "omega" => 969,
118
+ "thetasym" => 977,
119
+ "upsih" => 978,
120
+ "piv" => 982,
121
+ "bull" => 8226,
122
+ "hellip" => 8230,
123
+ "prime" => 8242,
124
+ "Prime" => 8243,
125
+ "oline" => 8254,
126
+ "frasl" => 8260,
127
+ "weierp" => 8472,
128
+ "image" => 8465,
129
+ "real" => 8476,
130
+ "trade" => 8482,
131
+ "alefsym" => 8501,
132
+ "larr" => 8592,
133
+ "uarr" => 8593,
134
+ "rarr" => 8594,
135
+ "darr" => 8595,
136
+ "harr" => 8596,
137
+ "crarr" => 8629,
138
+ "lArr" => 8656,
139
+ "uArr" => 8657,
140
+ "rArr" => 8658,
141
+ "dArr" => 8659,
142
+ "hArr" => 8660,
143
+ "forall" => 8704,
144
+ "part" => 8706,
145
+ "exist" => 8707,
146
+ "empty" => 8709,
147
+ "nabla" => 8711,
148
+ "isin" => 8712,
149
+ "notin" => 8713,
150
+ "ni" => 8715,
151
+ "prod" => 8719,
152
+ "sum" => 8721,
153
+ "minus" => 8722,
154
+ "lowast" => 8727,
155
+ "radic" => 8730,
156
+ "prop" => 8733,
157
+ "infin" => 8734,
158
+ "ang" => 8736,
159
+ "and" => 8743,
160
+ "or" => 8744,
161
+ "cap" => 8745,
162
+ "cup" => 8746,
163
+ "int" => 8747,
164
+ "there4" => 8756,
165
+ "sim" => 8764,
166
+ "cong" => 8773,
167
+ "asymp" => 8776,
168
+ "ne" => 8800,
169
+ "equiv" => 8801,
170
+ "le" => 8804,
171
+ "ge" => 8805,
172
+ "sub" => 8834,
173
+ "sup" => 8835,
174
+ "nsub" => 8836,
175
+ "sube" => 8838,
176
+ "supe" => 8839,
177
+ "oplus" => 8853,
178
+ "otimes" => 8855,
179
+ "perp" => 8869,
180
+ "sdot" => 8901,
181
+ "lceil" => 8968,
182
+ "rceil" => 8969,
183
+ "lfloor" => 8970,
184
+ "rfloor" => 8971,
185
+ "lang" => 9001,
186
+ "rang" => 9002,
187
+ "loz" => 9674,
188
+ "spades" => 9824,
189
+ "clubs" => 9827,
190
+ "hearts" => 9829,
191
+ "diams" => 9830,
192
+
193
+ "nbsp" => 160,
194
+ "iexcl" => 161,
195
+ "cent" => 162,
196
+ "pound" => 163,
197
+ "curren" => 164,
198
+ "yen" => 165,
199
+ "brvbar" => 166,
200
+ "sect" => 167,
201
+ "uml" => 168,
202
+ "copy" => 169,
203
+ "ordf" => 170,
204
+ "laquo" => 171,
205
+ "not" => 172,
206
+ "shy" => 173,
207
+ "reg" => 174,
208
+ "macr" => 175,
209
+ "deg" => 176,
210
+ "plusmn" => 177,
211
+ "sup2" => 178,
212
+ "sup3" => 179,
213
+ "acute" => 180,
214
+ "micro" => 181,
215
+ "para" => 182,
216
+ "middot" => 183,
217
+ "cedil" => 184,
218
+ "sup1" => 185,
219
+ "ordm" => 186,
220
+ "raquo" => 187,
221
+ "frac14" => 188,
222
+ "frac12" => 189,
223
+ "frac34" => 190,
224
+ "iquest" => 191,
225
+ "Agrave" => 192,
226
+ "Aacute" => 193,
227
+ "Acirc" => 194,
228
+ "Atilde" => 195,
229
+ "Auml" => 196,
230
+ "Aring" => 197,
231
+ "AElig" => 198,
232
+ "Ccedil" => 199,
233
+ "Egrave" => 200,
234
+ "Eacute" => 201,
235
+ "Ecirc" => 202,
236
+ "Euml" => 203,
237
+ "Igrave" => 204,
238
+ "Iacute" => 205,
239
+ "Icirc" => 206,
240
+ "Iuml" => 207,
241
+ "ETH" => 208,
242
+ "Ntilde" => 209,
243
+ "Ograve" => 210,
244
+ "Oacute" => 211,
245
+ "Ocirc" => 212,
246
+ "Otilde" => 213,
247
+ "Ouml" => 214,
248
+ "times" => 215,
249
+ "Oslash" => 216,
250
+ "Ugrave" => 217,
251
+ "Uacute" => 218,
252
+ "Ucirc" => 219,
253
+ "Uuml" => 220,
254
+ "Yacute" => 221,
255
+ "THORN" => 222,
256
+ "szlig" => 223,
257
+ "agrave" => 224,
258
+ "aacute" => 225,
259
+ "acirc" => 226,
260
+ "atilde" => 227,
261
+ "auml" => 228,
262
+ "aring" => 229,
263
+ "aelig" => 230,
264
+ "ccedil" => 231,
265
+ "egrave" => 232,
266
+ "eacute" => 233,
267
+ "ecirc" => 234,
268
+ "euml" => 235,
269
+ "igrave" => 236,
270
+ "iacute" => 237,
271
+ "icirc" => 238,
272
+ "iuml" => 239,
273
+ "eth" => 240,
274
+ "ntilde" => 241,
275
+ "ograve" => 242,
276
+ "oacute" => 243,
277
+ "ocirc" => 244,
278
+ "otilde" => 245,
279
+ "ouml" => 246,
280
+ "divide" => 247,
281
+ "oslash" => 248,
282
+ "ugrave" => 249,
283
+ "uacute" => 250,
284
+ "ucirc" => 251,
285
+ "uuml" => 252,
286
+ "yacute" => 253,
287
+ "thorn" => 254,
288
+ "yuml" => 255,
289
+ }
290
+
291
+ end
@@ -0,0 +1,198 @@
1
+ # Copyright (C) 2006-2008 by Sergio Pistone
2
+ # sergio_pistone@yahoo.com.ar
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the
16
+ # Free Software Foundation, Inc.,
17
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
+
19
+ require File.expand_path( File.dirname( __FILE__ ) + "/formdata" )
20
+
21
+ require "net/http"
22
+ require "uri"
23
+
24
+ module HTTP
25
+
26
+ # @@user_agent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2"
27
+ @@user_agent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071110 Firefox/2.0.0.9"
28
+ # @@user_agent = "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080218 Firefox/2.0.0.12"
29
+
30
+ @@proxy_url = nil
31
+ @@proxy_excluded_urls = []
32
+ @@proxy_reverse = false # if true, excluded_urls list becomes a list with the _only_ urls the proxy should be used for
33
+
34
+ def HTTP.normalize_url( url, protocol="http" )
35
+ url = url.strip()
36
+ protocol_regexp = /^ *([^: ]+):\/+/
37
+ md = protocol_regexp.match( url )
38
+ return nil if md && md[1] != protocol
39
+ url.gsub!( /\/+$/, "" ) # remove / at the end of the url
40
+ url.gsub!( protocol_regexp, "" ) # remove the protocol part if there was one
41
+ return "#{protocol}://#{url}" # reinsert protocol part assuring protocol:// form
42
+ end
43
+
44
+ def HTTP.set_proxy_settings( proxy_url, excluded_urls=[], reverse=false )
45
+ @@proxy_url = proxy_url ? HTTP.normalize_url( proxy_url, "http" ) : nil
46
+ @@proxy_reverse = @@proxy_url ? reverse : false
47
+ @@proxy_excluded_urls = []
48
+ if @@proxy_url
49
+ excluded_urls.each() do |url|
50
+ url = normalize_url( url, "http" )
51
+ @@proxy_excluded_urls.insert( -1, url ) if url && ! @@proxy_excluded_urls.include?( url )
52
+ end
53
+ end
54
+ end
55
+
56
+ def HTTP.get_proxy_settings()
57
+ ret = [@@proxy_url ? @@proxy_url.dup : nil, [], @@proxy_reverse]
58
+ @@proxy_excluded_urls.each() { |url| ret[1][ret[1].size] = url.dup }
59
+ return ret
60
+ end
61
+
62
+ # returns proxy_host, proxy_port, proxy_user, proxy_pass for given url
63
+ def HTTP.get_url_proxy_settings( url )
64
+
65
+ return nil, nil, nil, nil if ! @@proxy_url
66
+ proxy = HTTP.parse_uri( @@proxy_url )
67
+ return nil, nil, nil, nil if ! proxy.host
68
+ proxy.port = 80 if ! proxy.port
69
+
70
+ # check if given url should be treated specially
71
+ exception = false
72
+ @@proxy_excluded_urls.each() do |exception_url|
73
+ if url.index( exception_url ) == 0
74
+ exception = true
75
+ break
76
+ end
77
+ end
78
+
79
+ if exception && @@proxy_reverse || ! exception && ! @@proxy_reverse
80
+ return proxy.host, proxy.port, proxy.user, proxy.password
81
+ else
82
+ return nil, nil, nil, nil
83
+ end
84
+ end
85
+
86
+ def HTTP.parse_uri( uri )
87
+ begin
88
+ return URI.parse( uri )
89
+ rescue URI::InvalidURIError
90
+ return URI.parse( URI.escape( uri ) )
91
+ end
92
+ end
93
+
94
+ def HTTP.fetch_page_get( url, headers=nil, follow=10 )
95
+ begin
96
+
97
+ p_url = HTTP.parse_uri( url )
98
+ return nil, url if p_url.host == nil || p_url.port == nil || p_url.request_uri == nil
99
+ proxy_host, proxy_port, proxy_user, proxy_pass = HTTP.get_url_proxy_settings( url )
100
+
101
+ full_headers = {
102
+ "User-Agent" => @@user_agent,
103
+ "Referer" => "#{p_url.scheme}://#{p_url.host}",
104
+ }
105
+ full_headers.merge!( headers ) if headers
106
+
107
+ http = Net::HTTP.new( p_url.host, p_url.port, proxy_host, proxy_port, proxy_user, proxy_pass )
108
+ response = http.request_get( p_url.request_uri, full_headers )
109
+
110
+ case response
111
+ when Net::HTTPSuccess
112
+ when Net::HTTPRedirection, Net::HTTPFound
113
+ if follow == 0
114
+ response = nil
115
+ elsif follow > 0
116
+ response, url = HTTP.fetch_page_get( response["location"], nil, follow-1 )
117
+ end
118
+ else
119
+ response = nil
120
+ end
121
+
122
+ return response, url
123
+
124
+ rescue Errno::ETIMEDOUT, Errno::EBADF, EOFError => e
125
+ raise TimeoutError.new( e.to_s )
126
+ end
127
+ end
128
+
129
+ def HTTP.fetch_page_post( url, params, headers=nil, follow=10 )
130
+ begin
131
+ p_url = HTTP.parse_uri( url )
132
+ return nil, url if p_url.host == nil || p_url.port == nil || p_url.request_uri == nil
133
+ proxy_host, proxy_port, proxy_user, proxy_pass = HTTP.get_url_proxy_settings( url )
134
+
135
+ data, full_headers = URLEncodedFormData.prepare_query( params )
136
+ full_headers["User-Agent"] = @@user_agent
137
+ full_headers["Referer"] = "#{p_url.scheme}://#{p_url.host}"
138
+ full_headers.merge!( headers ) if headers
139
+
140
+ http = Net::HTTP.new( p_url.host, p_url.port, proxy_host, proxy_port, proxy_user, proxy_pass )
141
+ response = http.request_post( p_url.request_uri, data, full_headers )
142
+
143
+ case response
144
+ when Net::HTTPSuccess
145
+ when Net::HTTPRedirection, Net::HTTPFound
146
+ if follow == 0
147
+ response = nil
148
+ elsif follow > 0
149
+ response, url = HTTP.fetch_page_get( response["location"], nil, follow-1 )
150
+ end
151
+ else
152
+ response = nil
153
+ end
154
+
155
+ return response, url
156
+
157
+ rescue Errno::ETIMEDOUT, Errno::EBADF, EOFError => e
158
+ raise TimeoutError.new( e.to_s )
159
+ end
160
+ end
161
+
162
+ def HTTP.fetch_page_post_form_multipart( url, params, headers=nil, follow=10 )
163
+ begin
164
+
165
+ p_url = HTTP.parse_uri( url )
166
+ return nil, url if p_url.host == nil || p_url.port == nil || p_url.request_uri == nil
167
+ proxy_host, proxy_port, proxy_user, proxy_pass = HTTP.get_url_proxy_settings( url )
168
+
169
+ data, full_headers = MultipartFormData.prepare_query( params )
170
+ full_headers["User-Agent"] = @@user_agent
171
+ full_headers["Referer"] = "#{p_url.scheme}://#{p_url.host}"
172
+ full_headers.merge!( headers ) if headers
173
+
174
+ http = Net::HTTP.new( p_url.host, p_url.port, proxy_host, proxy_port, proxy_user, proxy_pass )
175
+ response = http.request_post( p_url.request_uri, data, full_headers )
176
+
177
+ case response
178
+ when Net::HTTPSuccess
179
+ when Net::HTTPRedirection, Net::HTTPFound
180
+ if follow == 0
181
+ response = nil
182
+ elsif follow > 0
183
+ response, url = HTTP.fetch_page_get( response["location"], nil, follow-1 )
184
+ end
185
+ else
186
+ response = nil
187
+ end
188
+
189
+ return response, url
190
+
191
+ rescue Errno::ETIMEDOUT, Errno::EBADF, EOFError => e
192
+ raise TimeoutError.new( e.to_s )
193
+ end
194
+ end
195
+
196
+ end
197
+
198
+