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" 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