/
http.rb
150 lines (146 loc) · 3.17 KB
/
http.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
require 'socket'
require 'uri'
class HttpHeader < String
def [](key)
return $1 if self.scan(/^#{key.strip}:\s*(.*?)\s*\r?\n/)
nil
end
def []=(key, str)
key.strip!; str.strip!
if not self.gsub!(/^#{key}:\s*.*?\s*\r?\n/, "#{key}: #{str}\r\n")
self << "#{key}: #{str}\r\n"
end
str
end
def delete(key)
return $1 if self.gsub!(/^#{key.strip}:\s*(.*?)\s*\r?\n/, '')
nil
end
end
class HttpRequest
def initialize(socket)
@socket = socket
end
def header
if not defined?(@header)
@header = HttpHeader.new
request_line = @socket.gets
l = request_line.gsub(URI.regexp) do |s|
@uri = URI s
s = @uri.request_uri
end
begin
break if l =~ /\A\r?\n/
@header << l
yield l if block_given?
end while l = @socket.gets
elsif block_given?
@header.each_line do |l|
yield l
end
end
@header
end
def body
if not defined?(@body)
@body = ''
if method == 'POST' and con_len = header['Content-length']
total_len, body_len = 0, con_len.to_i
while total_len < body_len and l = @socket.readpartial(4096)
@body << l
yield l if block_given?
total_len += l.size
end
end
elsif block_given?
@body.each_line do |l|
yield l
end
end
@body
end
def uri
header unless defined?(@uri)
@uri
end
def parse_request_line
if header =~ /\A(\S+)\s+(\S+)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo
@method, @path, @http_version = $1, $2, ($3 ? $3 : "0.9")
end
end
def method
parse_request_line unless defined?(@method)
@method
end
def path
parse_request_line unless defined?(@path)
@path
end
def http_version
parse_request_line unless defined?(@http_version)
@http_version
end
end
class HttpResponse
def initialize(socket)
@socket = socket
end
def header
if not defined?(@header)
@header = HttpHeader.new
while l = @socket.gets
break if l =~ /\A\r?\n/
@header << l
yield l if block_given?
end
elsif block_given?
@header.each_line do |l|
yield l
end
end
@header
end
def header= (str)
@header = str.to_s
end
def body
if not defined?(@body)
@body = ''
if status.to_i == 304 or status.to_i == 303
elsif body_len = header['Content-Length']
total_len, max_len = 0, body_len.to_i
while total_len < max_len and l = @socket.readpartial(4096)
@body << l
yield l if block_given?
total_len += l.size
end
else
while l = @socket.gets
@body << l
yield l if block_given?
end
end
elsif block_given?
@body.each_line do |l|
yield l
end
end
@body
end
def body= (str)
@body = str.to_s
end
def parse_response_line
if header =~ /\AHTTP\/(\d\.\d)\s+(\d+)/mo
@http_version, @status = ($1 ? $1 : "0.9"), $2
end
end
def http_version
parse_response_line unless defined?(@http_version)
@http_version
end
def status
parse_response_line unless defined?(@status)
@status
end
end