PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/External.LCA_RESTRICTED/Languages/Ruby/redist-libs/ruby/1.9.1/webrick/httpresponse.rb

#
Ruby | 326 lines | 268 code | 39 blank | 19 comment | 38 complexity | bb04edbc5566d4b60b2852b7e56685b1 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. #
  2. # httpresponse.rb -- HTTPResponse Class
  3. #
  4. # Author: IPR -- Internet Programming with Ruby -- writers
  5. # Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
  6. # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
  7. # reserved.
  8. #
  9. # $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
  10. require 'time'
  11. require 'webrick/httpversion'
  12. require 'webrick/htmlutils'
  13. require 'webrick/httputils'
  14. require 'webrick/httpstatus'
  15. module WEBrick
  16. class HTTPResponse
  17. attr_reader :http_version, :status, :header
  18. attr_reader :cookies
  19. attr_accessor :reason_phrase
  20. attr_accessor :body
  21. attr_accessor :request_method, :request_uri, :request_http_version
  22. attr_accessor :filename
  23. attr_accessor :keep_alive
  24. attr_reader :config, :sent_size
  25. def initialize(config)
  26. @config = config
  27. @buffer_size = config[:OutputBufferSize]
  28. @logger = config[:Logger]
  29. @header = Hash.new
  30. @status = HTTPStatus::RC_OK
  31. @reason_phrase = nil
  32. @http_version = HTTPVersion::convert(@config[:HTTPVersion])
  33. @body = ''
  34. @keep_alive = true
  35. @cookies = []
  36. @request_method = nil
  37. @request_uri = nil
  38. @request_http_version = @http_version # temporary
  39. @chunked = false
  40. @filename = nil
  41. @sent_size = 0
  42. end
  43. def status_line
  44. "HTTP/#@http_version #@status #@reason_phrase #{CRLF}"
  45. end
  46. def status=(status)
  47. @status = status
  48. @reason_phrase = HTTPStatus::reason_phrase(status)
  49. end
  50. def [](field)
  51. @header[field.downcase]
  52. end
  53. def []=(field, value)
  54. @header[field.downcase] = value.to_s
  55. end
  56. def content_length
  57. if len = self['content-length']
  58. return Integer(len)
  59. end
  60. end
  61. def content_length=(len)
  62. self['content-length'] = len.to_s
  63. end
  64. def content_type
  65. self['content-type']
  66. end
  67. def content_type=(type)
  68. self['content-type'] = type
  69. end
  70. def each
  71. @header.each{|k, v| yield(k, v) }
  72. end
  73. def chunked?
  74. @chunked
  75. end
  76. def chunked=(val)
  77. @chunked = val ? true : false
  78. end
  79. def keep_alive?
  80. @keep_alive
  81. end
  82. def send_response(socket)
  83. begin
  84. setup_header()
  85. send_header(socket)
  86. send_body(socket)
  87. rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN => ex
  88. @logger.debug(ex)
  89. @keep_alive = false
  90. rescue Exception => ex
  91. @logger.error(ex)
  92. @keep_alive = false
  93. end
  94. end
  95. def setup_header()
  96. @reason_phrase ||= HTTPStatus::reason_phrase(@status)
  97. @header['server'] ||= @config[:ServerSoftware]
  98. @header['date'] ||= Time.now.httpdate
  99. # HTTP/0.9 features
  100. if @request_http_version < "1.0"
  101. @http_version = HTTPVersion.new("0.9")
  102. @keep_alive = false
  103. end
  104. # HTTP/1.0 features
  105. if @request_http_version < "1.1"
  106. if chunked?
  107. @chunked = false
  108. ver = @request_http_version.to_s
  109. msg = "chunked is set for an HTTP/#{ver} request. (ignored)"
  110. @logger.warn(msg)
  111. end
  112. end
  113. # Determine the message length (RFC2616 -- 4.4 Message Length)
  114. if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
  115. @header.delete('content-length')
  116. @body = ""
  117. elsif chunked?
  118. @header["transfer-encoding"] = "chunked"
  119. @header.delete('content-length')
  120. elsif %r{^multipart/byteranges} =~ @header['content-type']
  121. @header.delete('content-length')
  122. elsif @header['content-length'].nil?
  123. unless @body.is_a?(IO)
  124. @header['content-length'] = @body ? @body.bytesize : 0
  125. end
  126. end
  127. # Keep-Alive connection.
  128. if @header['connection'] == "close"
  129. @keep_alive = false
  130. elsif keep_alive?
  131. if chunked? || @header['content-length']
  132. @header['connection'] = "Keep-Alive"
  133. end
  134. else
  135. @header['connection'] = "close"
  136. end
  137. # Location is a single absoluteURI.
  138. if location = @header['location']
  139. if @request_uri
  140. @header['location'] = @request_uri.merge(location)
  141. end
  142. end
  143. end
  144. def send_header(socket)
  145. if @http_version.major > 0
  146. data = status_line()
  147. @header.each{|key, value|
  148. tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
  149. data << "#{tmp}: #{value}" << CRLF
  150. }
  151. @cookies.each{|cookie|
  152. data << "Set-Cookie: " << cookie.to_s << CRLF
  153. }
  154. data << CRLF
  155. _write_data(socket, data)
  156. end
  157. end
  158. def send_body(socket)
  159. case @body
  160. when IO then send_body_io(socket)
  161. else send_body_string(socket)
  162. end
  163. end
  164. def to_s
  165. ret = ""
  166. send_response(ret)
  167. ret
  168. end
  169. def set_redirect(status, url)
  170. @body = "<HTML><A HREF=\"#{url.to_s}\">#{url.to_s}</A>.</HTML>\n"
  171. @header['location'] = url.to_s
  172. raise status
  173. end
  174. def set_error(ex, backtrace=false)
  175. case ex
  176. when HTTPStatus::Status
  177. @keep_alive = false if HTTPStatus::error?(ex.code)
  178. self.status = ex.code
  179. else
  180. @keep_alive = false
  181. self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
  182. end
  183. @header['content-type'] = "text/html; charset=ISO-8859-1"
  184. if respond_to?(:create_error_page)
  185. create_error_page()
  186. return
  187. end
  188. if @request_uri
  189. host, port = @request_uri.host, @request_uri.port
  190. else
  191. host, port = @config[:ServerName], @config[:Port]
  192. end
  193. @body = ''
  194. @body << <<-_end_of_html_
  195. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
  196. <HTML>
  197. <HEAD><TITLE>#{HTMLUtils::escape(@reason_phrase)}</TITLE></HEAD>
  198. <BODY>
  199. <H1>#{HTMLUtils::escape(@reason_phrase)}</H1>
  200. #{HTMLUtils::escape(ex.message)}
  201. <HR>
  202. _end_of_html_
  203. if backtrace && $DEBUG
  204. @body << "backtrace of `#{HTMLUtils::escape(ex.class.to_s)}' "
  205. @body << "#{HTMLUtils::escape(ex.message)}"
  206. @body << "<PRE>"
  207. ex.backtrace.each{|line| @body << "\t#{line}\n"}
  208. @body << "</PRE><HR>"
  209. end
  210. @body << <<-_end_of_html_
  211. <ADDRESS>
  212. #{HTMLUtils::escape(@config[:ServerSoftware])} at
  213. #{host}:#{port}
  214. </ADDRESS>
  215. </BODY>
  216. </HTML>
  217. _end_of_html_
  218. end
  219. private
  220. def send_body_io(socket)
  221. begin
  222. if @request_method == "HEAD"
  223. # do nothing
  224. elsif chunked?
  225. while buf = @body.read(@buffer_size)
  226. next if buf.empty?
  227. data = ""
  228. data << format("%x", buf.bytesize) << CRLF
  229. data << buf << CRLF
  230. _write_data(socket, data)
  231. @sent_size += buf.bytesize
  232. end
  233. _write_data(socket, "0#{CRLF}#{CRLF}")
  234. else
  235. size = @header['content-length'].to_i
  236. _send_file(socket, @body, 0, size)
  237. @sent_size = size
  238. end
  239. ensure
  240. @body.close
  241. end
  242. end
  243. def send_body_string(socket)
  244. if @request_method == "HEAD"
  245. # do nothing
  246. elsif chunked?
  247. remain = body ? @body.bytesize : 0
  248. while buf = @body[@sent_size, @buffer_size]
  249. break if buf.empty?
  250. data = ""
  251. data << format("%x", buf.bytesize) << CRLF
  252. data << buf << CRLF
  253. _write_data(socket, data)
  254. @sent_size += buf.bytesize
  255. end
  256. _write_data(socket, "0#{CRLF}#{CRLF}")
  257. else
  258. if @body && @body.bytesize > 0
  259. _write_data(socket, @body)
  260. @sent_size = @body.bytesize
  261. end
  262. end
  263. end
  264. def _send_file(output, input, offset, size)
  265. while offset > 0
  266. sz = @buffer_size < size ? @buffer_size : size
  267. buf = input.read(sz)
  268. offset -= buf.bytesize
  269. end
  270. if size == 0
  271. while buf = input.read(@buffer_size)
  272. _write_data(output, buf)
  273. end
  274. else
  275. while size > 0
  276. sz = @buffer_size < size ? @buffer_size : size
  277. buf = input.read(sz)
  278. _write_data(output, buf)
  279. size -= buf.bytesize
  280. end
  281. end
  282. end
  283. def _write_data(socket, data)
  284. socket << data
  285. end
  286. end
  287. end