CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/http/packet/header.rb
Views: 11766
1
# -*- coding: binary -*-
2
3
4
module Rex
5
module Proto
6
module Http
7
8
###
9
#
10
# Represents the logical HTTP header portion of an HTTP packet (request or
11
# response).
12
#
13
###
14
class Packet::Header < Hash
15
16
#
17
# Initializes an HTTP packet header class that inherits from a Hash base
18
# class.
19
#
20
def initialize
21
self.dcase_hash = {}
22
23
reset
24
end
25
26
#
27
# Parses a header from a string.
28
#
29
# XXX - Putting : in a header value breaks this badly
30
def from_s(header)
31
reset
32
33
# ghettoooooo!
34
# If we don't have any newlines..., put one there.
35
if (header.size > 0 && header !~ /\r\n/)
36
header << "\r\n"
37
end
38
39
# put the non-standard line terminations back to normal
40
# gah. not having look behinds suck,
41
header.gsub!(/([^\r])\n/n,'\1' + "\r\n")
42
43
# undo folding, kinda ugly but works for now.
44
header.gsub!(/:\s*\r\n\s+/smni,': ')
45
46
# Extract the command string
47
self.cmd_string = header.slice!(/.+\r\n/)
48
49
# Extract each header value pair
50
header.split(/\r\n/mn).each { |str|
51
if (md = str.match(/^(.+?)\s*:\s*(.+?)\s*$/))
52
if (self[md[1]])
53
self[md[1]] << ", " + md[2]
54
else
55
self[md[1]] = md[2]
56
end
57
end
58
}
59
end
60
61
#
62
# More advanced [] that does downcase comparison.
63
#
64
def [](key)
65
begin
66
rv = self.fetch(key)
67
rescue IndexError
68
rv = nil
69
end
70
if (rv == nil)
71
begin
72
rv = self.dcase_hash[key.downcase]
73
rescue IndexError
74
rv = nil
75
end
76
end
77
78
return rv
79
end
80
81
#
82
# More advanced []= that does downcase storage.
83
#
84
def []=(key, value)
85
stored = false
86
87
self.each_key { |k|
88
if (k.downcase == key.downcase)
89
self.store(k, value)
90
stored = true
91
end
92
}
93
94
self.store(key, value) if (stored == false)
95
self.dcase_hash[key.downcase] = value
96
end
97
98
#
99
# More advanced include? that does downcase comparison
100
#
101
def include?(key)
102
self.each_key.any? { |k|
103
k.casecmp?(key)
104
}
105
end
106
#
107
# Converts the header to a string.
108
#
109
def to_s(prefix = '')
110
str = prefix
111
112
if self.junk_headers
113
while str.length < 4096
114
if self.fold
115
str << "X-#{Rex::Text.rand_text_alphanumeric(rand(30) + 5)}:\r\n\t#{Rex::Text.rand_text_alphanumeric(rand(1024) + 1)}\r\n"
116
else
117
str << "X-#{Rex::Text.rand_text_alphanumeric(rand(30) + 5)}: #{Rex::Text.rand_text_alphanumeric(rand(1024) + 1)}\r\n"
118
end
119
end
120
end
121
122
each_pair { |var, val|
123
if self.fold
124
str << "#{var}:\r\n\t#{val}\r\n"
125
else
126
str << "#{var}: #{val}\r\n"
127
end
128
}
129
130
str << "\r\n"
131
132
return str
133
end
134
135
#
136
# Brings in from an array like yo.
137
#
138
def from_a(ary)
139
ary.each { |e|
140
self[e[0]] = e[1]
141
}
142
end
143
144
#
145
# Flushes all header pairs.
146
#
147
def reset
148
self.cmd_string = ''
149
self.clear
150
self.dcase_hash.clear
151
end
152
153
#
154
# Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
155
# "can't add a new key into hash during iteration"
156
#
157
def each(&block)
158
list = []
159
self.keys.sort.each do |sidx|
160
list << [sidx, self[sidx]]
161
end
162
list.each(&block)
163
end
164
165
#
166
# The raw command string associated with the header which will vary between
167
# requests and responses.
168
#
169
attr_accessor :junk_headers
170
attr_accessor :cmd_string
171
attr_accessor :fold
172
173
protected
174
175
attr_accessor :dcase_hash # :nodoc:
176
177
end
178
179
end
180
end
181
end
182
183