rbkb 0.6.10 → 0.6.11
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.
- data/History.txt +4 -0
- data/README.rdoc +5 -7
- data/lib/rbkb.rb +1 -1
- data/lib/rbkb/extends.rb +63 -2
- data/rbkb.gemspec +4 -4
- metadata +2 -18
- data/lib/rbkb/http.rb +0 -21
- data/lib/rbkb/http/base.rb +0 -172
- data/lib/rbkb/http/body.rb +0 -214
- data/lib/rbkb/http/common.rb +0 -74
- data/lib/rbkb/http/headers.rb +0 -370
- data/lib/rbkb/http/parameters.rb +0 -104
- data/lib/rbkb/http/request.rb +0 -58
- data/lib/rbkb/http/response.rb +0 -86
- data/test/test_http.rb +0 -27
- data/test/test_http_helper.rb +0 -60
- data/test/test_http_request.rb +0 -136
- data/test/test_http_response.rb +0 -222
data/History.txt
CHANGED
data/README.rdoc
CHANGED
@@ -17,9 +17,8 @@ related to pen-testing and reversing.
|
|
17
17
|
|
18
18
|
rbkb is inspired by Matasano BlackBag (a set of similar tools written in C).
|
19
19
|
|
20
|
-
See:
|
21
|
-
|
22
|
-
* http://www.matasano.com/log/552/code-release-blackbag-09-binary-protocol-reversing-unix-thingies/
|
20
|
+
See:
|
21
|
+
blackbag - http://github.com/emonti/rbkb/raw/master/reference/blackbag-0.9.1.tgz
|
23
22
|
|
24
23
|
Things go into the black bag as they are stolen (as a compliment!) or dreamed
|
25
24
|
up, usually for simplifying some repetetive task or a desire for a new tool.
|
@@ -81,10 +80,9 @@ your irb sessions and own scripts. See 'lib_usage.rdoc' for more info.
|
|
81
80
|
|
82
81
|
=== Gem Installation
|
83
82
|
|
84
|
-
rbkb is available as a gem
|
83
|
+
rbkb is available as a gem on gemcutter.org:
|
85
84
|
|
86
|
-
gem
|
87
|
-
gem install emonti-rbkb
|
85
|
+
gem install rbkb --source http://gemcutter.org
|
88
86
|
|
89
87
|
|
90
88
|
==== Gem Install Note
|
@@ -101,7 +99,7 @@ executable bin/* files somewhere unexpected. To find out where these are and
|
|
101
99
|
either add them to your PATH or copy/symlink them somewhere else like
|
102
100
|
/usr/local/bin/ do this:
|
103
101
|
|
104
|
-
gem contents
|
102
|
+
gem contents rbkb
|
105
103
|
|
106
104
|
|
107
105
|
=== Manual installation:
|
data/lib/rbkb.rb
CHANGED
data/lib/rbkb/extends.rb
CHANGED
@@ -19,7 +19,7 @@ end
|
|
19
19
|
# Generates a random string of 'size' bytes (8 by default)
|
20
20
|
def random_string(size = 8)
|
21
21
|
chars = (0..255).map {|c| c.chr }
|
22
|
-
(1..size).collect {|a| chars[rand(chars.size)]}
|
22
|
+
(1..size).collect {|a| chars[rand(chars.size)]}.join
|
23
23
|
end
|
24
24
|
|
25
25
|
# Simple syntactic sugar to pass any object to a block
|
@@ -194,6 +194,32 @@ class String
|
|
194
194
|
e
|
195
195
|
end
|
196
196
|
|
197
|
+
|
198
|
+
# Produces a character frequency distribution histogram in descending
|
199
|
+
# order. Example:
|
200
|
+
#
|
201
|
+
# pp some_english_text.char_frequency()
|
202
|
+
#
|
203
|
+
# [[" ", 690],
|
204
|
+
# ["e", 354],
|
205
|
+
# ["t", 242],
|
206
|
+
# ["o", 233],
|
207
|
+
# ["i", 218],
|
208
|
+
# ["a", 176],
|
209
|
+
# ["s", 172],
|
210
|
+
# ["r", 172],
|
211
|
+
# ["n", 167],
|
212
|
+
# ["d", 106],
|
213
|
+
# ...
|
214
|
+
# ]
|
215
|
+
#
|
216
|
+
def char_frequency
|
217
|
+
hits = {}
|
218
|
+
self.each_byte {|c| hits[c.chr] ||= 0; hits[c.chr] += 1 }
|
219
|
+
hits.to_a.sort {|a,b| b[1] <=> a[1] }
|
220
|
+
end
|
221
|
+
|
222
|
+
|
197
223
|
# xor against a key. key will be repeated or truncated to self.size.
|
198
224
|
def xor(k)
|
199
225
|
s=self
|
@@ -205,12 +231,30 @@ class String
|
|
205
231
|
out.string
|
206
232
|
end
|
207
233
|
|
234
|
+
|
235
|
+
# (en|de)ciphers using a substition cipher en/decoder ring in the form of a
|
236
|
+
# hash with orig => substitute mappings
|
237
|
+
def substitution(keymap)
|
238
|
+
split('').map {|c| (sub=keymap[c]) ? sub : c }.join
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
# (en|de)crypts using a substition xor en/decoder ring in the form of
|
243
|
+
# a hash with orig => substitute mappings. Used in conjunction with
|
244
|
+
# char_frequency, this sometimes provides a shorter way to derive a single
|
245
|
+
# character xor key used in conjunction with char_frequency.
|
246
|
+
def substitution_xor(keymap)
|
247
|
+
split('').map {|c| (sub=keymap[c]) ? sub.xor(c) : c }.join
|
248
|
+
end
|
249
|
+
|
250
|
+
|
208
251
|
# convert bytes to number then xor against another byte-string or number
|
209
252
|
def ^(x)
|
210
253
|
x = x.dat_to_num unless x.is_a? Numeric
|
211
254
|
(self.dat_to_num ^ x)#.to_bytes
|
212
255
|
end
|
213
256
|
|
257
|
+
|
214
258
|
# Byte rotation as found in lame ciphers.
|
215
259
|
# This was cribbed from Timur Duehr with only a minor change.
|
216
260
|
def rotate_bytes(k=0)
|
@@ -223,9 +267,11 @@ class String
|
|
223
267
|
return r
|
224
268
|
end
|
225
269
|
|
270
|
+
|
226
271
|
# String randomizer
|
227
272
|
def randomize ; self.split('').randomize.to_s ; end
|
228
273
|
|
274
|
+
|
229
275
|
# In-place string randomizer
|
230
276
|
def randomize! ; self.replace(randomize) end
|
231
277
|
|
@@ -552,7 +598,6 @@ class String
|
|
552
598
|
end
|
553
599
|
r
|
554
600
|
end
|
555
|
-
|
556
601
|
|
557
602
|
|
558
603
|
# Returns a reference to actual constant for a given name in namespace
|
@@ -579,6 +624,22 @@ class Symbol
|
|
579
624
|
end
|
580
625
|
|
581
626
|
class Array
|
627
|
+
|
628
|
+
# Should be in the std library.
|
629
|
+
#
|
630
|
+
# keys = [:one, :two, :three]
|
631
|
+
# vals = [1, 2, 3]
|
632
|
+
#
|
633
|
+
# keys.zip(vals).to_hash
|
634
|
+
# #=> {:two=>2, :three=>3, :one=>1}})
|
635
|
+
#
|
636
|
+
# keys.to_hash(vals)
|
637
|
+
# #=> {:two=>2, :three=>3, :one=>1}})
|
638
|
+
def to_hash(vals=nil)
|
639
|
+
a = vals ? self.zip(vals) : self
|
640
|
+
a.inject({}) {|hash, i| hash[i[0]] = i[1]; hash}
|
641
|
+
end
|
642
|
+
|
582
643
|
# randomizes the order of contents in the Array (self)
|
583
644
|
def randomize ; self.sort_by { rand } ; end
|
584
645
|
|
data/rbkb.gemspec
CHANGED
@@ -2,23 +2,23 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{rbkb}
|
5
|
-
s.version = "0.6.
|
5
|
+
s.version = "0.6.11"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Eric Monti"]
|
9
|
-
s.date = %q{2009-10-
|
9
|
+
s.date = %q{2009-10-07}
|
10
10
|
s.description = %q{Rbkb is a collection of ruby-based pen-testing and reversing tools. Inspired by Matasano Blackbag.}
|
11
11
|
s.email = %q{emonti@matasano.com}
|
12
12
|
s.executables = ["b64", "bgrep", "blit", "c", "crc32", "d64", "dedump", "feed", "hexify", "len", "plugsrv", "rex", "rstrings", "slice", "telson", "unhexify", "urldec", "urlenc", "xor"]
|
13
13
|
s.extra_rdoc_files = ["History.txt", "README.rdoc", "bin/b64", "bin/bgrep", "bin/blit", "bin/c", "bin/crc32", "bin/d64", "bin/dedump", "bin/feed", "bin/hexify", "bin/len", "bin/plugsrv", "bin/rex", "bin/rstrings", "bin/slice", "bin/telson", "bin/unhexify", "bin/urldec", "bin/urlenc", "bin/xor", "cli_usage.rdoc", "lib_usage.rdoc"]
|
14
|
-
s.files = ["History.txt", "README.rdoc", "Rakefile", "bin/b64", "bin/bgrep", "bin/blit", "bin/c", "bin/crc32", "bin/d64", "bin/dedump", "bin/feed", "bin/hexify", "bin/len", "bin/plugsrv", "bin/rex", "bin/rstrings", "bin/slice", "bin/telson", "bin/unhexify", "bin/urldec", "bin/urlenc", "bin/xor", "cli_usage.rdoc", "doctor-bag.jpg", "lib/rbkb.rb", "lib/rbkb/cli.rb", "lib/rbkb/cli/b64.rb", "lib/rbkb/cli/bgrep.rb", "lib/rbkb/cli/blit.rb", "lib/rbkb/cli/chars.rb", "lib/rbkb/cli/crc32.rb", "lib/rbkb/cli/d64.rb", "lib/rbkb/cli/dedump.rb", "lib/rbkb/cli/feed.rb", "lib/rbkb/cli/hexify.rb", "lib/rbkb/cli/len.rb", "lib/rbkb/cli/rstrings.rb", "lib/rbkb/cli/slice.rb", "lib/rbkb/cli/telson.rb", "lib/rbkb/cli/unhexify.rb", "lib/rbkb/cli/urldec.rb", "lib/rbkb/cli/urlenc.rb", "lib/rbkb/cli/xor.rb", "lib/rbkb/extends.rb", "lib/rbkb/
|
14
|
+
s.files = ["History.txt", "README.rdoc", "Rakefile", "bin/b64", "bin/bgrep", "bin/blit", "bin/c", "bin/crc32", "bin/d64", "bin/dedump", "bin/feed", "bin/hexify", "bin/len", "bin/plugsrv", "bin/rex", "bin/rstrings", "bin/slice", "bin/telson", "bin/unhexify", "bin/urldec", "bin/urlenc", "bin/xor", "cli_usage.rdoc", "doctor-bag.jpg", "lib/rbkb.rb", "lib/rbkb/cli.rb", "lib/rbkb/cli/b64.rb", "lib/rbkb/cli/bgrep.rb", "lib/rbkb/cli/blit.rb", "lib/rbkb/cli/chars.rb", "lib/rbkb/cli/crc32.rb", "lib/rbkb/cli/d64.rb", "lib/rbkb/cli/dedump.rb", "lib/rbkb/cli/feed.rb", "lib/rbkb/cli/hexify.rb", "lib/rbkb/cli/len.rb", "lib/rbkb/cli/rstrings.rb", "lib/rbkb/cli/slice.rb", "lib/rbkb/cli/telson.rb", "lib/rbkb/cli/unhexify.rb", "lib/rbkb/cli/urldec.rb", "lib/rbkb/cli/urlenc.rb", "lib/rbkb/cli/xor.rb", "lib/rbkb/extends.rb", "lib/rbkb/plug.rb", "lib/rbkb/plug/blit.rb", "lib/rbkb/plug/cli.rb", "lib/rbkb/plug/feed_import.rb", "lib/rbkb/plug/peer.rb", "lib/rbkb/plug/plug.rb", "lib/rbkb/plug/proxy.rb", "lib/rbkb/plug/unix_domain.rb", "lib_usage.rdoc", "rbkb.gemspec", "spec/rbkb_spec.rb", "spec/spec_helper.rb", "tasks/ann.rake", "tasks/bones.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/notes.rake", "tasks/post_load.rake", "tasks/rdoc.rake", "tasks/rubyforge.rake", "tasks/setup.rb", "tasks/spec.rake", "tasks/svn.rake", "tasks/test.rake", "test/test_cli_b64.rb", "test/test_cli_bgrep.rb", "test/test_cli_blit.rb", "test/test_cli_chars.rb", "test/test_cli_crc32.rb", "test/test_cli_d64.rb", "test/test_cli_dedump.rb", "test/test_cli_feed.rb", "test/test_cli_helper.rb", "test/test_cli_hexify.rb", "test/test_cli_len.rb", "test/test_cli_rstrings.rb", "test/test_cli_slice.rb", "test/test_cli_telson.rb", "test/test_cli_unhexify.rb", "test/test_cli_urldec.rb", "test/test_cli_urlenc.rb", "test/test_cli_xor.rb", "test/test_helper.rb", "test/test_rbkb.rb"]
|
15
15
|
s.homepage = %q{http://emonti.github.com/rbkb}
|
16
16
|
s.rdoc_options = ["--line-numbers", "--main", "README.rdoc"]
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
s.rubyforge_project = %q{rbkb}
|
19
19
|
s.rubygems_version = %q{1.3.4}
|
20
20
|
s.summary = %q{Rbkb is a collection of ruby-based pen-testing and reversing tools}
|
21
|
-
s.test_files = ["test/test_cli_b64.rb", "test/test_cli_bgrep.rb", "test/test_cli_blit.rb", "test/test_cli_chars.rb", "test/test_cli_crc32.rb", "test/test_cli_d64.rb", "test/test_cli_dedump.rb", "test/test_cli_feed.rb", "test/test_cli_helper.rb", "test/test_cli_hexify.rb", "test/test_cli_len.rb", "test/test_cli_rstrings.rb", "test/test_cli_slice.rb", "test/test_cli_telson.rb", "test/test_cli_unhexify.rb", "test/test_cli_urldec.rb", "test/test_cli_urlenc.rb", "test/test_cli_xor.rb", "test/test_helper.rb", "test/
|
21
|
+
s.test_files = ["test/test_cli_b64.rb", "test/test_cli_bgrep.rb", "test/test_cli_blit.rb", "test/test_cli_chars.rb", "test/test_cli_crc32.rb", "test/test_cli_d64.rb", "test/test_cli_dedump.rb", "test/test_cli_feed.rb", "test/test_cli_helper.rb", "test/test_cli_hexify.rb", "test/test_cli_len.rb", "test/test_cli_rstrings.rb", "test/test_cli_slice.rb", "test/test_cli_telson.rb", "test/test_cli_unhexify.rb", "test/test_cli_urldec.rb", "test/test_cli_urlenc.rb", "test/test_cli_xor.rb", "test/test_helper.rb", "test/test_rbkb.rb"]
|
22
22
|
|
23
23
|
if s.respond_to? :specification_version then
|
24
24
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbkb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Monti
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-07 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -125,14 +125,6 @@ files:
|
|
125
125
|
- lib/rbkb/cli/urlenc.rb
|
126
126
|
- lib/rbkb/cli/xor.rb
|
127
127
|
- lib/rbkb/extends.rb
|
128
|
-
- lib/rbkb/http.rb
|
129
|
-
- lib/rbkb/http/base.rb
|
130
|
-
- lib/rbkb/http/body.rb
|
131
|
-
- lib/rbkb/http/common.rb
|
132
|
-
- lib/rbkb/http/headers.rb
|
133
|
-
- lib/rbkb/http/parameters.rb
|
134
|
-
- lib/rbkb/http/request.rb
|
135
|
-
- lib/rbkb/http/response.rb
|
136
128
|
- lib/rbkb/plug.rb
|
137
129
|
- lib/rbkb/plug/blit.rb
|
138
130
|
- lib/rbkb/plug/cli.rb
|
@@ -176,10 +168,6 @@ files:
|
|
176
168
|
- test/test_cli_urlenc.rb
|
177
169
|
- test/test_cli_xor.rb
|
178
170
|
- test/test_helper.rb
|
179
|
-
- test/test_http.rb
|
180
|
-
- test/test_http_helper.rb
|
181
|
-
- test/test_http_request.rb
|
182
|
-
- test/test_http_response.rb
|
183
171
|
- test/test_rbkb.rb
|
184
172
|
has_rdoc: true
|
185
173
|
homepage: http://emonti.github.com/rbkb
|
@@ -231,8 +219,4 @@ test_files:
|
|
231
219
|
- test/test_cli_urlenc.rb
|
232
220
|
- test/test_cli_xor.rb
|
233
221
|
- test/test_helper.rb
|
234
|
-
- test/test_http.rb
|
235
|
-
- test/test_http_helper.rb
|
236
|
-
- test/test_http_request.rb
|
237
|
-
- test/test_http_response.rb
|
238
222
|
- test/test_rbkb.rb
|
data/lib/rbkb/http.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
|
2
|
-
# ???Why???? would anyone create their own HTTP implementation in ruby with
|
3
|
-
# so many options out there? Short answer: Net:HTTP and others just don't cut
|
4
|
-
# it in lots of edge cases. I needed something I could control completely.
|
5
|
-
|
6
|
-
module Rbkb
|
7
|
-
module Http
|
8
|
-
VERSION = "0.0.3"
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'time' # gives us Time.httpdate parser and output methods
|
13
|
-
|
14
|
-
require "rbkb/http/common.rb"
|
15
|
-
require "rbkb/http/base.rb"
|
16
|
-
require "rbkb/http/request.rb"
|
17
|
-
require "rbkb/http/response.rb"
|
18
|
-
require "rbkb/http/headers.rb"
|
19
|
-
require "rbkb/http/body.rb"
|
20
|
-
require "rbkb/http/parameters.rb"
|
21
|
-
|
data/lib/rbkb/http/base.rb
DELETED
@@ -1,172 +0,0 @@
|
|
1
|
-
module Rbkb::Http
|
2
|
-
|
3
|
-
# A base class containing some common features for Request and Response
|
4
|
-
# objects.
|
5
|
-
#
|
6
|
-
# Don't use this class directly, it's intended for being overridden
|
7
|
-
# from its derived classes or mixins.
|
8
|
-
class Base
|
9
|
-
include CommonInterface
|
10
|
-
|
11
|
-
def self.parse(*args)
|
12
|
-
new(*args)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Initializes a new Base object
|
16
|
-
def initialize(*args)
|
17
|
-
_common_init(*args)
|
18
|
-
end
|
19
|
-
|
20
|
-
# This method parses just HTTP message body. Expects body to be split
|
21
|
-
# from the headers before-hand.
|
22
|
-
def capture_body(bstr)
|
23
|
-
self.body ||= default_body_obj
|
24
|
-
@body.capture(bstr)
|
25
|
-
end
|
26
|
-
|
27
|
-
# XXX stub
|
28
|
-
def first_entity
|
29
|
-
@first_entity
|
30
|
-
end
|
31
|
-
|
32
|
-
# XXX stub
|
33
|
-
def first_entity=(f)
|
34
|
-
@first_entity=(f)
|
35
|
-
end
|
36
|
-
|
37
|
-
# This method parses only HTTP response headers. Expects headers to be
|
38
|
-
# split from the body before-hand.
|
39
|
-
def capture_headers(hstr)
|
40
|
-
self.headers ||= default_headers_obj
|
41
|
-
|
42
|
-
if @body and not @body.capture_complete?
|
43
|
-
return
|
44
|
-
elsif @headers.capture_complete?
|
45
|
-
self.first_entity, @headers = default_headers_obj.capture_full_headers(hstr)
|
46
|
-
else
|
47
|
-
@headers.capture(hstr)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# This method returns the content length from Headers. This is
|
52
|
-
# mostly useful if you are using a BoundBody object for the body.
|
53
|
-
#
|
54
|
-
# Returns nil if no "Content-Length" is not found.
|
55
|
-
#
|
56
|
-
# The opts parameter :ignore_content_length affects this method and
|
57
|
-
# will cause it always to return nil. This is useful, for example,
|
58
|
-
# for the responses to the HTTP HEAD request method, which return
|
59
|
-
# a Content-Length without actual content.
|
60
|
-
#
|
61
|
-
def content_length(hdrs=@headers)
|
62
|
-
raise "headers is nil?" if not hdrs
|
63
|
-
if( (not @opts[:ignore_content_length]) and
|
64
|
-
hdrs.get_header_value("Content-Length").to_s =~ /^(\d+)$/ )
|
65
|
-
|
66
|
-
$1.to_i
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def attach_new_header(hdr_obj=nil)
|
71
|
-
self.headers = hdr_obj
|
72
|
-
return hdr_obj
|
73
|
-
end
|
74
|
-
|
75
|
-
def attach_new_body(body_obj=nil)
|
76
|
-
self.body = body_obj
|
77
|
-
return body_obj
|
78
|
-
end
|
79
|
-
|
80
|
-
# XXX doc override!
|
81
|
-
def default_headers_obj(*args)
|
82
|
-
Header.new(*args)
|
83
|
-
end
|
84
|
-
|
85
|
-
# XXX doc override!
|
86
|
-
def default_body_obj(*args)
|
87
|
-
Body.new(*args)
|
88
|
-
end
|
89
|
-
|
90
|
-
# This method will non-destructively reset the capture state on this
|
91
|
-
# object and all child entities. Note, however, If child entities are not
|
92
|
-
# defined, it may instantiate new ones.
|
93
|
-
# See also: capture_complete?, reset_capture!
|
94
|
-
def reset_capture
|
95
|
-
if @headers
|
96
|
-
@headers.reset_capture if not @headers.capture_complete?
|
97
|
-
else
|
98
|
-
attach_new_header()
|
99
|
-
end
|
100
|
-
|
101
|
-
if @body
|
102
|
-
@body.reset_capture if not @body.capture_complete?
|
103
|
-
else
|
104
|
-
attach_new_body()
|
105
|
-
end
|
106
|
-
@capture_state = nil
|
107
|
-
self
|
108
|
-
end
|
109
|
-
|
110
|
-
# This method will destructively reset the capture state on this object.
|
111
|
-
# It does so by initializing fresh child entities and discarding the old
|
112
|
-
# ones. See also: capture_complete?, reset_capture
|
113
|
-
def reset_capture!
|
114
|
-
attach_new_header()
|
115
|
-
attach_new_body()
|
116
|
-
@capture_state = nil
|
117
|
-
self
|
118
|
-
end
|
119
|
-
|
120
|
-
# Indicates whether this object is ready to capture fresh data, or is
|
121
|
-
# waiting for additional data or a reset from a previous incomplete or
|
122
|
-
# otherwise broken capture. See also: reset_capture, reset_capture!
|
123
|
-
def capture_complete?
|
124
|
-
if( (@headers and not @headers.capture_complete?) or
|
125
|
-
(@body and not @body.capture_complete?) )
|
126
|
-
return false
|
127
|
-
else
|
128
|
-
true
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
attr_reader :body, :headers
|
133
|
-
|
134
|
-
# This accessor will attempt to always do the "right thing" while
|
135
|
-
# setting this object's body entity.
|
136
|
-
#
|
137
|
-
# See also: default_body_obj
|
138
|
-
def body=(b)
|
139
|
-
if @body
|
140
|
-
@body.data = b
|
141
|
-
elsif b.kind_of? Body
|
142
|
-
@body = b.dup
|
143
|
-
@body.opts = b.opts
|
144
|
-
else
|
145
|
-
@body = default_body_obj(b)
|
146
|
-
end
|
147
|
-
@body.base = self
|
148
|
-
return @body
|
149
|
-
end
|
150
|
-
|
151
|
-
# This accessor will attempt to always do the "right thing" while
|
152
|
-
# setting this object's headers entity.
|
153
|
-
#
|
154
|
-
# See also: default_headers_obj
|
155
|
-
def headers=(h)
|
156
|
-
if @headers
|
157
|
-
@headers.data = h
|
158
|
-
elsif h.kind_of? Headers
|
159
|
-
@headers = h.dup
|
160
|
-
@headers.opts = h.opts
|
161
|
-
else
|
162
|
-
@headers = default_headers_obj(h)
|
163
|
-
end
|
164
|
-
@headers.base = self
|
165
|
-
return @body
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
|
data/lib/rbkb/http/body.rb
DELETED
@@ -1,214 +0,0 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
|
3
|
-
module Rbkb::Http
|
4
|
-
class Body < String
|
5
|
-
include CommonInterface
|
6
|
-
|
7
|
-
def self.parse(str)
|
8
|
-
new().capture(str)
|
9
|
-
end
|
10
|
-
|
11
|
-
attr_reader :expect_length
|
12
|
-
|
13
|
-
def initialize(str=nil, opts=nil)
|
14
|
-
self.opts = opts
|
15
|
-
if Body === str
|
16
|
-
self.replace(str)
|
17
|
-
@opts = str.opts.merge(@opts)
|
18
|
-
elsif String === str
|
19
|
-
super(str)
|
20
|
-
else
|
21
|
-
super()
|
22
|
-
end
|
23
|
-
|
24
|
-
yield(self) if block_given?
|
25
|
-
end
|
26
|
-
|
27
|
-
# The capture method is used when parsing HTTP requests/responses.
|
28
|
-
# This can and probably should be overridden in derived classes.
|
29
|
-
def capture(str)
|
30
|
-
yield(str) if block_given?
|
31
|
-
self.data=(str)
|
32
|
-
end
|
33
|
-
|
34
|
-
# The to_raw method is used when writing HTTP requests/responses.
|
35
|
-
# This can and probably should be overridden in derived classes.
|
36
|
-
def to_raw
|
37
|
-
(block_given?) ? yield(self.data) : self.data
|
38
|
-
end
|
39
|
-
|
40
|
-
attr_reader :base
|
41
|
-
|
42
|
-
def base=(b)
|
43
|
-
if b.nil? or b.is_a? Base
|
44
|
-
@base = b
|
45
|
-
else
|
46
|
-
raise "base must be a Response or Request object or nil"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def data
|
51
|
-
self
|
52
|
-
end
|
53
|
-
|
54
|
-
# Sets internal raw string data without any HTTP decoration.
|
55
|
-
def data=(str)
|
56
|
-
self.replace(str.to_s)
|
57
|
-
end
|
58
|
-
|
59
|
-
# Returns the content length from the HTTP base object if
|
60
|
-
# there is one and content-length is available.
|
61
|
-
def get_content_length
|
62
|
-
@base.content_length if @base
|
63
|
-
end
|
64
|
-
|
65
|
-
# This method will non-destructively reset the capture state on this object.
|
66
|
-
# It is non-destructive in that it will not affect existing captured data
|
67
|
-
# if present.
|
68
|
-
def reset_capture
|
69
|
-
@expect_length = nil
|
70
|
-
@base.reset_capture() if @base and @base.capture_complete?
|
71
|
-
end
|
72
|
-
|
73
|
-
# This method will destructively reset the capture state on this object.
|
74
|
-
# This method is destructive in that it will clear any previously captured
|
75
|
-
# data.
|
76
|
-
def reset_capture!
|
77
|
-
reset_capture()
|
78
|
-
self.data=""
|
79
|
-
end
|
80
|
-
|
81
|
-
def capture_complete?
|
82
|
-
not @expect_length
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
|
-
# BoundBody is designed for handling an HTTP body when using the usual
|
88
|
-
# "Content-Length: NNN" HTTP header.
|
89
|
-
class BoundBody < Body
|
90
|
-
|
91
|
-
# This method may throw :expect_length with one of the following values
|
92
|
-
# to indicate certain content-length conditions:
|
93
|
-
#
|
94
|
-
# > 0 : Got incomplete data in this capture. The object expects
|
95
|
-
# capture to be called again with more body data.
|
96
|
-
#
|
97
|
-
# < 0 : Got more data than expected, the caller should truncate and
|
98
|
-
# handle the extra data in some way. Note: Calling capture again
|
99
|
-
# on this instance will start a fresh body capture.
|
100
|
-
#
|
101
|
-
# Caller can also detect the above conditions by checking the expect_length
|
102
|
-
# attribute but should still be prepared handle the throw().
|
103
|
-
#
|
104
|
-
# 0/nil: Got exactly what was expected. Caller can proceed with fresh
|
105
|
-
# captures on this or other Body objects.
|
106
|
-
#
|
107
|
-
# See also reset_capture and reset_capture!
|
108
|
-
def capture(str)
|
109
|
-
raise "arg 0 must be a string" unless String === str
|
110
|
-
|
111
|
-
# Start fresh unless we're expecting more data
|
112
|
-
self.data="" unless @expect_length and @expect_length > 0
|
113
|
-
|
114
|
-
if not clen=get_content_length()
|
115
|
-
raise "content-length is unknown. aborting capture"
|
116
|
-
else
|
117
|
-
@expect_length = clen - (self.size + str.size)
|
118
|
-
self << str[0, clen - self.size]
|
119
|
-
if @expect_length > 0
|
120
|
-
throw(:expect_length, @expect_length)
|
121
|
-
elsif @expect_length < 0
|
122
|
-
throw(:expect_length, @expect_length)
|
123
|
-
else
|
124
|
-
reset_capture()
|
125
|
-
end
|
126
|
-
end
|
127
|
-
return self
|
128
|
-
end
|
129
|
-
|
130
|
-
def to_raw(*args)
|
131
|
-
if @base
|
132
|
-
@base.headers.set_header("Content-Length", self.size)
|
133
|
-
end
|
134
|
-
super(*args)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
# ChunkedBody is designed for handling an HTTP body when using a
|
140
|
-
# "Transfer-Encoding: chunked" HTTP header.
|
141
|
-
class ChunkedBody < Body
|
142
|
-
DEFAULT_CHUNK_SIZE = 2048
|
143
|
-
|
144
|
-
# Throws :expect_length with 'true' when given incomplete data and expects
|
145
|
-
# to be called again with more body data to parse.
|
146
|
-
#
|
147
|
-
# The caller can also detect this condition by checking the expect_length
|
148
|
-
# attribute but must still handle the throw().
|
149
|
-
#
|
150
|
-
# See also reset_capture and reset_capture!
|
151
|
-
def capture(str)
|
152
|
-
# chunked encoding is gross...
|
153
|
-
if @expect_length
|
154
|
-
sio = StringIO.new(@last_chunk.to_s + str)
|
155
|
-
else
|
156
|
-
sio = StringIO.new(str)
|
157
|
-
self.data=""
|
158
|
-
end
|
159
|
-
@last_chunk = nil
|
160
|
-
|
161
|
-
@expect_length = true
|
162
|
-
while not sio.eof?
|
163
|
-
unless m=/^([a-fA-F0-9]+)\s*(;[[:print:]\s]*)?\r?\n$/.match(line=sio.readline)
|
164
|
-
raise "invalid chunk at #{line.chomp.inspect}"
|
165
|
-
end
|
166
|
-
if (chunksz = m[1].hex) == 0
|
167
|
-
@expect_length = false
|
168
|
-
# XXX ignore Trailer headers
|
169
|
-
break
|
170
|
-
end
|
171
|
-
|
172
|
-
if ( (not sio.eof?) and
|
173
|
-
(chunk=sio.read(chunksz)) and
|
174
|
-
chunk.size == chunksz and
|
175
|
-
(not sio.eof?) and (extra = sio.readline) and
|
176
|
-
(not sio.eof?) and (extra << sio.readline)
|
177
|
-
)
|
178
|
-
if extra =~ /^\r?\n\r?\n$/
|
179
|
-
yield(chunk) if block_given?
|
180
|
-
self << chunk
|
181
|
-
else
|
182
|
-
raise "expected CRLF"
|
183
|
-
end
|
184
|
-
else
|
185
|
-
@last_chunk = line + chunk.to_s + extra.to_s
|
186
|
-
break
|
187
|
-
end
|
188
|
-
end
|
189
|
-
throw(:expect_length, @expect_length) if @expect_length
|
190
|
-
return self
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
def to_raw(csz=nil)
|
195
|
-
csz ||= (@opts[:output_chunk_size] || DEFAULT_CHUNK_SIZE)
|
196
|
-
unless csz.kind_of? Integer and csz > 0
|
197
|
-
raise "chunk size must be an integer >= 1"
|
198
|
-
end
|
199
|
-
|
200
|
-
out=[]
|
201
|
-
i=0
|
202
|
-
while i <= self.size
|
203
|
-
chunk = self[i, csz]
|
204
|
-
out << "#{chunk.size.to_s(16)}\r\n#{chunk}\r\n\r\n"
|
205
|
-
yield(self, out.last) if block_given?
|
206
|
-
i+=csz
|
207
|
-
end
|
208
|
-
out << "0\r\n"
|
209
|
-
yield(self, out.last) if block_given?
|
210
|
-
return out.join
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|