narf 0.5.1 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/ChangeLog +44 -0
  2. data/README +6 -2
  3. data/README~ +124 -0
  4. data/build.rb +3 -2
  5. data/build.rb~ +1 -1
  6. data/doc/apache_cgi.txt +1 -5
  7. data/doc/apache_cgi.txt~ +17 -0
  8. data/doc/fastcgi.txt +1 -1
  9. data/doc/fastcgi.txt~ +19 -0
  10. data/doc/rdoc/classes/Web.html +9 -6
  11. data/doc/rdoc/classes/Web.src/M000002.html +1 -1
  12. data/doc/rdoc/classes/Web.src/M000003.html +1 -1
  13. data/doc/rdoc/classes/Web.src/M000004.html +1 -1
  14. data/doc/rdoc/classes/Web.src/M000005.html +1 -1
  15. data/doc/rdoc/classes/Web.src/M000006.html +1 -1
  16. data/doc/rdoc/classes/Web.src/M000007.html +1 -1
  17. data/doc/rdoc/classes/Web.src/M000008.html +1 -1
  18. data/doc/rdoc/classes/Web.src/M000009.html +1 -1
  19. data/doc/rdoc/classes/Web/CGD.src/M000038.html +2 -1
  20. data/doc/rdoc/classes/Web/CGD.src/M000039.html +1 -1
  21. data/doc/rdoc/classes/Web/CGD.src/M000040.html +1 -1
  22. data/doc/rdoc/classes/Web/CGD.src/M000041.html +1 -1
  23. data/doc/rdoc/classes/Web/CGI.src/M000105.html +1 -1
  24. data/doc/rdoc/classes/Web/CGI.src/M000106.html +1 -1
  25. data/doc/rdoc/classes/Web/CGI.src/M000107.html +1 -1
  26. data/doc/rdoc/classes/Web/Narflates.html +4 -2
  27. data/doc/rdoc/classes/Web/Testing.src/M000027.html +1 -4
  28. data/doc/rdoc/classes/Web/Testing.src/M000028.html +1 -2
  29. data/doc/rdoc/classes/Web/Testing.src/M000029.html +1 -1
  30. data/doc/rdoc/classes/Web/Testing.src/M000030.html +1 -1
  31. data/doc/rdoc/classes/Web/Testing.src/M000031.html +1 -1
  32. data/doc/rdoc/classes/Web/Testing.src/M000032.html +1 -1
  33. data/doc/rdoc/classes/Web/Testing.src/M000033.html +1 -1
  34. data/doc/rdoc/classes/Web/Testing.src/M000034.html +1 -1
  35. data/doc/rdoc/classes/Web/Testing.src/M000035.html +1 -1
  36. data/doc/rdoc/classes/Web/Testing.src/M000036.html +1 -1
  37. data/doc/rdoc/created.rid +1 -1
  38. data/doc/rdoc/files/README.html +7 -3
  39. data/doc/rdoc/files/doc/apache_cgi_txt.html +3 -9
  40. data/doc/rdoc/files/doc/fastcgi_txt.html +2 -2
  41. data/doc/rdoc/files/lib/web/cgi_rb.html +1 -1
  42. data/doc/rdoc/files/lib/web/parser_rb.html +1 -1
  43. data/doc/rdoc/files/lib/web/template_rb.html +1 -1
  44. data/doc/rdoc/files/lib/web/testing_rb.html +1 -1
  45. data/doc/rdoc/files/lib/web/wiki_rb.html +1 -1
  46. data/doc/rdoc/files/lib/web_rb.html +1 -1
  47. data/lib/web.rb +127 -20
  48. data/lib/web/parser.rb +25 -7
  49. data/lib/web/parser.rb~ +30 -8
  50. data/lib/web/template.rb +6 -4
  51. data/lib/web/wiki.rb +23 -12
  52. data/lib/web/wiki.rb~ +1 -1
  53. data/narf-0.5.1.gem +0 -0
  54. data/narf.gemspec +1 -1
  55. data/narf.gemspec~ +18 -30
  56. data/test/test.request.rb +33 -20
  57. data/test/test.request.rb~ +10 -0
  58. data/test/testfiles/mac_ie_env.yaml +32 -0
  59. data/test/testfiles/mac_ie_stdin.bin +0 -0
  60. data/test/testfiles/mac_safari_stdin.bin +0 -0
  61. data/test/wiki/test.tarpit.rb +16 -0
  62. data/test/wiki/test.tarpit.rb~ +40 -0
  63. metadata +9 -3
  64. data/vandals.test.txt +0 -3
@@ -5,7 +5,7 @@ module Web
5
5
  #
6
6
  # this hash is has case insensitive keys. Might be somewhat
7
7
  # incomplete
8
- class CaseInsensitiveHash < Hash
8
+ class CaseInsensitiveHash < Hash #:nodoc:
9
9
  def [](key)
10
10
  super( key.to_s.downcase )
11
11
  end
@@ -189,20 +189,32 @@ module Web
189
189
  raise EOFError, "no content body"
190
190
  end
191
191
 
192
+ # ok... so what the hell does this do?
193
+ # I promise never to denigrate the accomplishments
194
+ # of my predecessors again :-)
195
+ # ~ pat
192
196
  until -1 == content_length
193
197
  head = nil
194
198
  body = Tempfile.new("Web")
195
199
  body.binmode
196
200
 
201
+ # until we have:
202
+ # * a header
203
+ # * and a buffer that has a boundary
204
+ # so far, make sense to me.
197
205
  until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
198
-
206
+ # if we have a header....
199
207
  if head
208
+ # !??!??!?!?!
200
209
  trim_size = (EOL + boundary + EOL).size
201
210
  if trim_size < buf.size
202
211
  body.print buf[0 ... (buf.size - trim_size)]
203
212
  buf[0 ... (buf.size - trim_size)] = ""
204
213
  end
214
+
215
+ # If we have a double space (the smell of a header...)
205
216
  elsif /#{EOL}#{EOL}/n.match(buf)
217
+ # extract the header, and erase it from the buffer
206
218
  buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
207
219
  head = $1.dup
208
220
  ""
@@ -210,18 +222,18 @@ module Web
210
222
  next
211
223
  end
212
224
 
225
+ # read a chunk from the input
213
226
  c = if bufsize < content_length
214
227
  input.read(bufsize) or ''
215
228
  else
216
229
  input.read(content_length) or ''
217
230
  end
231
+ # add it to the input, reduce our countdown
218
232
  buf.concat c
219
233
  content_length -= c.size
220
-
221
234
  end
222
235
 
223
-
224
- /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
236
+ /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
225
237
  filename = ($1 or "").dup
226
238
  if /Mac/ni.match(env['http_user_agent']) and
227
239
  /Mozilla/ni.match(env['http_user_agent']) and
@@ -232,7 +244,9 @@ module Web
232
244
  /Content-Type: (.*)/ni.match(head)
233
245
  content_type = ($1 or "").strip
234
246
 
235
- buf = buf.sub(/\A((?:.|\n)*?)(?:#{EOL})?#{boundary}(#{EOL}|--)/n) do
247
+ # is this the part that is eating too much?
248
+ #buf = buf.sub(/\A(.*?)(?:#{EOL})?#{boundary}(#{EOL}|--)/mn) do
249
+ buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{boundary}([\r\n]{1,2}|--)/n) do
236
250
  body.print $1
237
251
  if "--" == $2
238
252
  content_length = -1
@@ -241,7 +255,8 @@ module Web
241
255
  end
242
256
 
243
257
  body.rewind
244
-
258
+
259
+
245
260
  if (content_type.empty?)
246
261
  upload = body.read
247
262
  else
@@ -250,7 +265,14 @@ module Web
250
265
 
251
266
  /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
252
267
  name = $1.dup
253
-
268
+
269
+
270
+ File.open( "/Users/patsplat/Desktop/test.#{name}", "w" ) {|f|
271
+ f.write body.read
272
+ }
273
+
274
+ body.rewind
275
+
254
276
  if params.has_key?(name)
255
277
  params[name].push(upload)
256
278
  else
@@ -154,14 +154,16 @@ module Web
154
154
  # the template merged with values:
155
155
  #
156
156
  # --- script.rb:
157
- # Web.print_template "mytemplate.html",
158
- # "field1" => "val1",
159
- # "field2" => "val2",
160
- # "field3" => "val3",
157
+ # Web::process do
158
+ # Web.print_template "mytemplate.html",
159
+ # "field1" => "val1",
160
+ # "field2" => "val2",
161
+ # "field3" => "val3",
161
162
  # "field4" => "3",
162
163
  # "values" => [{ "name" => "one", "value" => "1"},
163
164
  # { "name" => "two", "value" => "2"},
164
165
  # { "name' => "three", "value" => "3"}]
166
+ # end
165
167
  #
166
168
  # --- mytemplate.html:
167
169
  # <narf:input type="text" name="field1">
@@ -4,6 +4,7 @@ require 'web/wiki/page'
4
4
  require 'yaml'
5
5
  require 'ftools'
6
6
  require 'strscan'
7
+ require 'ipaddr'
7
8
 
8
9
  module Web
9
10
  # == Purpose
@@ -107,9 +108,7 @@ module Web
107
108
  @@wiki ||= Wiki.new
108
109
  end
109
110
 
110
- # This is a deadly method, only use on a test wiki.
111
111
  def Wiki.wipe #:nodoc:
112
- wiki.wipe
113
112
  @@wiki = nil
114
113
  end
115
114
 
@@ -242,8 +241,9 @@ module Web
242
241
  }
243
242
  end
244
243
 
244
+
245
245
  def store_basedir
246
- if ( vandals.include?(ENV["REMOTE_ADDR"]) )
246
+ if ( vandal? )
247
247
  Wiki.pref( "tarpit_dir" )
248
248
  else
249
249
  Wiki.pref( "store_dir" )
@@ -268,17 +268,28 @@ module Web
268
268
  store_basedir
269
269
  end
270
270
  end
271
+
272
+ def vandal?
273
+ vandal = false
274
+ vandals.each do |pattern|
275
+ if pattern =~ ENV["REMOTE_ADDR"]
276
+ vandal = true
277
+ break
278
+ end
279
+ end
280
+ vandal
281
+ end
271
282
 
272
283
  def vandals
273
- if File.exists?( Wiki.pref("vandals") || "" )
274
- File.open( Wiki.pref("vandals") ) { |f|
275
- f.to_a
276
- }.collect{ |line|
277
- line.chomp
278
- }
279
- else
280
- [ ]
281
- end
284
+ @vandals ||= if File.exists?( Wiki.pref("vandals") || "" )
285
+ File.open( Wiki.pref("vandals") ) { |f|
286
+ f.to_a
287
+ }.collect{ |line|
288
+ /^#{line.chomp.strip.gsub(/"/, '')}/
289
+ }
290
+ else
291
+ [ ]
292
+ end
282
293
  end
283
294
 
284
295
  def exit_handler
@@ -317,7 +317,7 @@ module Web
317
317
  def initialize( wiki )
318
318
  @handled = false
319
319
  @wiki = wiki
320
- @template = if (File.basename(Web.get_cgi.script_name) == "admin.rb")
320
+ @template = if (File.basename(Web.script_name) == "admin.rb")
321
321
  "admin.html"
322
322
  else
323
323
  "template.html"
Binary file
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  spec = Gem::Specification.new do |s|
4
4
  #### Basic information.
5
5
  s.name = 'narf'
6
- s.version = "0.5.1"
6
+ s.version = "0.6.1"
7
7
  s.summary = <<-EOF
8
8
  NARF is a replacement for and derivative of the Ruby CGI library. It exists to trivialize web development .
9
9
  EOF
@@ -1,52 +1,40 @@
1
1
  require 'rubygems'
2
2
 
3
3
  spec = Gem::Specification.new do |s|
4
-
5
4
  #### Basic information.
6
-
7
- s.name = 'rmagic'
8
- s.version = "0.3.2"
5
+ s.name = 'narf'
6
+ s.version = "0.5.1"
9
7
  s.summary = <<-EOF
10
- RMagic demonstrates some of the magical things that Ruby can do. It includes
11
- a library and a demonstration application (rmagic-app).
12
- EOF
8
+ NARF is a replacement for and derivative of the Ruby CGI library. It exists to trivialize web development .
9
+ EOF
13
10
  s.description = <<-EOF
14
- RMagic tries to demonstrate all aspects of a gem specification. In practice,
15
- you will only need some of them. Few gems contain applications, and even fewer
16
- contain native (C code) extensions.
17
- EOF
11
+ These are the basic goals of narf:
18
12
 
19
- #### Dependencies and requirements.
13
+ * To provide a clean API for basic Web application functionality.
14
+ * To make it easy, really easy to write testable Web applications.
15
+ * To run everywhere
20
16
 
21
- s.add_dependency('log4r', '> 1.0.4')
22
- s.requirements << "A decent graphics card and monitor."
17
+ EOF
23
18
 
24
19
  #### Which files are to be included in this gem? Everything! (Except CVS directories.)
25
-
26
- s.files = Dir.glob("**/*").delete_if { |item| item.include?("CVS") }
27
-
28
- #### C code extensions.
29
-
30
- s.extensions << "ext/rmagic/extconf.rb"
20
+ s.files = Dir.glob("**/*").delete_if { |item|
21
+ item.include?("CVS") || item.include?("svn")
22
+ }
31
23
 
32
24
  #### Load-time details: library and application (you will need one or both).
33
25
 
34
26
  s.require_path = 'lib' # Use these for libraries.
35
- s.autorequire = 'rmagic'
36
-
37
- s.bindir = "bin" # Use these for applications.
38
- s.executables = ["rmagic-app"]
39
- s.default_executable = "rmagic-app"
27
+ s.autorequire = 'web'
40
28
 
41
29
  #### Documentation and testing.
42
30
 
43
31
  s.has_rdoc = true
44
- s.test_suite_file = "test/rmagic-tests.rb"
32
+ #s.test_suite_file = "build.rb test"
45
33
 
46
34
  #### Author and project details.
47
35
 
48
- s.author = "Ruby J. User"
49
- s.email = "rubyuser@yahoo.com"
50
- s.homepage = "http://rmagic.rubyforge.org"
51
- s.rubyforge_project = "rmagic"
36
+ s.author = "Patrick May"
37
+ s.email = "narf@hexane.org"
38
+ s.homepage = "http://www.narf-lib.org"
39
+ s.rubyforge_project = "narf"
52
40
  end
@@ -256,28 +256,41 @@ class TestRequest < Test::Unit::TestCase
256
256
 
257
257
  end
258
258
 
259
- #-------------------------------------------------------
260
- # I've been unable to get this test to work right.
261
- # For some reason, the code inside Request.parse
262
- # can't see the MOD_RUBY constant I'm trying to set.
263
- #
264
- # Tracing statements have shown that the
265
- # if(defined?MOD_RUBY) in Request.parse returns false
266
- # but if(defined?MOD_RUBY) returns true within the
267
- # test's scope.
268
- #-------------------------------------------------------
269
- # def test_parse_get_with_mod_ruby
270
- # Object.const_set( :MOD_RUBY, true )
271
- # assert_equal( {"key" => ["some value"], "anotherKey" => ["someother value"]},
272
- # Web::Request.parse )
273
- # end
259
+ def options
260
+ {}
261
+ end
274
262
 
275
- # this test added so I can test the effect of above apart from the cause
276
- #def test_mod_ruby_query_string
277
- # assert_equal( "key=some%20value&anotherKey=someother%20value",
278
- # Web::CGD.mod_ruby_query_string )
279
- # end
263
+ def test_mac_ie_multipart_bug
264
+ require 'yaml'
265
+ test_env = nil
266
+ File.open("test/testfiles/mac_ie_env.yaml", "r") { |f|
267
+ test_env = YAML.load(f)
268
+ }
280
269
 
270
+ backup_env = {}
271
+ test_env.each{ |k,v|
272
+ backup_env[k.downcase] = ENV[k.downcase]
273
+ ENV[k.downcase] = v
274
+ }
275
+
276
+ begin
277
+ File.open("test/testfiles/mac_ie_stdin.bin", "r") { |f|
278
+ $stdin = f
279
+
280
+ parse_request
281
+
282
+ assert_equal "test", @multiple_params["text"].first
283
+ assert_equal Web::Upload, @multiple_params["small"].first.class
284
+ assert_equal 15, @multiple_params["button.x"].first.to_i
285
+ assert_equal 11, @multiple_params["button.y"].first.to_i
286
+ }
287
+ ensure
288
+ backup_env.each{ |k,v|
289
+ ENV[k] = v
290
+ }
291
+ end
292
+
293
+ end
281
294
  end
282
295
 
283
296
  class TestUpload < Test::Unit::TestCase
@@ -246,6 +246,16 @@ class TestRequest < Test::Unit::TestCase
246
246
 
247
247
  end
248
248
 
249
+ def test_downcase_env
250
+ ENV["KEY"] = "value"
251
+ env = downcase_env( ENV )
252
+ ["key", "kEy", "kEY", "KEY", "KEy", "Key", "keY"].each{ |k|
253
+ assert( env.has_key?(k) )
254
+ assert_equal( "value", env[k] )
255
+ }
256
+
257
+ end
258
+
249
259
  #-------------------------------------------------------
250
260
  # I've been unable to get this test to work right.
251
261
  # For some reason, the code inside Request.parse
@@ -0,0 +1,32 @@
1
+ ---
2
+ SERVER_NAME: 127.0.0.1
3
+ HTTP_UA_OS: MacOS
4
+ HTTP_USER_AGENT: Mozilla/4.0 (compatible; MSIE 5.22; Mac_PowerPC)
5
+ HTTP_EXTENSION: Security/Remote-Passphrase
6
+ CONTENT_LENGTH: "2134"
7
+ "__CF_USER_TEXT_ENCODING": 0x46:0:0
8
+ SCRIPT_NAME: "/~patsplat/fhwang.rb"
9
+ SERVER_PROTOCOL: HTTP/1.1
10
+ SERVER_ADDR: 192.168.1.101
11
+ HTTP_HOST: localhost
12
+ HTTP_ACCEPT_LANGUAGE: en
13
+ SERVER_SOFTWARE: Apache/1.3.29 (Darwin)
14
+ REMOTE_ADDR: 192.168.1.101
15
+ HTTP_REFERER: http://localhost/~patsplat/form.html
16
+ CONTENT_TYPE: multipart/form-data; boundary=---------------------------047485629054451
17
+ HTTP_UA_CPU: PPC
18
+ HTTP_COOKIE: "_session_id=57c6e5950b4fceab"
19
+ REQUEST_URI: "/~patsplat/fhwang.rb"
20
+ SERVER_SIGNATURE: "<ADDRESS>Apache/1.3.29 Server at 127.0.0.1 Port 80</ADDRESS>\n"
21
+ DOCUMENT_ROOT: "/Library/WebServer/Documents"
22
+ SERVER_PORT: "80"
23
+ QUERY_STRING: ''
24
+ GATEWAY_INTERFACE: CGI/1.1
25
+ SERVER_ADMIN: "[no address given]"
26
+ REMOTE_PORT: "49176"
27
+ HTTP_PRAGMA: no-cache
28
+ SCRIPT_FILENAME: "/Users/patsplat/Sites/fhwang.rb"
29
+ PATH: "/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/System/Library/CoreServices"
30
+ HTTP_ACCEPT: "*/*"
31
+ REQUEST_METHOD: POST
32
+ HTTP_CONNECTION: Keep-Alive
@@ -11,6 +11,7 @@ class TestTarpit < Test::Unit::TestCase
11
11
  def teardown
12
12
  teardown_wiki
13
13
  ENV["REMOTE_ADDR"] = @old_remote_addr
14
+ File.delete("vandals.test.txt") if File.exists? "vandals.test.txt"
14
15
  end
15
16
 
16
17
  def do_edit( name, content )
@@ -37,4 +38,19 @@ class TestTarpit < Test::Unit::TestCase
37
38
  Web::Wiki.store_dir )
38
39
  end
39
40
 
41
+ def test_ip_range
42
+ File.open( "vandals.test.txt", "w" ) { |f|
43
+ f.puts( "123.51", "23.17.49", "88.34.23.9")
44
+ }
45
+
46
+ assert_equal( make_temp("test.pages/"),
47
+ Web::Wiki::store_dir )
48
+
49
+ ["123.51.27.13", "23.17.49.2", "88.34.23.9"].each{ |ip|
50
+ ENV["REMOTE_ADDR"] = ip
51
+ assert_equal( make_temp("tarpit/"),
52
+ Web::Wiki.store_dir )
53
+ }
54
+ end
55
+
40
56
  end
@@ -0,0 +1,40 @@
1
+ require 'web/wiki'
2
+
3
+ class TestTarpit < Test::Unit::TestCase
4
+ include Web::Testing
5
+
6
+ def setup
7
+ @old_remote_addr = ENV["REMOTE_ADDR"]
8
+ setup_wiki
9
+ end
10
+
11
+ def teardown
12
+ teardown_wiki
13
+ ENV["REMOTE_ADDR"] = @old_remote_addr
14
+ end
15
+
16
+ def do_edit( name, content )
17
+ do_request "wiki.rb", "action" => "edit", "page.name" => name
18
+ do_submit "edit_page", "page.content" => content, "action" => "Save"
19
+ end
20
+
21
+ def test_page_revisions_store_remote_addr
22
+ page = Web::Wiki.wiki.load_page( "HomePage" )
23
+ assert_equal( "auto-create", page.remote_addr )
24
+
25
+ ENV["REMOTE_ADDR"] = "127.0.0.1"
26
+ do_edit( "HomePage", "this is a test" )
27
+ page = Web::Wiki.wiki.load_page( "HomePage" )
28
+ assert_equal( "127.0.0.1", page.remote_addr )
29
+ end
30
+
31
+ def test_tarpit
32
+ File.open( "vandals.test.txt", "w" ) { |f|
33
+ f.puts( "123.51.23.192", "127.0.0.1", "52.213.123.65" )
34
+ }
35
+ ENV["REMOTE_ADDR"] = "127.0.0.1"
36
+ assert_equal( make_temp("tarpit/"),
37
+ Web::Wiki.store_dir )
38
+ end
39
+
40
+ end