| Class | WEBrick::HTTPResponse |
| In: |
lib/webrick/httpresponse.rb
|
| Parent: | Object |
| BUFSIZE | = | 1024*4 |
| body | [RW] | |
| config | [R] | |
| cookies | [R] | |
| filename | [RW] | |
| header | [R] | |
| http_version | [R] | |
| keep_alive | [RW] | |
| reason_phrase | [RW] | |
| request_http_version | [RW] | |
| request_method | [RW] | |
| request_uri | [RW] | |
| sent_size | [R] | |
| status | [R] |
# File lib/webrick/httpresponse.rb, line 31
31: def initialize(config)
32: @config = config
33: @logger = config[:Logger]
34: @header = Hash.new
35: @status = HTTPStatus::RC_OK
36: @reason_phrase = nil
37: @http_version = HTTPVersion::convert(@config[:HTTPVersion])
38: @body = ''
39: @keep_alive = true
40: @cookies = []
41: @request_method = nil
42: @request_uri = nil
43: @request_http_version = @http_version # temporary
44: @chunked = false
45: @filename = nil
46: @sent_size = 0
47: end
# File lib/webrick/httpresponse.rb, line 62
62: def []=(field, value)
63: @header[field.downcase] = value.to_s
64: end
# File lib/webrick/httpresponse.rb, line 92
92: def chunked=(val)
93: @chunked = val ? true : false
94: end
# File lib/webrick/httpresponse.rb, line 66
66: def content_length
67: if len = self['content-length']
68: return Integer(len)
69: end
70: end
# File lib/webrick/httpresponse.rb, line 72
72: def content_length=(len)
73: self['content-length'] = len.to_s
74: end
# File lib/webrick/httpresponse.rb, line 80
80: def content_type=(type)
81: self['content-type'] = type
82: end
# File lib/webrick/httpresponse.rb, line 84
84: def each
85: @header.each{|k, v| yield(k, v) }
86: end
# File lib/webrick/httpresponse.rb, line 184
184: def send_body(socket)
185: case @body
186: when IO then send_body_io(socket)
187: else send_body_string(socket)
188: end
189: end
# File lib/webrick/httpresponse.rb, line 169
169: def send_header(socket)
170: if @http_version.major > 0
171: data = status_line()
172: @header.each{|key, value|
173: tmp = key.gsub(/\bwww|^te$|\b\w/){|s| s.upcase }
174: data << "#{tmp}: #{value}" << CRLF
175: }
176: @cookies.each{|cookie|
177: data << "Set-Cookie: " << cookie.to_s << CRLF
178: }
179: data << CRLF
180: _write_data(socket, data)
181: end
182: end
# File lib/webrick/httpresponse.rb, line 100
100: def send_response(socket)
101: begin
102: setup_header()
103: send_header(socket)
104: send_body(socket)
105: rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex
106: @logger.debug(ex)
107: @keep_alive = false
108: rescue Exception => ex
109: @logger.error(ex)
110: @keep_alive = false
111: end
112: end
# File lib/webrick/httpresponse.rb, line 203
203: def set_error(ex, backtrace=false)
204: case ex
205: when HTTPStatus::Status
206: @keep_alive = false if HTTPStatus::error?(ex.code)
207: self.status = ex.code
208: else
209: @keep_alive = false
210: self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
211: end
212: @header['content-type'] = "text/html; charset=ISO-8859-1"
213:
214: if respond_to?(:create_error_page)
215: create_error_page()
216: return
217: end
218:
219: if @request_uri
220: host, port = @request_uri.host, @request_uri.port
221: else
222: host, port = @config[:ServerName], @config[:Port]
223: end
224:
225: @body = ''
226: @body << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n<HTML>\n<HEAD><TITLE>\#{HTMLUtils::escape(@reason_phrase)}</TITLE></HEAD>\n<BODY>\n<H1>\#{HTMLUtils::escape(@reason_phrase)}</H1>\n\#{HTMLUtils::escape(ex.message)}\n<HR>\n"
227:
228: if backtrace && $DEBUG
229: @body << "backtrace of `#{HTMLUtils::escape(ex.class.to_s)}' "
230: @body << "#{HTMLUtils::escape(ex.message)}"
231: @body << "<PRE>"
232: ex.backtrace.each{|line| @body << "\t#{line}\n"}
233: @body << "</PRE><HR>"
234: end
235:
236: @body << "<ADDRESS>\n\#{HTMLUtils::escape(@config[:ServerSoftware])} at\n\#{host}:\#{port}\n</ADDRESS>\n</BODY>\n</HTML>\n"
237: end
# File lib/webrick/httpresponse.rb, line 197
197: def set_redirect(status, url)
198: @body = "<HTML><A HREF=\"#{url.to_s}\">#{url.to_s}</A>.</HTML>\n"
199: @header['location'] = url.to_s
200: raise status
201: end
# File lib/webrick/httpresponse.rb, line 114
114: def setup_header()
115: @reason_phrase ||= HTTPStatus::reason_phrase(@status)
116: @header['server'] ||= @config[:ServerSoftware]
117: @header['date'] ||= Time.now.httpdate
118:
119: # HTTP/0.9 features
120: if @request_http_version < "1.0"
121: @http_version = HTTPVersion.new("0.9")
122: @keep_alive = false
123: end
124:
125: # HTTP/1.0 features
126: if @request_http_version < "1.1"
127: if chunked?
128: @chunked = false
129: ver = @request_http_version.to_s
130: msg = "chunked is set for an HTTP/#{ver} request. (ignored)"
131: @logger.warn(msg)
132: end
133: end
134:
135: # Determine the message length (RFC2616 -- 4.4 Message Length)
136: if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
137: @header.delete('content-length')
138: @body = ""
139: elsif chunked?
140: @header["transfer-encoding"] = "chunked"
141: @header.delete('content-length')
142: elsif %r{^multipart/byteranges} =~ @header['content-type']
143: @header.delete('content-length')
144: elsif @header['content-length'].nil?
145: unless @body.is_a?(IO)
146: @header['content-length'] = @body ? @body.size : 0
147: end
148: end
149:
150: # Keep-Alive connection.
151: if @header['connection'] == "close"
152: @keep_alive = false
153: elsif keep_alive?
154: if chunked? || @header['content-length']
155: @header['connection'] = "Keep-Alive"
156: end
157: else
158: @header['connection'] = "close"
159: end
160:
161: # Location is a single absoluteURI.
162: if location = @header['location']
163: if @request_uri
164: @header['location'] = @request_uri.merge(location)
165: end
166: end
167: end
# File lib/webrick/httpresponse.rb, line 53
53: def status=(status)
54: @status = status
55: @reason_phrase = HTTPStatus::reason_phrase(status)
56: end
# File lib/webrick/httpresponse.rb, line 49
49: def status_line
50: "HTTP/#@http_version #@status #@reason_phrase #{CRLF}"
51: end
# File lib/webrick/httpresponse.rb, line 191
191: def to_s
192: ret = ""
193: send_response(ret)
194: ret
195: end
# File lib/webrick/httpresponse.rb, line 304
304: def _send_file(output, input, offset, size)
305: while offset > 0
306: sz = BUFSIZE < offset ? BUFSIZE : offset
307: buf = input.read(sz)
308: offset -= buf.size
309: end
310:
311: if size == 0
312: while buf = input.read(BUFSIZE)
313: _write_data(output, buf)
314: end
315: else
316: while size > 0
317: sz = BUFSIZE < size ? BUFSIZE : size
318: buf = input.read(sz)
319: _write_data(output, buf)
320: size -= buf.size
321: end
322: end
323: end
# File lib/webrick/httpresponse.rb, line 325
325: def _write_data(socket, data)
326: socket << data
327: end
# File lib/webrick/httpresponse.rb, line 258
258: def send_body_io(socket)
259: begin
260: if @request_method == "HEAD"
261: # do nothing
262: elsif chunked?
263: while buf = @body.read(BUFSIZE)
264: next if buf.empty?
265: data = ""
266: data << format("%x", buf.size) << CRLF
267: data << buf << CRLF
268: _write_data(socket, data)
269: @sent_size += buf.size
270: end
271: _write_data(socket, "0#{CRLF}#{CRLF}")
272: else
273: size = @header['content-length'].to_i
274: _send_file(socket, @body, 0, size)
275: @sent_size = size
276: end
277: ensure
278: @body.close
279: end
280: end
# File lib/webrick/httpresponse.rb, line 282
282: def send_body_string(socket)
283: if @request_method == "HEAD"
284: # do nothing
285: elsif chunked?
286: remain = body ? @body.size : 0
287: while buf = @body[@sent_size, BUFSIZE]
288: break if buf.empty?
289: data = ""
290: data << format("%x", buf.size) << CRLF
291: data << buf << CRLF
292: _write_data(socket, data)
293: @sent_size += buf.size
294: end
295: _write_data(socket, "0#{CRLF}#{CRLF}")
296: else
297: if @body && @body.size > 0
298: _write_data(socket, @body)
299: @sent_size = @body.size
300: end
301: end
302: end