narf 0.5.1 → 0.6.1

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 (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