Class WEBrick::HTTPRequest
In: lib/webrick/https.rb
lib/webrick/httprequest.rb
Parent: Object

Methods

Constants

BODY_CONTAINABLE_METHODS = [ "POST", "PUT" ]
BUFSIZE = 1024*4

External Aliases

parse -> orig_parse
parse_uri -> orig_parse_uri
meta_vars -> orig_meta_vars

Attributes

accept  [R] 
accept_charset  [R] 
accept_encoding  [R] 
accept_language  [R] 
addr  [R] 
attributes  [R] 
cipher  [R] 
client_cert  [R] 
cookies  [R]  Header and entity body
header  [R]  Header and entity body
host  [R]  Request-URI
http_version  [R] 
keep_alive  [R] 
path  [R]  Request-URI
path_info  [RW] 
peeraddr  [R] 
port  [R]  Request-URI
query_string  [RW] 
raw_header  [R]  Header and entity body
request_line  [R]  Request line
request_method  [R] 
request_time  [R] 
request_uri  [R]  Request-URI
script_name  [RW] 
server_cert  [R] 
unparsed_uri  [R] 
user  [RW]  Misc

Public Class methods

[Source]

    # File lib/webrick/httprequest.rb, line 45
45:     def initialize(config)
46:       @config = config
47:       @logger = config[:Logger]
48: 
49:       @request_line = @request_method =
50:         @unparsed_uri = @http_version = nil
51: 
52:       @request_uri = @host = @port = @path = nil
53:       @script_name = @path_info = nil
54:       @query_string = nil
55:       @query = nil
56:       @form_data = nil
57: 
58:       @raw_header = Array.new
59:       @header = nil
60:       @cookies = []
61:       @accept = []
62:       @accept_charset = []
63:       @accept_encoding = []
64:       @accept_language = []
65:       @body = ""
66: 
67:       @addr = @peeraddr = nil
68:       @attributes = {}
69:       @user = nil
70:       @keep_alive = false
71:       @request_time = nil
72: 
73:       @remaining_size = nil
74:       @socket = nil
75:     end

Public Instance methods

[Source]

     # File lib/webrick/httprequest.rb, line 145
145:     def [](header_name)
146:       if @header
147:         value = @header[header_name.downcase]
148:         value.empty? ? nil : value.join(", ")
149:       end
150:     end

[Source]

     # File lib/webrick/httprequest.rb, line 124
124:     def body(&block)
125:       block ||= Proc.new{|chunk| @body << chunk }
126:       read_body(@socket, block)
127:       @body.empty? ? nil : @body
128:     end

[Source]

     # File lib/webrick/httprequest.rb, line 137
137:     def content_length
138:       return Integer(self['content-length'])
139:     end

[Source]

     # File lib/webrick/httprequest.rb, line 141
141:     def content_type
142:       return self['content-type']
143:     end

[Source]

     # File lib/webrick/httprequest.rb, line 152
152:     def each
153:       @header.each{|k, v|
154:         value = @header[k]
155:         yield(k, value.empty? ? nil : value.join(", "))
156:       }
157:     end

[Source]

     # File lib/webrick/httprequest.rb, line 171
171:     def fixup()
172:       begin
173:         body{|chunk| }   # read remaining body
174:       rescue HTTPStatus::Error => ex
175:         @logger.error("HTTPRequest#fixup: #{ex.class} occured.")
176:         @keep_alive = false
177:       rescue => ex
178:         @logger.error(ex)
179:         @keep_alive = false
180:       end
181:     end

[Source]

     # File lib/webrick/httprequest.rb, line 159
159:     def keep_alive?
160:       @keep_alive
161:     end

[Source]

    # File lib/webrick/https.rb, line 44
44:     def meta_vars
45:       meta = orig_meta_vars
46:       if @server_cert
47:         meta["HTTPS"] = "on"
48:         meta["SSL_SERVER_CERT"] = @server_cert.to_pem
49:         meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
50:         if @client_cert_chain
51:           @client_cert_chain.each_with_index{|cert, i|
52:             meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
53:           }
54:         end
55:         meta["SSL_CIPHER"] = @cipher[0]
56:         meta["SSL_PROTOCOL"] = @cipher[1]
57:         meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s
58:         meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s
59:       end
60:       meta
61:     end

[Source]

     # File lib/webrick/httprequest.rb, line 183
183:     def meta_vars
184:       # This method provides the metavariables defined by the revision 3
185:       # of ``The WWW Common Gateway Interface Version 1.1''.
186:       # (http://Web.Golux.Com/coar/cgi/)
187: 
188:       meta = Hash.new
189: 
190:       cl = self["Content-Length"]
191:       ct = self["Content-Type"]
192:       meta["CONTENT_LENGTH"]    = cl if cl.to_i > 0
193:       meta["CONTENT_TYPE"]      = ct.dup if ct
194:       meta["GATEWAY_INTERFACE"] = "CGI/1.1"
195:       meta["PATH_INFO"]         = @path_info ? @path_info.dup : ""
196:      #meta["PATH_TRANSLATED"]   = nil      # no plan to be provided
197:       meta["QUERY_STRING"]      = @query_string ? @query_string.dup : ""
198:       meta["REMOTE_ADDR"]       = @peeraddr[3]
199:       meta["REMOTE_HOST"]       = @peeraddr[2]
200:      #meta["REMOTE_IDENT"]      = nil      # no plan to be provided
201:       meta["REMOTE_USER"]       = @user
202:       meta["REQUEST_METHOD"]    = @request_method.dup
203:       meta["REQUEST_URI"]       = @request_uri.to_s
204:       meta["SCRIPT_NAME"]       = @script_name.dup
205:       meta["SERVER_NAME"]       = @host
206:       meta["SERVER_PORT"]       = @port.to_s
207:       meta["SERVER_PROTOCOL"]   = "HTTP/" + @config[:HTTPVersion].to_s
208:       meta["SERVER_SOFTWARE"]   = @config[:ServerSoftware].dup
209: 
210:       self.each{|key, val|
211:         next if /^content-type$/i =~ key
212:         next if /^content-length$/i =~ key
213:         name = "HTTP_" + key
214:         name.gsub!(/-/o, "_")
215:         name.upcase!
216:         meta[name] = val
217:       }
218: 
219:       meta
220:     end

[Source]

     # File lib/webrick/httprequest.rb, line 77
 77:     def parse(socket=nil)
 78:       @socket = socket
 79:       begin
 80:         @peeraddr = socket.respond_to?(:peeraddr) ? socket.peeraddr : []
 81:         @addr = socket.respond_to?(:addr) ? socket.addr : []
 82:       rescue Errno::ENOTCONN
 83:         raise HTTPStatus::EOFError
 84:       end
 85: 
 86:       read_request_line(socket)
 87:       if @http_version.major > 0
 88:         read_header(socket)
 89:         @header['cookie'].each{|cookie|
 90:           @cookies += Cookie::parse(cookie)
 91:         }
 92:         @accept = HTTPUtils.parse_qvalues(self['accept'])
 93:         @accept_charset = HTTPUtils.parse_qvalues(self['accept-charset'])
 94:         @accept_encoding = HTTPUtils.parse_qvalues(self['accept-encoding'])
 95:         @accept_language = HTTPUtils.parse_qvalues(self['accept-language'])
 96:       end
 97:       return if @request_method == "CONNECT"
 98:       return if @unparsed_uri == "*"
 99: 
100:       begin
101:         @request_uri = parse_uri(@unparsed_uri)
102:         @path = HTTPUtils::unescape(@request_uri.path)
103:         @path = HTTPUtils::normalize_path(@path)
104:         @host = @request_uri.host
105:         @port = @request_uri.port
106:         @query_string = @request_uri.query
107:         @script_name = ""
108:         @path_info = @path.dup
109:       rescue
110:         raise HTTPStatus::BadRequest, "bad URI `#{@unparsed_uri}'."
111:       end
112: 
113:       if /close/io =~ self["connection"]
114:         @keep_alive = false
115:       elsif /keep-alive/io =~ self["connection"]
116:         @keep_alive = true
117:       elsif @http_version < "1.1"
118:         @keep_alive = false
119:       else
120:         @keep_alive = true
121:       end
122:     end

[Source]

    # File lib/webrick/https.rb, line 23
23:     def parse(socket=nil)
24:       if socket.respond_to?(:cert)
25:         @server_cert = socket.cert || @config[:SSLCertificate]
26:         @client_cert = socket.peer_cert
27:         @client_cert_chain = socket.peer_cert_chain
28:         @cipher      = socket.cipher
29:       end
30:       orig_parse(socket)
31:     end

[Source]

    # File lib/webrick/https.rb, line 35
35:     def parse_uri(str, scheme="https")
36:       if @server_cert
37:         return orig_parse_uri(str, scheme)
38:       end
39:       return orig_parse_uri(str)
40:     end

[Source]

     # File lib/webrick/httprequest.rb, line 130
130:     def query
131:       unless @query
132:         parse_query()
133:       end
134:       @query
135:     end

[Source]

     # File lib/webrick/httprequest.rb, line 163
163:     def to_s
164:       ret = @request_line.dup
165:       @raw_header.each{|line| ret << line }
166:       ret << CRLF
167:       ret << body if body
168:       ret
169:     end

Private Instance methods

[Source]

     # File lib/webrick/httprequest.rb, line 324
324:     def _read_data(io, method, arg)
325:       begin
326:         timeout(@config[:RequestTimeout]){
327:           return io.__send__(method, arg)
328:         }
329:       rescue Errno::ECONNRESET
330:         return nil
331:       rescue TimeoutError
332:         raise HTTPStatus::RequestTimeout
333:       end
334:     end

[Source]

     # File lib/webrick/httprequest.rb, line 344
344:     def parse_query()
345:       begin
346:         if @request_method == "GET" || @request_method == "HEAD"
347:           @query = HTTPUtils::parse_query(@query_string)
348:         elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/
349:           @query = HTTPUtils::parse_query(body)
350:         elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/
351:           boundary = HTTPUtils::dequote($1)
352:           @query = HTTPUtils::parse_form_data(body, boundary)
353:         else
354:           @query = Hash.new
355:         end
356:       rescue => ex
357:         raise HTTPStatus::BadRequest, ex.message
358:       end
359:     end

[Source]

     # File lib/webrick/httprequest.rb, line 248
248:     def parse_uri(str, scheme="http")
249:       if @config[:Escape8bitURI]
250:         str = HTTPUtils::escape8bit(str)
251:       end
252:       uri = URI::parse(str)
253:       return uri if uri.absolute?
254:       if self["host"]
255:         pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n
256:         host, port = *self['host'].scan(pattern)[0]
257:       elsif @addr.size > 0
258:         host, port = @addr[2], @addr[1]
259:       else
260:         host, port = @config[:ServerName], @config[:Port]
261:       end
262:       uri.scheme = scheme
263:       uri.host = host
264:       uri.port = port ? port.to_i : nil
265:       return URI::parse(uri.to_s)
266:     end

[Source]

     # File lib/webrick/httprequest.rb, line 268
268:     def read_body(socket, block)
269:       return unless socket
270:       if tc = self['transfer-encoding']
271:         case tc
272:         when /chunked/io then read_chunked(socket, block)
273:         else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}."
274:         end
275:       elsif self['content-length'] || @remaining_size
276:         @remaining_size ||= self['content-length'].to_i
277:         while @remaining_size > 0 
278:           sz = BUFSIZE < @remaining_size ? BUFSIZE : @remaining_size
279:           break unless buf = read_data(socket, sz)
280:           @remaining_size -= buf.size
281:           block.call(buf)
282:         end
283:         if @remaining_size > 0 && @socket.eof?
284:           raise HTTPStatus::BadRequest, "invalid body size."
285:         end
286:       elsif BODY_CONTAINABLE_METHODS.member?(@request_method)
287:         raise HTTPStatus::LengthRequired
288:       end
289:       return @body
290:     end

[Source]

     # File lib/webrick/httprequest.rb, line 292
292:     def read_chunk_size(socket)
293:       line = read_line(socket)
294:       if /^([0-9a-fA-F]+)(?:;(\S+))?/ =~ line
295:         chunk_size = $1.hex
296:         chunk_ext = $2
297:         [ chunk_size, chunk_ext ]
298:       else
299:         raise HTTPStatus::BadRequest, "bad chunk `#{line}'."
300:       end
301:     end

[Source]

     # File lib/webrick/httprequest.rb, line 303
303:     def read_chunked(socket, block)
304:       chunk_size, = read_chunk_size(socket)
305:       while chunk_size > 0
306:         data = ""
307:         while data.size < chunk_size
308:           tmp = read_data(socket, chunk_size-data.size) # read chunk-data
309:           break unless tmp
310:           data << tmp
311:         end
312:         if data.nil? || data.size != chunk_size
313:           raise BadRequest, "bad chunk data size."
314:         end
315:         read_line(socket)                    # skip CRLF
316:         block.call(data)
317:         chunk_size, = read_chunk_size(socket)
318:       end
319:       read_header(socket)                    # trailer + CRLF
320:       @header.delete("transfer-encoding")
321:       @remaining_size = 0
322:     end

[Source]

     # File lib/webrick/httprequest.rb, line 340
340:     def read_data(io, size)
341:       _read_data(io, :read, size)
342:     end

[Source]

     # File lib/webrick/httprequest.rb, line 238
238:     def read_header(socket)
239:       if socket
240:         while line = read_line(socket)
241:           break if /\A(#{CRLF}|#{LF})\z/om =~ line
242:           @raw_header << line
243:         end
244:       end
245:       @header = HTTPUtils::parse_header(@raw_header.join)
246:     end

[Source]

     # File lib/webrick/httprequest.rb, line 336
336:     def read_line(io)
337:       _read_data(io, :gets, LF)
338:     end

[Source]

     # File lib/webrick/httprequest.rb, line 224
224:     def read_request_line(socket)
225:       @request_line = read_line(socket) if socket
226:       @request_time = Time.now
227:       raise HTTPStatus::EOFError unless @request_line
228:       if /^(\S+)\s+(\S+?)(?:\s+HTTP\/(\d+\.\d+))?\r?\n/mo =~ @request_line
229:         @request_method = $1
230:         @unparsed_uri   = $2
231:         @http_version   = HTTPVersion.new($3 ? $3 : "0.9")
232:       else
233:         rl = @request_line.sub(/\x0d?\x0a\z/o, '')
234:         raise HTTPStatus::BadRequest, "bad Request-Line `#{rl}'."
235:       end
236:     end

[Validate]