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 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
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:       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/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 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 328
328:     def _read_data(io, method, arg)
329:       begin
330:         timeout(@config[:RequestTimeout]){
331:           return io.__send__(method, arg)
332:         }
333:       rescue Errno::ECONNRESET
334:         return nil
335:       rescue TimeoutError
336:         raise HTTPStatus::RequestTimeout
337:       end
338:     end

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Source]

     # File lib/webrick/httprequest.rb, line 344
344:     def read_data(io, size)
345:       _read_data(io, :read, size)
346:     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:       begin
246:         @header = HTTPUtils::parse_header(@raw_header)
247:       rescue => ex
248:         raise  HTTPStatus::BadRequest, ex.message
249:       end
250:     end

[Source]

     # File lib/webrick/httprequest.rb, line 340
340:     def read_line(io)
341:       _read_data(io, :gets, LF)
342:     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]