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

Methods

Constants

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

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 45
45:     def meta_vars
46:       meta = orig_meta_vars
47:       if @server_cert
48:         meta["HTTPS"] = "on"
49:         meta["SSL_SERVER_CERT"] = @server_cert.to_pem
50:         meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
51:         if @client_cert_chain
52:           @client_cert_chain.each_with_index{|cert, i|
53:             meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
54:           }
55:         end
56:         meta["SSL_CIPHER"] = @cipher[0]
57:         meta["SSL_PROTOCOL"] = @cipher[1]
58:         meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s
59:         meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s
60:       end
61:       meta
62:     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
orig_meta_vars()

Alias for meta_vars

orig_parse(socket=nil)

Alias for parse

orig_parse_uri(str, scheme="http")

Alias for parse_uri

[Source]

    # File lib/webrick/https.rb, line 23
23:     def parse(socket=nil)
24:       @cipher = @server_cert = @client_cert = nil
25:       if socket.respond_to?(:cert)
26:         @server_cert = socket.cert || @config[:SSLCertificate]
27:         @client_cert = socket.peer_cert
28:         @client_cert_chain = socket.peer_cert_chain
29:         @cipher      = socket.cipher
30:       end
31:       orig_parse(socket)
32:     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 36
36:     def parse_uri(str, scheme="https")
37:       if @server_cert
38:         return orig_parse_uri(str, scheme)
39:       end
40:       return orig_parse_uri(str)
41:     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 325
325:     def _read_data(io, method, arg)
326:       begin
327:         timeout(@config[:RequestTimeout]){
328:           return io.__send__(method, arg)
329:         }
330:       rescue Errno::ECONNRESET
331:         return nil
332:       rescue TimeoutError
333:         raise HTTPStatus::RequestTimeout
334:       end
335:     end

[Source]

     # File lib/webrick/httprequest.rb, line 345
345:     def parse_query()
346:       begin
347:         if @request_method == "GET" || @request_method == "HEAD"
348:           @query = HTTPUtils::parse_query(@query_string)
349:         elsif self['content-type'] =~ /^application\/x-www-form-urlencoded/
350:           @query = HTTPUtils::parse_query(body)
351:         elsif self['content-type'] =~ /^multipart\/form-data; boundary=(.+)/
352:           boundary = HTTPUtils::dequote($1)
353:           @query = HTTPUtils::parse_form_data(body, boundary)
354:         else
355:           @query = Hash.new
356:         end
357:       rescue => ex
358:         raise HTTPStatus::BadRequest, ex.message
359:       end
360:     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:       str.sub!(%r{\A/+}o, '/')
253:       uri = URI::parse(str)
254:       return uri if uri.absolute?
255:       if self["host"]
256:         pattern = /\A(#{URI::REGEXP::PATTERN::HOST})(?::(\d+))?\z/n
257:         host, port = *self['host'].scan(pattern)[0]
258:       elsif @addr.size > 0
259:         host, port = @addr[2], @addr[1]
260:       else
261:         host, port = @config[:ServerName], @config[:Port]
262:       end
263:       uri.scheme = scheme
264:       uri.host = host
265:       uri.port = port ? port.to_i : nil
266:       return URI::parse(uri.to_s)
267:     end

[Source]

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

[Source]

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

[Source]

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

[Source]

     # File lib/webrick/httprequest.rb, line 341
341:     def read_data(io, size)
342:       _read_data(io, :read, size)
343:     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 337
337:     def read_line(io)
338:       _read_data(io, :gets, LF)
339:     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]