Wiki2Go 1.17.5 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/bin/Wiki2Go_firewall_blacklist.rb +8 -0
  2. data/bin/Wiki2Go_make_cvs_repository.rb +1 -0
  3. data/bin/Wiki2Go_make_site.rb +1 -2
  4. data/bin/Wiki2Go_update_site.rb +1 -2
  5. data/lib/Web2Go/CGIRequest.rb +8 -2
  6. data/lib/Web2Go/CGIResponse.rb +17 -14
  7. data/lib/Web2Go/MockRequest.rb +12 -2
  8. data/lib/Web2Go/MockResponse.rb +10 -7
  9. data/lib/Web2Go/WebrickRequest.rb +106 -101
  10. data/lib/Web2Go/WebrickResponse.rb +4 -8
  11. data/lib/Wiki2Go/BlackList.rb +48 -25
  12. data/lib/Wiki2Go/DotGraphics.rb +1 -1
  13. data/lib/Wiki2Go/FileStorage.rb +266 -266
  14. data/lib/Wiki2Go/HTMLFormatter.rb +28 -0
  15. data/lib/Wiki2Go/Install/config/chonqed_blacklist.txt +418 -0
  16. data/lib/Wiki2Go/Install/config/passwords +1 -1
  17. data/lib/Wiki2Go/Install/config/url_blacklist.txt +3855 -0
  18. data/lib/Wiki2Go/Install/make_repository.rb +32 -26
  19. data/lib/Wiki2Go/Install/make_site.rb +197 -111
  20. data/lib/Wiki2Go/Install/site/error.html +1 -1
  21. data/lib/Wiki2Go/Install/site/robots.txt +10 -1
  22. data/lib/Wiki2Go/Install/site/style.css +129 -64
  23. data/lib/Wiki2Go/Install/templates/admin.htm +1 -1
  24. data/lib/Wiki2Go/Install/templates/admin_pages/edit.txt +2 -1
  25. data/lib/Wiki2Go/Install/templates/admin_pages/format_for_fck.txt +31 -0
  26. data/lib/Wiki2Go/Install/templates/admin_pages/passwords.txt +1 -1
  27. data/lib/Wiki2Go/Install/templates/edit.htm +62 -46
  28. data/lib/Wiki2Go/Install/templates/full_footer.htm +31 -33
  29. data/lib/Wiki2Go/Install/templates/header.htm +0 -1
  30. data/lib/Wiki2Go/Install/templates/menu.htm +29 -0
  31. data/lib/Wiki2Go/Install/templates/pagelist.htm +46 -43
  32. data/lib/Wiki2Go/Install/templates/simple_footer.htm +20 -16
  33. data/lib/Wiki2Go/Install/templates/versionlist.htm +52 -40
  34. data/lib/Wiki2Go/Install/templates/view.htm +46 -29
  35. data/lib/Wiki2Go/Install/templates/wikiedit.htm +63 -0
  36. data/lib/Wiki2Go/Install/wiki/delete.png +0 -0
  37. data/lib/Wiki2Go/Install/wiki/style.css +133 -63
  38. data/lib/Wiki2Go/LineFormatter.rb +345 -197
  39. data/lib/Wiki2Go/Page.rb +16 -3
  40. data/lib/Wiki2Go/PrivateWikiConfig.rb +5 -5
  41. data/lib/Wiki2Go/PublicWikiConfig.rb +83 -37
  42. data/lib/Wiki2Go/ReadWriteWikiConfig.rb +8 -8
  43. data/lib/Wiki2Go/Server.rb +6 -1
  44. data/lib/Wiki2Go/SpamFilter.rb +32 -41
  45. data/lib/Wiki2Go/Web.rb +10 -3
  46. data/lib/Wiki2Go/Wiki2Go.rb +301 -94
  47. data/lib/Wiki2Go/Wiki2GoConfig.rb +87 -6
  48. data/lib/Wiki2Go/Wiki2GoServlet.rb +66 -12
  49. data/lib/Wiki2Go/WikiFormatter.rb +60 -30
  50. data/lib/Wiki2Go/cgi/diff.rb +20 -0
  51. data/lib/Wiki2Go/cgi/secure/log_rss.rb +21 -0
  52. data/lib/Wiki2Go/cgi/sidebyside.rb +20 -0
  53. data/lib/Wiki2Go/cgi/wikiedit.rb +20 -0
  54. data/lib/Wiki2Go/firewall_blacklist.rb +88 -0
  55. data/test/All.rb +5 -2
  56. data/test/TestBlackList.rb +70 -14
  57. data/test/TestConfig.rb +5 -5
  58. data/test/TestDiff.rb +95 -0
  59. data/test/TestFormatter.rb +14 -16
  60. data/test/TestHTMLFormatter.rb +37 -0
  61. data/test/TestInstall.rb +70 -27
  62. data/test/TestLineFormatter.rb +71 -15
  63. data/test/TestRSS.rb +8 -7
  64. data/test/TestRepository.rb +50 -0
  65. data/test/TestServer.rb +3 -8
  66. data/test/TestSpamFilter.rb +33 -1
  67. data/test/TestStorage.rb +11 -0
  68. data/test/TestWeb.rb +2 -2
  69. data/test/TestWiki2Go.rb +766 -166
  70. data/test/TestWiki2GoServlet.rb +1122 -524
  71. data/test/UnitTestFiles.rb +7 -3
  72. data/test/Wiki2GoConfigForTest.rb +40 -6
  73. data/test/checksite.rb +17 -50
  74. data/test/test_firewall_blacklist.rb +131 -0
  75. data/test/test_page.rb +45 -0
  76. data/test/testdata/Registration.rbl.txt +7 -0
  77. data/test/testdata/config/url_blacklist.txt +38822 -0
  78. data/test/testdata/expected_changes.html +1 -2
  79. data/test/testdata/expected_edit.html +108 -59
  80. data/test/testdata/expected_full_rss.xml +2 -2
  81. data/test/testdata/expected_out.html +97 -61
  82. data/test/testdata/expected_put.html +88 -53
  83. data/test/testdata/expected_save.html +88 -52
  84. data/test/testdata/expected_savehtml.html +88 -52
  85. data/test/testdata/expected_search.html +68 -53
  86. data/test/testdata/expected_upload.html +88 -53
  87. data/test/testdata/expected_versions.html +97 -82
  88. data/test/testdata/expected_view.html +97 -61
  89. data/test/testdata/firewall/iptables.config +37 -0
  90. data/test/testdata/firewall/user_blacklist.txt +162 -0
  91. data/test/testdata/logs/wiki.log +652 -0
  92. data/test/testdata/logs/wiki.log.0 +113 -0
  93. data/test/testdata/logs/wiki.log.1 +113 -0
  94. data/test/testdata/logs/wiki.log.2 +113 -0
  95. data/test/testdata/logs/wiki.log.3 +115 -0
  96. data/test/testdata/logs/wiki.log.4 +5 -0
  97. data/test/testdata/logs/wiki.log.5 +7 -0
  98. data/test/testdata/logs/wiki.log.6 +5 -0
  99. data/test/testdata/logs/wiki.log.7 +118 -0
  100. data/test/testdata/logs/wiki.log.8 +12 -0
  101. data/test/testdata/site/html/Xpday/rss.xml +53 -103
  102. data/test/testdata/texts/Bugs/FrontPage.txt +6 -0
  103. data/test/testdata/texts/Bugs/NoHidden.spam +17850 -0
  104. data/test/testdata/texts/Bugs/PairProgrammingParties.spam +102 -0
  105. data/test/testdata/texts/Bugs/PairProgrammingParties.txt +99 -0
  106. metadata +53 -7
  107. data/test/TestMail.rb +0 -29
  108. data/test/gc.log +0 -2
data/lib/Wiki2Go/Page.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "digest/sha2"
2
+
1
3
  module Wiki2Go
2
4
 
3
5
  # Represents one page in the Wiki
@@ -6,7 +8,7 @@ module Wiki2Go
6
8
  # Name of the file
7
9
  attr_reader :filename
8
10
  # Descriptive name given by author
9
- attr_reader :name
11
+ attr_accessor :name
10
12
  # Real author (if authenticated) or IP/DNS address
11
13
  attr_accessor :author
12
14
  # Authorname given by author
@@ -35,7 +37,7 @@ module Wiki2Go
35
37
  @lines = lines
36
38
  end
37
39
  @lastmodified = time
38
- @created_on = time
40
+ @created_on = time
39
41
 
40
42
  @author = author
41
43
  @alias = aliasname || author
@@ -91,9 +93,15 @@ module Wiki2Go
91
93
 
92
94
  # Content as a String
93
95
  def content
94
- return @lines.join
96
+ return @lines.join($/)
95
97
  end
96
98
 
99
+ # Checksum based on content, author, document name and author alias
100
+ # Returns String with hex digest
101
+ def checksum(salt="")
102
+ Digest::SHA256.hexdigest("#{salt}#{content}--#{author}--#{name}--#{self.alias}")
103
+ end
104
+
97
105
  # DEPRECATED use filename instead
98
106
  def title
99
107
  @filename
@@ -104,6 +112,11 @@ module Wiki2Go
104
112
  @filename = name
105
113
  end
106
114
 
115
+ # Does this page contain dynamic (Rublet) content?
116
+ def is_dynamic?
117
+ Page.is_dynamic?(@filename)
118
+ end
119
+
107
120
  # Does filename indicate that page should be executed (Rublet)?
108
121
  def Page.is_dynamic?(pagename)
109
122
  pagename =~ /\.rbl$/
@@ -38,10 +38,10 @@ module Wiki2Go
38
38
  end
39
39
  end
40
40
 
41
- class PrivateWikiConfig < Wiki2Go::PrivateWikiConfig
42
- def initialize(directory)
43
- super(directory)
44
- end
45
- end
41
+ #class PrivateWikiConfig < Wiki2Go::PrivateWikiConfig
42
+ #def initialize(directory)
43
+ #super(directory)
44
+ #end
45
+ #end
46
46
 
47
47
 
@@ -8,86 +8,132 @@ require 'Wiki2Go/SpamFilter'
8
8
  module Wiki2Go
9
9
  # Base class for public wiki
10
10
  class PublicWikiConfig < Wiki2Go::Config
11
-
11
+
12
12
  # Initialize with root directory of wiki
13
- # By default, generates HTML
13
+ # By default, generates HTML and filters SPAM
14
14
  def initialize(directory)
15
15
  super(directory)
16
16
  @generate_html = true
17
+ @delete_spam = true
17
18
  @spamfilter = Wiki2Go::SpamFilter.new(self)
18
-
19
19
  end
20
-
20
+
21
+ # Accept a call from the user if they are not blacklisted
22
+ def accept_user?(web)
23
+ return true if web.secure?
24
+
25
+ author = web.user
26
+ pagename = web.name.length > 0 ? "#{web.name}/#{web.current_page}" : web.current_page
27
+ if @spamfilter.edit_by_banned_user?(author) then
28
+ log("User #{author} is blacklisted while editing '#{pagename}'.")
29
+ return false
30
+ end
31
+ return true
32
+ end
33
+
34
+ # Add the spammer IP address to the blacklist
35
+ def blacklist_user(spammer)
36
+ @spamfilter.blacklist_user(spammer)
37
+ end
38
+
21
39
  # Accept a page save if
22
40
  # * The edit is by an authenticated user
23
41
  # * OR the user is not on the blacklist and none of the URLs on the page are on the blacklist and no more than 5 urls added
42
+ # * AND no hidden style in tags
43
+ # * AND page not erased
24
44
  def accept_page?(web,content)
25
-
26
- return true if web.secure
27
-
28
- author = web.user
29
-
45
+
46
+ return true if web.secure?
47
+
48
+ author = web.user
49
+ pagename = web.name.length > 0 ? "#{web.name}/#{web.current_page}" : web.current_page
50
+
51
+ if @spamfilter.hidden_text_in(content) then
52
+ blacklist_user(author)
53
+
54
+ log(content)
55
+ errorlog("User used hidden style in tags of '#{pagename}': Blacklisted user #{author}")
56
+
57
+ tarpit
58
+ return false
59
+ elsif @spamfilter.cleared_page?(content) then
60
+ @spamfilter.greylist_urls(author,[])
61
+ log(content)
62
+ errorlog("User erased page '#{pagename}': Greylisted user #{author}")
63
+
64
+ tarpit
65
+ return false
66
+ elsif @spamfilter.empty_urls_in(content) then
67
+ blacklist_user(author)
68
+
69
+ log(content)
70
+ errorlog("User used empty URL hrefs in '#{pagename}': Blacklisted user #{author}")
71
+
72
+ tarpit
73
+ return false
74
+ end
75
+
30
76
  current_page = storage.load_page(web.name,web.current_page)
31
77
  urls = @spamfilter.added_urls(current_page.content,content)
32
-
33
- if urls.length > @maximum_urls then
34
- @spamfilter.blacklist_user(author)
78
+
79
+ if @spamfilter.edit_by_banned_user?(author) then
35
80
  @spamfilter.blacklist_urls(urls)
36
-
37
- errorlog("User added too many URLS: #{urls.length}. Blacklisted user #{author} and #{urls.join(', ')}")
38
-
39
- tarpit
81
+
82
+ log("User #{author} is blacklisted while editing '#{pagename}'. Blacklisting #{urls.join(', ')}")
83
+
84
+ # tarpit
40
85
  return false
41
- elsif @spamfilter.edit_by_banned_user?(author) then
86
+ elsif urls.length > @maximum_urls then
87
+ blacklist_user(author)
42
88
  @spamfilter.blacklist_urls(urls)
43
-
44
- errorlog("User #{author} is blacklisted. Blacklisting #{urls.join(', ')}")
45
-
89
+
90
+ errorlog("User added too many URLS to '#{pagename}': #{urls.length}. Blacklisted user #{author} and #{urls.join(', ')}")
91
+
46
92
  tarpit
47
93
  return false
48
94
  elsif urls.length >0 && @spamfilter.edit_contains_banned_url?(urls) then
49
-
50
- @spamfilter.blacklist_user(author)
95
+
96
+ blacklist_user(author)
51
97
  @spamfilter.blacklist_urls(urls)
52
-
53
- errorlog("Edit by user #{author} contains blacklisted url. Blacklisting #{urls.join(', ')}")
54
-
98
+
99
+ errorlog("Edit by user #{author} of page '#{pagename}' contains blacklisted url. Blacklisting #{urls.join(', ')}")
100
+
55
101
  tarpit
56
102
  return false
57
103
  else
58
104
  if urls.length > 0 then
59
105
  @spamfilter.greylist_urls(author,urls)
60
- errorlog("Greylisted user #{author} because of the following urls: #{urls}")
106
+ errorlog("Greylisted user #{author} while editing '#{pagename}' because of the following urls: #{urls.join(', ')}")
61
107
  end
62
108
  return true
63
109
  end
64
110
  end
65
-
111
+
66
112
  # What to do when we encounter a spammer? Delay him for 60 seconds
67
113
  def tarpit
68
114
  sleep(60)
69
115
  end
70
-
116
+
71
117
  # A public wiki is always editable
72
118
  def editable?(web)
73
119
  true
74
120
  end
75
-
121
+
76
122
  # Redirect if the url is on the greylist, unless the user is authenticated
77
123
  def redirect_url?(web,url)
78
- return false if web.secure
79
-
124
+ return false if web.secure?
125
+
80
126
  redirect = @spamfilter.greylisted_url?(url)
81
127
  log("Redirect #{url}") if redirect
82
128
  return redirect
83
129
  end
84
-
130
+
85
131
  end
86
132
  end
87
133
 
88
- class PublicWikiConfig < Wiki2Go::PublicWikiConfig
134
+ #class PublicWikiConfig < Wiki2Go::PublicWikiConfig
89
135
 
90
- def initialize(directory)
91
- super(directory)
92
- end
93
- end
136
+ #def initialize(directory)
137
+ #super(directory)
138
+ #end
139
+ #end
@@ -4,8 +4,8 @@ require "Wiki2Go/FileStorage.rb"
4
4
  require "Wiki2Go/Wiki2GoConfig.rb"
5
5
 
6
6
  module Wiki2Go
7
- # Base class for read/write wikis (authenticated users can write, everybody can read)
8
- class ReadWriteWikiConfig < Wiki2Go::Config
7
+ # Base class for read/write wikis (authenticated users can write, everybody can read)
8
+ class ReadWriteWikiConfig < Wiki2Go::Config
9
9
 
10
10
  def initialize(directory)
11
11
  super(directory)
@@ -14,7 +14,7 @@ module Wiki2Go
14
14
 
15
15
  # Wiki is editable if user is authenticated
16
16
  def editable?(web)
17
- web.secure
17
+ web.secure?
18
18
  end
19
19
 
20
20
  # Never redirect URLs, we trust our authenticated writers
@@ -25,10 +25,10 @@ module Wiki2Go
25
25
  end
26
26
  end
27
27
 
28
- class ReadWriteWikiConfig < Wiki2Go::ReadWriteWikiConfig
28
+ #class ReadWriteWikiConfig < Wiki2Go::ReadWriteWikiConfig
29
29
 
30
- def initialize(directory)
31
- super(directory)
32
- end
33
- end
30
+ #def initialize(directory)
31
+ #super(directory)
32
+ #end
33
+ #end
34
34
 
@@ -24,6 +24,7 @@ module Wiki2Go
24
24
  @generate_html = false
25
25
  @multi_wiki = true
26
26
  @debug = true
27
+ @editor = 'wikiedit'
27
28
  add_processor('GRAPH',Wiki2Go::DotGraphics.new('c:/Program Files/ATT/Graphviz/bin/'))
28
29
  enable_syntax_highlighting
29
30
  end
@@ -50,7 +51,7 @@ module Wiki2Go
50
51
  cvsroot = ''
51
52
  blogstyle = false
52
53
 
53
- opts.on("-d",'--dir <directory>','(default is current directory)',String) { |val| dir = val }
54
+ opts.on("-d",'--dir <directory>','(default is current directory)',String) { |val| dir = File.expand_path(val) }
54
55
  opts.on("-p",'--port <nb>',"(default is port 8081)",String) { |val| port = val }
55
56
  opts.on("-w",'--wiki <wikiname>',"(default is 'Wiki2Go')",String) { |val| wiki = val }
56
57
  opts.on("-s","--single","Single or multi-wiki (default)") { |val| single = true }
@@ -64,6 +65,8 @@ module Wiki2Go
64
65
  end
65
66
  opts.parse(args)
66
67
 
68
+ # TODO : read CgiOptions.rb (if present) and reuse what's available
69
+
67
70
  @config = LocalConfig.new(dir)
68
71
  @config.port = port
69
72
  @config.default_web = wiki
@@ -84,6 +87,8 @@ module Wiki2Go
84
87
  web_thread = Thread.new(@config) do |config|
85
88
  s = WEBrick::HTTPServer.new( :Port => config.port)
86
89
 
90
+ s.mount("/scripts/", WikiServlet,config)
91
+ s.mount("/scripts/secure/", WikiServlet,config)
87
92
  s.mount("/", WikiServlet,config)
88
93
 
89
94
  trap("INT"){ s.shutdown }
@@ -11,16 +11,14 @@ module Wiki2Go
11
11
  end
12
12
 
13
13
  def edit_by_banned_user?(author)
14
- @config.log("Checking if '#{author}' is banned")
15
- banned = banned_users.contains(author)
16
- @config.log("Checking if '#{author}' is banned. Done.")
14
+ banned = @config.banned_users.contains(author)
15
+ @config.log("Checking if '#{author}' is banned=> #{banned}")
17
16
  banned
18
17
  end
19
18
 
20
19
  def edit_contains_banned_url?(content)
21
- @config.log("Checking if '#{content}' is banned")
22
- banned = banned_urls.found_in(content) || chonqed_urls.found_in(content)
23
- @config.log("Checking if '#{content}' is banned. Done")
20
+ banned = @config.banned_urls.found_in(content) || @config.chonqed_urls.found_in(content)
21
+ @config.log("Checking if '#{content}' is banned => #{banned}")
24
22
  banned
25
23
  end
26
24
 
@@ -28,6 +26,12 @@ module Wiki2Go
28
26
  return added_urls(original_content,modified_content).size > max_new_urls
29
27
  end
30
28
 
29
+ # Some idiot spams the xp.be wiki with loads of <a href=" "> tags
30
+ def empty_urls_in(content)
31
+ refs = content.scan(/href="(\s+)"/)
32
+ refs.length > 0
33
+ end
34
+
31
35
  def added_urls(original_content, modified_content)
32
36
  url_finder = Wiki2Go::UrlFinder.new
33
37
 
@@ -38,27 +42,21 @@ module Wiki2Go
38
42
  end
39
43
 
40
44
  def blacklist_user(author)
41
- bad_users = banned_users
45
+ bad_users = @config.banned_users
42
46
  bad_users.add(author)
43
47
  @config.storage.save_list(bad_users)
44
48
  end
45
49
 
46
50
  def blacklist_url(url)
47
- banned_urls.add(url)
48
- @config.storage.save_list(banned_urls)
51
+ @config.banned_urls.add(url)
52
+ @config.storage.save_list(@config.banned_urls)
49
53
  end
50
54
 
51
55
  def blacklist_urls(urls)
52
56
  urls.each do |url|
53
- banned_urls.add(url)
57
+ @config.banned_urls.add(url)
54
58
  end
55
- @config.storage.save_list(banned_urls)
56
- end
57
-
58
- def blacklist_user_and_urls_added(author,original,new_content)
59
- blacklist_user(author)
60
- new_urls = added_urls(original,new_content)
61
- blacklist_urls(new_urls)
59
+ @config.storage.save_list(@config.banned_urls)
62
60
  end
63
61
 
64
62
  def greylist_new_urls(author,original,new_content)
@@ -68,7 +66,7 @@ module Wiki2Go
68
66
 
69
67
  def greylist_urls(author,new_urls)
70
68
  if new_urls.length > 0 then
71
- list = greylist
69
+ list = @config.greylist
72
70
  new_urls.each do |url|
73
71
  list.add(author,url)
74
72
  end
@@ -77,16 +75,16 @@ module Wiki2Go
77
75
  end
78
76
 
79
77
  def greylisted_url?(url)
80
- greylist.contains_url?(url)
78
+ @config.greylist.contains_url?(url)
81
79
  end
82
80
 
83
81
  def greylist_suspects
84
- greylist.suspects
82
+ @config.greylist.suspects
85
83
  end
86
84
 
87
85
  def remove_from_greylist(author,url)
88
- greylist.remove(author,url)
89
- @config.storage.save_list(greylist)
86
+ @config.greylist.remove(author,url)
87
+ @config.storage.save_list(@config.greylist)
90
88
  end
91
89
 
92
90
  def update_chongqed
@@ -100,28 +98,21 @@ module Wiki2Go
100
98
  end
101
99
  output
102
100
  end
103
-
104
- private
105
-
106
- def banned_users
107
- @banned_users ||= @config.storage.load_blacklist('user')
108
- @banned_users
109
- end
110
-
111
- def banned_urls
112
- @banned_urls ||= @config.storage.load_blacklist('url')
113
- @banned_urls
101
+
102
+ # Verify if a spammer tries to obfuscate his crap by using inline hidden styles
103
+ # content = HTML text to examine
104
+ def hidden_text_in(content)
105
+ content =~ /<(\S[^>]*style\s*=\s*"[^"]*display\s*:\s*none[^>]*)>/i
114
106
  end
115
-
116
- def chonqed_urls
117
- @chonqed_urls ||= @config.storage.load_blacklist('chonqed')
118
- @chonqed_urls
107
+
108
+ # Detect when a non-authenticated user tries to clear a page
109
+ def cleared_page?(content)
110
+ content !~ /\S/
119
111
  end
120
112
 
121
- def greylist
122
- @greylist ||= @config.storage.load_greylist
123
- @greylist
124
- end
113
+ private
114
+
115
+
125
116
 
126
117
  end
127
118
  end
data/lib/Wiki2Go/Web.rb CHANGED
@@ -53,9 +53,11 @@ module Wiki2Go
53
53
  @request.nil? ? 'unknown' : @request.user
54
54
  end
55
55
 
56
- def secure
57
- @request.nil? ? false : @request.authenticated
58
- end
56
+ def secure?
57
+ @request.nil? ? false : @request.authenticated?
58
+ end
59
+
60
+ alias :secure :secure?
59
61
 
60
62
  def alias=(name)
61
63
  @alias = name
@@ -91,6 +93,11 @@ module Wiki2Go
91
93
  File.join(@name,@current_page)
92
94
  end
93
95
  end
96
+
97
+ # The URL of the static error page
98
+ def error_page
99
+ File.join(base_url,'error.html')
100
+ end
94
101
 
95
102
  def Web.page_url(server,port,url,verb,config)
96
103
  before,verb,web,page = Web.parse_url(url,verb,config)