PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/Util/IronRuby/lib/ruby/1.8/cgi.rb

http://github.com/IronLanguages/main
Ruby | 2303 lines | 1488 code | 78 blank | 737 comment | 70 complexity | 41f8abbdc42c47d8a367ecafe1114742 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. #
  2. # cgi.rb - cgi support library
  3. #
  4. # Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
  5. #
  6. # Copyright (C) 2000 Information-technology Promotion Agency, Japan
  7. #
  8. # Author: Wakou Aoyama <wakou@ruby-lang.org>
  9. #
  10. # Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber)
  11. #
  12. # == Overview
  13. #
  14. # The Common Gateway Interface (CGI) is a simple protocol
  15. # for passing an HTTP request from a web server to a
  16. # standalone program, and returning the output to the web
  17. # browser. Basically, a CGI program is called with the
  18. # parameters of the request passed in either in the
  19. # environment (GET) or via $stdin (POST), and everything
  20. # it prints to $stdout is returned to the client.
  21. #
  22. # This file holds the +CGI+ class. This class provides
  23. # functionality for retrieving HTTP request parameters,
  24. # managing cookies, and generating HTML output. See the
  25. # class documentation for more details and examples of use.
  26. #
  27. # The file cgi/session.rb provides session management
  28. # functionality; see that file for more details.
  29. #
  30. # See http://www.w3.org/CGI/ for more information on the CGI
  31. # protocol.
  32. raise "Please, use ruby 1.5.4 or later." if RUBY_VERSION < "1.5.4"
  33. require 'English'
  34. # CGI class. See documentation for the file cgi.rb for an overview
  35. # of the CGI protocol.
  36. #
  37. # == Introduction
  38. #
  39. # CGI is a large class, providing several categories of methods, many of which
  40. # are mixed in from other modules. Some of the documentation is in this class,
  41. # some in the modules CGI::QueryExtension and CGI::HtmlExtension. See
  42. # CGI::Cookie for specific information on handling cookies, and cgi/session.rb
  43. # (CGI::Session) for information on sessions.
  44. #
  45. # For queries, CGI provides methods to get at environmental variables,
  46. # parameters, cookies, and multipart request data. For responses, CGI provides
  47. # methods for writing output and generating HTML.
  48. #
  49. # Read on for more details. Examples are provided at the bottom.
  50. #
  51. # == Queries
  52. #
  53. # The CGI class dynamically mixes in parameter and cookie-parsing
  54. # functionality, environmental variable access, and support for
  55. # parsing multipart requests (including uploaded files) from the
  56. # CGI::QueryExtension module.
  57. #
  58. # === Environmental Variables
  59. #
  60. # The standard CGI environmental variables are available as read-only
  61. # attributes of a CGI object. The following is a list of these variables:
  62. #
  63. #
  64. # AUTH_TYPE HTTP_HOST REMOTE_IDENT
  65. # CONTENT_LENGTH HTTP_NEGOTIATE REMOTE_USER
  66. # CONTENT_TYPE HTTP_PRAGMA REQUEST_METHOD
  67. # GATEWAY_INTERFACE HTTP_REFERER SCRIPT_NAME
  68. # HTTP_ACCEPT HTTP_USER_AGENT SERVER_NAME
  69. # HTTP_ACCEPT_CHARSET PATH_INFO SERVER_PORT
  70. # HTTP_ACCEPT_ENCODING PATH_TRANSLATED SERVER_PROTOCOL
  71. # HTTP_ACCEPT_LANGUAGE QUERY_STRING SERVER_SOFTWARE
  72. # HTTP_CACHE_CONTROL REMOTE_ADDR
  73. # HTTP_FROM REMOTE_HOST
  74. #
  75. #
  76. # For each of these variables, there is a corresponding attribute with the
  77. # same name, except all lower case and without a preceding HTTP_.
  78. # +content_length+ and +server_port+ are integers; the rest are strings.
  79. #
  80. # === Parameters
  81. #
  82. # The method #params() returns a hash of all parameters in the request as
  83. # name/value-list pairs, where the value-list is an Array of one or more
  84. # values. The CGI object itself also behaves as a hash of parameter names
  85. # to values, but only returns a single value (as a String) for each
  86. # parameter name.
  87. #
  88. # For instance, suppose the request contains the parameter
  89. # "favourite_colours" with the multiple values "blue" and "green". The
  90. # following behaviour would occur:
  91. #
  92. # cgi.params["favourite_colours"] # => ["blue", "green"]
  93. # cgi["favourite_colours"] # => "blue"
  94. #
  95. # If a parameter does not exist, the former method will return an empty
  96. # array, the latter an empty string. The simplest way to test for existence
  97. # of a parameter is by the #has_key? method.
  98. #
  99. # === Cookies
  100. #
  101. # HTTP Cookies are automatically parsed from the request. They are available
  102. # from the #cookies() accessor, which returns a hash from cookie name to
  103. # CGI::Cookie object.
  104. #
  105. # === Multipart requests
  106. #
  107. # If a request's method is POST and its content type is multipart/form-data,
  108. # then it may contain uploaded files. These are stored by the QueryExtension
  109. # module in the parameters of the request. The parameter name is the name
  110. # attribute of the file input field, as usual. However, the value is not
  111. # a string, but an IO object, either an IOString for small files, or a
  112. # Tempfile for larger ones. This object also has the additional singleton
  113. # methods:
  114. #
  115. # #local_path():: the path of the uploaded file on the local filesystem
  116. # #original_filename():: the name of the file on the client computer
  117. # #content_type():: the content type of the file
  118. #
  119. # == Responses
  120. #
  121. # The CGI class provides methods for sending header and content output to
  122. # the HTTP client, and mixes in methods for programmatic HTML generation
  123. # from CGI::HtmlExtension and CGI::TagMaker modules. The precise version of HTML
  124. # to use for HTML generation is specified at object creation time.
  125. #
  126. # === Writing output
  127. #
  128. # The simplest way to send output to the HTTP client is using the #out() method.
  129. # This takes the HTTP headers as a hash parameter, and the body content
  130. # via a block. The headers can be generated as a string using the #header()
  131. # method. The output stream can be written directly to using the #print()
  132. # method.
  133. #
  134. # === Generating HTML
  135. #
  136. # Each HTML element has a corresponding method for generating that
  137. # element as a String. The name of this method is the same as that
  138. # of the element, all lowercase. The attributes of the element are
  139. # passed in as a hash, and the body as a no-argument block that evaluates
  140. # to a String. The HTML generation module knows which elements are
  141. # always empty, and silently drops any passed-in body. It also knows
  142. # which elements require matching closing tags and which don't. However,
  143. # it does not know what attributes are legal for which elements.
  144. #
  145. # There are also some additional HTML generation methods mixed in from
  146. # the CGI::HtmlExtension module. These include individual methods for the
  147. # different types of form inputs, and methods for elements that commonly
  148. # take particular attributes where the attributes can be directly specified
  149. # as arguments, rather than via a hash.
  150. #
  151. # == Examples of use
  152. #
  153. # === Get form values
  154. #
  155. # require "cgi"
  156. # cgi = CGI.new
  157. # value = cgi['field_name'] # <== value string for 'field_name'
  158. # # if not 'field_name' included, then return "".
  159. # fields = cgi.keys # <== array of field names
  160. #
  161. # # returns true if form has 'field_name'
  162. # cgi.has_key?('field_name')
  163. # cgi.has_key?('field_name')
  164. # cgi.include?('field_name')
  165. #
  166. # CAUTION! cgi['field_name'] returned an Array with the old
  167. # cgi.rb(included in ruby 1.6)
  168. #
  169. # === Get form values as hash
  170. #
  171. # require "cgi"
  172. # cgi = CGI.new
  173. # params = cgi.params
  174. #
  175. # cgi.params is a hash.
  176. #
  177. # cgi.params['new_field_name'] = ["value"] # add new param
  178. # cgi.params['field_name'] = ["new_value"] # change value
  179. # cgi.params.delete('field_name') # delete param
  180. # cgi.params.clear # delete all params
  181. #
  182. #
  183. # === Save form values to file
  184. #
  185. # require "pstore"
  186. # db = PStore.new("query.db")
  187. # db.transaction do
  188. # db["params"] = cgi.params
  189. # end
  190. #
  191. #
  192. # === Restore form values from file
  193. #
  194. # require "pstore"
  195. # db = PStore.new("query.db")
  196. # db.transaction do
  197. # cgi.params = db["params"]
  198. # end
  199. #
  200. #
  201. # === Get multipart form values
  202. #
  203. # require "cgi"
  204. # cgi = CGI.new
  205. # value = cgi['field_name'] # <== value string for 'field_name'
  206. # value.read # <== body of value
  207. # value.local_path # <== path to local file of value
  208. # value.original_filename # <== original filename of value
  209. # value.content_type # <== content_type of value
  210. #
  211. # and value has StringIO or Tempfile class methods.
  212. #
  213. # === Get cookie values
  214. #
  215. # require "cgi"
  216. # cgi = CGI.new
  217. # values = cgi.cookies['name'] # <== array of 'name'
  218. # # if not 'name' included, then return [].
  219. # names = cgi.cookies.keys # <== array of cookie names
  220. #
  221. # and cgi.cookies is a hash.
  222. #
  223. # === Get cookie objects
  224. #
  225. # require "cgi"
  226. # cgi = CGI.new
  227. # for name, cookie in cgi.cookies
  228. # cookie.expires = Time.now + 30
  229. # end
  230. # cgi.out("cookie" => cgi.cookies) {"string"}
  231. #
  232. # cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
  233. #
  234. # require "cgi"
  235. # cgi = CGI.new
  236. # cgi.cookies['name'].expires = Time.now + 30
  237. # cgi.out("cookie" => cgi.cookies['name']) {"string"}
  238. #
  239. # === Print http header and html string to $DEFAULT_OUTPUT ($>)
  240. #
  241. # require "cgi"
  242. # cgi = CGI.new("html3") # add HTML generation methods
  243. # cgi.out() do
  244. # cgi.html() do
  245. # cgi.head{ cgi.title{"TITLE"} } +
  246. # cgi.body() do
  247. # cgi.form() do
  248. # cgi.textarea("get_text") +
  249. # cgi.br +
  250. # cgi.submit
  251. # end +
  252. # cgi.pre() do
  253. # CGI::escapeHTML(
  254. # "params: " + cgi.params.inspect + "\n" +
  255. # "cookies: " + cgi.cookies.inspect + "\n" +
  256. # ENV.collect() do |key, value|
  257. # key + " --> " + value + "\n"
  258. # end.join("")
  259. # )
  260. # end
  261. # end
  262. # end
  263. # end
  264. #
  265. # # add HTML generation methods
  266. # CGI.new("html3") # html3.2
  267. # CGI.new("html4") # html4.01 (Strict)
  268. # CGI.new("html4Tr") # html4.01 Transitional
  269. # CGI.new("html4Fr") # html4.01 Frameset
  270. #
  271. class CGI
  272. # :stopdoc:
  273. # String for carriage return
  274. CR = "\015"
  275. # String for linefeed
  276. LF = "\012"
  277. # Standard internet newline sequence
  278. EOL = CR + LF
  279. REVISION = '$Id: cgi.rb 17815 2008-07-02 10:06:15Z shyouhei $' #:nodoc:
  280. NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM)
  281. # Path separators in different environments.
  282. PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
  283. # HTTP status codes.
  284. HTTP_STATUS = {
  285. "OK" => "200 OK",
  286. "PARTIAL_CONTENT" => "206 Partial Content",
  287. "MULTIPLE_CHOICES" => "300 Multiple Choices",
  288. "MOVED" => "301 Moved Permanently",
  289. "REDIRECT" => "302 Found",
  290. "NOT_MODIFIED" => "304 Not Modified",
  291. "BAD_REQUEST" => "400 Bad Request",
  292. "AUTH_REQUIRED" => "401 Authorization Required",
  293. "FORBIDDEN" => "403 Forbidden",
  294. "NOT_FOUND" => "404 Not Found",
  295. "METHOD_NOT_ALLOWED" => "405 Method Not Allowed",
  296. "NOT_ACCEPTABLE" => "406 Not Acceptable",
  297. "LENGTH_REQUIRED" => "411 Length Required",
  298. "PRECONDITION_FAILED" => "412 Rrecondition Failed",
  299. "SERVER_ERROR" => "500 Internal Server Error",
  300. "NOT_IMPLEMENTED" => "501 Method Not Implemented",
  301. "BAD_GATEWAY" => "502 Bad Gateway",
  302. "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
  303. }
  304. # Abbreviated day-of-week names specified by RFC 822
  305. RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
  306. # Abbreviated month names specified by RFC 822
  307. RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
  308. # :startdoc:
  309. def env_table
  310. ENV
  311. end
  312. def stdinput
  313. $stdin
  314. end
  315. def stdoutput
  316. $DEFAULT_OUTPUT
  317. end
  318. private :env_table, :stdinput, :stdoutput
  319. # URL-encode a string.
  320. # url_encoded_string = CGI::escape("'Stop!' said Fred")
  321. # # => "%27Stop%21%27+said+Fred"
  322. def CGI::escape(string)
  323. string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
  324. '%' + $1.unpack('H2' * $1.size).join('%').upcase
  325. end.tr(' ', '+')
  326. end
  327. # URL-decode a string.
  328. # string = CGI::unescape("%27Stop%21%27+said+Fred")
  329. # # => "'Stop!' said Fred"
  330. def CGI::unescape(string)
  331. string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
  332. [$1.delete('%')].pack('H*')
  333. end
  334. end
  335. # Escape special characters in HTML, namely &\"<>
  336. # CGI::escapeHTML('Usage: foo "bar" <baz>')
  337. # # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
  338. def CGI::escapeHTML(string)
  339. string.gsub(/&/n, '&amp;').gsub(/\"/n, '&quot;').gsub(/>/n, '&gt;').gsub(/</n, '&lt;')
  340. end
  341. # Unescape a string that has been HTML-escaped
  342. # CGI::unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
  343. # # => "Usage: foo \"bar\" <baz>"
  344. def CGI::unescapeHTML(string)
  345. string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/n) do
  346. match = $1.dup
  347. case match
  348. when 'amp' then '&'
  349. when 'quot' then '"'
  350. when 'gt' then '>'
  351. when 'lt' then '<'
  352. when /\A#0*(\d+)\z/n then
  353. if Integer($1) < 256
  354. Integer($1).chr
  355. else
  356. if Integer($1) < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
  357. [Integer($1)].pack("U")
  358. else
  359. "&##{$1};"
  360. end
  361. end
  362. when /\A#x([0-9a-f]+)\z/ni then
  363. if $1.hex < 256
  364. $1.hex.chr
  365. else
  366. if $1.hex < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
  367. [$1.hex].pack("U")
  368. else
  369. "&#x#{$1};"
  370. end
  371. end
  372. else
  373. "&#{match};"
  374. end
  375. end
  376. end
  377. # Escape only the tags of certain HTML elements in +string+.
  378. #
  379. # Takes an element or elements or array of elements. Each element
  380. # is specified by the name of the element, without angle brackets.
  381. # This matches both the start and the end tag of that element.
  382. # The attribute list of the open tag will also be escaped (for
  383. # instance, the double-quotes surrounding attribute values).
  384. #
  385. # print CGI::escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
  386. # # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
  387. #
  388. # print CGI::escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
  389. # # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
  390. def CGI::escapeElement(string, *elements)
  391. elements = elements[0] if elements[0].kind_of?(Array)
  392. unless elements.empty?
  393. string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
  394. CGI::escapeHTML($&)
  395. end
  396. else
  397. string
  398. end
  399. end
  400. # Undo escaping such as that done by CGI::escapeElement()
  401. #
  402. # print CGI::unescapeElement(
  403. # CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
  404. # # "&lt;BR&gt;<A HREF="url"></A>"
  405. #
  406. # print CGI::unescapeElement(
  407. # CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
  408. # # "&lt;BR&gt;<A HREF="url"></A>"
  409. def CGI::unescapeElement(string, *elements)
  410. elements = elements[0] if elements[0].kind_of?(Array)
  411. unless elements.empty?
  412. string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/ni) do
  413. CGI::unescapeHTML($&)
  414. end
  415. else
  416. string
  417. end
  418. end
  419. # Format a +Time+ object as a String using the format specified by RFC 1123.
  420. #
  421. # CGI::rfc1123_date(Time.now)
  422. # # Sat, 01 Jan 2000 00:00:00 GMT
  423. def CGI::rfc1123_date(time)
  424. t = time.clone.gmtime
  425. return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
  426. RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
  427. t.hour, t.min, t.sec)
  428. end
  429. # Create an HTTP header block as a string.
  430. #
  431. # Includes the empty line that ends the header block.
  432. #
  433. # +options+ can be a string specifying the Content-Type (defaults
  434. # to text/html), or a hash of header key/value pairs. The following
  435. # header keys are recognized:
  436. #
  437. # type:: the Content-Type header. Defaults to "text/html"
  438. # charset:: the charset of the body, appended to the Content-Type header.
  439. # nph:: a boolean value. If true, prepend protocol string and status code, and
  440. # date; and sets default values for "server" and "connection" if not
  441. # explicitly set.
  442. # status:: the HTTP status code, returned as the Status header. See the
  443. # list of available status codes below.
  444. # server:: the server software, returned as the Server header.
  445. # connection:: the connection type, returned as the Connection header (for
  446. # instance, "close".
  447. # length:: the length of the content that will be sent, returned as the
  448. # Content-Length header.
  449. # language:: the language of the content, returned as the Content-Language
  450. # header.
  451. # expires:: the time on which the current content expires, as a +Time+
  452. # object, returned as the Expires header.
  453. # cookie:: a cookie or cookies, returned as one or more Set-Cookie headers.
  454. # The value can be the literal string of the cookie; a CGI::Cookie
  455. # object; an Array of literal cookie strings or Cookie objects; or a
  456. # hash all of whose values are literal cookie strings or Cookie objects.
  457. # These cookies are in addition to the cookies held in the
  458. # @output_cookies field.
  459. #
  460. # Other header lines can also be set; they are appended as key: value.
  461. #
  462. # header
  463. # # Content-Type: text/html
  464. #
  465. # header("text/plain")
  466. # # Content-Type: text/plain
  467. #
  468. # header("nph" => true,
  469. # "status" => "OK", # == "200 OK"
  470. # # "status" => "200 GOOD",
  471. # "server" => ENV['SERVER_SOFTWARE'],
  472. # "connection" => "close",
  473. # "type" => "text/html",
  474. # "charset" => "iso-2022-jp",
  475. # # Content-Type: text/html; charset=iso-2022-jp
  476. # "length" => 103,
  477. # "language" => "ja",
  478. # "expires" => Time.now + 30,
  479. # "cookie" => [cookie1, cookie2],
  480. # "my_header1" => "my_value"
  481. # "my_header2" => "my_value")
  482. #
  483. # The status codes are:
  484. #
  485. # "OK" --> "200 OK"
  486. # "PARTIAL_CONTENT" --> "206 Partial Content"
  487. # "MULTIPLE_CHOICES" --> "300 Multiple Choices"
  488. # "MOVED" --> "301 Moved Permanently"
  489. # "REDIRECT" --> "302 Found"
  490. # "NOT_MODIFIED" --> "304 Not Modified"
  491. # "BAD_REQUEST" --> "400 Bad Request"
  492. # "AUTH_REQUIRED" --> "401 Authorization Required"
  493. # "FORBIDDEN" --> "403 Forbidden"
  494. # "NOT_FOUND" --> "404 Not Found"
  495. # "METHOD_NOT_ALLOWED" --> "405 Method Not Allowed"
  496. # "NOT_ACCEPTABLE" --> "406 Not Acceptable"
  497. # "LENGTH_REQUIRED" --> "411 Length Required"
  498. # "PRECONDITION_FAILED" --> "412 Precondition Failed"
  499. # "SERVER_ERROR" --> "500 Internal Server Error"
  500. # "NOT_IMPLEMENTED" --> "501 Method Not Implemented"
  501. # "BAD_GATEWAY" --> "502 Bad Gateway"
  502. # "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
  503. #
  504. # This method does not perform charset conversion.
  505. #
  506. def header(options = "text/html")
  507. buf = ""
  508. case options
  509. when String
  510. options = { "type" => options }
  511. when Hash
  512. options = options.dup
  513. end
  514. unless options.has_key?("type")
  515. options["type"] = "text/html"
  516. end
  517. if options.has_key?("charset")
  518. options["type"] += "; charset=" + options.delete("charset")
  519. end
  520. options.delete("nph") if defined?(MOD_RUBY)
  521. if options.delete("nph") or
  522. (/IIS\/(\d+)/n.match(env_table['SERVER_SOFTWARE']) and $1.to_i < 5)
  523. buf += (env_table["SERVER_PROTOCOL"] or "HTTP/1.0") + " " +
  524. (HTTP_STATUS[options["status"]] or options["status"] or "200 OK") +
  525. EOL +
  526. "Date: " + CGI::rfc1123_date(Time.now) + EOL
  527. unless options.has_key?("server")
  528. options["server"] = (env_table['SERVER_SOFTWARE'] or "")
  529. end
  530. unless options.has_key?("connection")
  531. options["connection"] = "close"
  532. end
  533. options.delete("status")
  534. end
  535. if options.has_key?("status")
  536. buf += "Status: " +
  537. (HTTP_STATUS[options["status"]] or options["status"]) + EOL
  538. options.delete("status")
  539. end
  540. if options.has_key?("server")
  541. buf += "Server: " + options.delete("server") + EOL
  542. end
  543. if options.has_key?("connection")
  544. buf += "Connection: " + options.delete("connection") + EOL
  545. end
  546. buf += "Content-Type: " + options.delete("type") + EOL
  547. if options.has_key?("length")
  548. buf += "Content-Length: " + options.delete("length").to_s + EOL
  549. end
  550. if options.has_key?("language")
  551. buf += "Content-Language: " + options.delete("language") + EOL
  552. end
  553. if options.has_key?("expires")
  554. buf += "Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL
  555. end
  556. if options.has_key?("cookie")
  557. if options["cookie"].kind_of?(String) or
  558. options["cookie"].kind_of?(Cookie)
  559. buf += "Set-Cookie: " + options.delete("cookie").to_s + EOL
  560. elsif options["cookie"].kind_of?(Array)
  561. options.delete("cookie").each{|cookie|
  562. buf += "Set-Cookie: " + cookie.to_s + EOL
  563. }
  564. elsif options["cookie"].kind_of?(Hash)
  565. options.delete("cookie").each_value{|cookie|
  566. buf += "Set-Cookie: " + cookie.to_s + EOL
  567. }
  568. end
  569. end
  570. if @output_cookies
  571. for cookie in @output_cookies
  572. buf += "Set-Cookie: " + cookie.to_s + EOL
  573. end
  574. end
  575. options.each{|key, value|
  576. buf += key + ": " + value.to_s + EOL
  577. }
  578. if defined?(MOD_RUBY)
  579. table = Apache::request.headers_out
  580. buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value|
  581. warn sprintf("name:%s value:%s\n", name, value) if $DEBUG
  582. case name
  583. when 'Set-Cookie'
  584. table.add(name, value)
  585. when /^status$/ni
  586. Apache::request.status_line = value
  587. Apache::request.status = value.to_i
  588. when /^content-type$/ni
  589. Apache::request.content_type = value
  590. when /^content-encoding$/ni
  591. Apache::request.content_encoding = value
  592. when /^location$/ni
  593. if Apache::request.status == 200
  594. Apache::request.status = 302
  595. end
  596. Apache::request.headers_out[name] = value
  597. else
  598. Apache::request.headers_out[name] = value
  599. end
  600. }
  601. Apache::request.send_http_header
  602. ''
  603. else
  604. buf + EOL
  605. end
  606. end # header()
  607. # Print an HTTP header and body to $DEFAULT_OUTPUT ($>)
  608. #
  609. # The header is provided by +options+, as for #header().
  610. # The body of the document is that returned by the passed-
  611. # in block. This block takes no arguments. It is required.
  612. #
  613. # cgi = CGI.new
  614. # cgi.out{ "string" }
  615. # # Content-Type: text/html
  616. # # Content-Length: 6
  617. # #
  618. # # string
  619. #
  620. # cgi.out("text/plain") { "string" }
  621. # # Content-Type: text/plain
  622. # # Content-Length: 6
  623. # #
  624. # # string
  625. #
  626. # cgi.out("nph" => true,
  627. # "status" => "OK", # == "200 OK"
  628. # "server" => ENV['SERVER_SOFTWARE'],
  629. # "connection" => "close",
  630. # "type" => "text/html",
  631. # "charset" => "iso-2022-jp",
  632. # # Content-Type: text/html; charset=iso-2022-jp
  633. # "language" => "ja",
  634. # "expires" => Time.now + (3600 * 24 * 30),
  635. # "cookie" => [cookie1, cookie2],
  636. # "my_header1" => "my_value",
  637. # "my_header2" => "my_value") { "string" }
  638. #
  639. # Content-Length is automatically calculated from the size of
  640. # the String returned by the content block.
  641. #
  642. # If ENV['REQUEST_METHOD'] == "HEAD", then only the header
  643. # is outputted (the content block is still required, but it
  644. # is ignored).
  645. #
  646. # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
  647. # the content is converted to this charset, and the language is set
  648. # to "ja".
  649. def out(options = "text/html") # :yield:
  650. options = { "type" => options } if options.kind_of?(String)
  651. content = yield
  652. if options.has_key?("charset")
  653. require "nkf"
  654. case options["charset"]
  655. when /iso-2022-jp/ni
  656. content = NKF::nkf('-m0 -x -j', content)
  657. options["language"] = "ja" unless options.has_key?("language")
  658. when /euc-jp/ni
  659. content = NKF::nkf('-m0 -x -e', content)
  660. options["language"] = "ja" unless options.has_key?("language")
  661. when /shift_jis/ni
  662. content = NKF::nkf('-m0 -x -s', content)
  663. options["language"] = "ja" unless options.has_key?("language")
  664. end
  665. end
  666. options["length"] = content.length.to_s
  667. output = stdoutput
  668. output.binmode if defined? output.binmode
  669. output.print header(options)
  670. output.print content unless "HEAD" == env_table['REQUEST_METHOD']
  671. end
  672. # Print an argument or list of arguments to the default output stream
  673. #
  674. # cgi = CGI.new
  675. # cgi.print # default: cgi.print == $DEFAULT_OUTPUT.print
  676. def print(*options)
  677. stdoutput.print(*options)
  678. end
  679. require "delegate"
  680. # Class representing an HTTP cookie.
  681. #
  682. # In addition to its specific fields and methods, a Cookie instance
  683. # is a delegator to the array of its values.
  684. #
  685. # See RFC 2965.
  686. #
  687. # == Examples of use
  688. # cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
  689. # cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
  690. # cookie1 = CGI::Cookie::new('name' => 'name',
  691. # 'value' => ['value1', 'value2', ...],
  692. # 'path' => 'path', # optional
  693. # 'domain' => 'domain', # optional
  694. # 'expires' => Time.now, # optional
  695. # 'secure' => true # optional
  696. # )
  697. #
  698. # cgi.out("cookie" => [cookie1, cookie2]) { "string" }
  699. #
  700. # name = cookie1.name
  701. # values = cookie1.value
  702. # path = cookie1.path
  703. # domain = cookie1.domain
  704. # expires = cookie1.expires
  705. # secure = cookie1.secure
  706. #
  707. # cookie1.name = 'name'
  708. # cookie1.value = ['value1', 'value2', ...]
  709. # cookie1.path = 'path'
  710. # cookie1.domain = 'domain'
  711. # cookie1.expires = Time.now + 30
  712. # cookie1.secure = true
  713. class Cookie < DelegateClass(Array)
  714. # Create a new CGI::Cookie object.
  715. #
  716. # The contents of the cookie can be specified as a +name+ and one
  717. # or more +value+ arguments. Alternatively, the contents can
  718. # be specified as a single hash argument. The possible keywords of
  719. # this hash are as follows:
  720. #
  721. # name:: the name of the cookie. Required.
  722. # value:: the cookie's value or list of values.
  723. # path:: the path for which this cookie applies. Defaults to the
  724. # base directory of the CGI script.
  725. # domain:: the domain for which this cookie applies.
  726. # expires:: the time at which this cookie expires, as a +Time+ object.
  727. # secure:: whether this cookie is a secure cookie or not (default to
  728. # false). Secure cookies are only transmitted to HTTPS
  729. # servers.
  730. #
  731. # These keywords correspond to attributes of the cookie object.
  732. def initialize(name = "", *value)
  733. options = if name.kind_of?(String)
  734. { "name" => name, "value" => value }
  735. else
  736. name
  737. end
  738. unless options.has_key?("name")
  739. raise ArgumentError, "`name' required"
  740. end
  741. @name = options["name"]
  742. @value = Array(options["value"])
  743. # simple support for IE
  744. if options["path"]
  745. @path = options["path"]
  746. else
  747. %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
  748. @path = ($1 or "")
  749. end
  750. @domain = options["domain"]
  751. @expires = options["expires"]
  752. @secure = options["secure"] == true ? true : false
  753. super(@value)
  754. end
  755. attr_accessor("name", "value", "path", "domain", "expires")
  756. attr_reader("secure")
  757. # Set whether the Cookie is a secure cookie or not.
  758. #
  759. # +val+ must be a boolean.
  760. def secure=(val)
  761. @secure = val if val == true or val == false
  762. @secure
  763. end
  764. # Convert the Cookie to its string representation.
  765. def to_s
  766. buf = ""
  767. buf += @name + '='
  768. if @value.kind_of?(String)
  769. buf += CGI::escape(@value)
  770. else
  771. buf += @value.collect{|v| CGI::escape(v) }.join("&")
  772. end
  773. if @domain
  774. buf += '; domain=' + @domain
  775. end
  776. if @path
  777. buf += '; path=' + @path
  778. end
  779. if @expires
  780. buf += '; expires=' + CGI::rfc1123_date(@expires)
  781. end
  782. if @secure == true
  783. buf += '; secure'
  784. end
  785. buf
  786. end
  787. end # class Cookie
  788. # Parse a raw cookie string into a hash of cookie-name=>Cookie
  789. # pairs.
  790. #
  791. # cookies = CGI::Cookie::parse("raw_cookie_string")
  792. # # { "name1" => cookie1, "name2" => cookie2, ... }
  793. #
  794. def Cookie::parse(raw_cookie)
  795. cookies = Hash.new([])
  796. return cookies unless raw_cookie
  797. raw_cookie.split(/[;,]\s?/).each do |pairs|
  798. name, values = pairs.split('=',2)
  799. next unless name and values
  800. name = CGI::unescape(name)
  801. values ||= ""
  802. values = values.split('&').collect{|v| CGI::unescape(v) }
  803. if cookies.has_key?(name)
  804. values = cookies[name].value + values
  805. end
  806. cookies[name] = Cookie::new({ "name" => name, "value" => values })
  807. end
  808. cookies
  809. end
  810. # Parse an HTTP query string into a hash of key=>value pairs.
  811. #
  812. # params = CGI::parse("query_string")
  813. # # {"name1" => ["value1", "value2", ...],
  814. # # "name2" => ["value1", "value2", ...], ... }
  815. #
  816. def CGI::parse(query)
  817. params = Hash.new([].freeze)
  818. query.split(/[&;]/n).each do |pairs|
  819. key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) }
  820. if params.has_key?(key)
  821. params[key].push(value)
  822. else
  823. params[key] = [value]
  824. end
  825. end
  826. params
  827. end
  828. # Mixin module. It provides the follow functionality groups:
  829. #
  830. # 1. Access to CGI environment variables as methods. See
  831. # documentation to the CGI class for a list of these variables.
  832. #
  833. # 2. Access to cookies, including the cookies attribute.
  834. #
  835. # 3. Access to parameters, including the params attribute, and overloading
  836. # [] to perform parameter value lookup by key.
  837. #
  838. # 4. The initialize_query method, for initialising the above
  839. # mechanisms, handling multipart forms, and allowing the
  840. # class to be used in "offline" mode.
  841. #
  842. module QueryExtension
  843. %w[ CONTENT_LENGTH SERVER_PORT ].each do |env|
  844. define_method(env.sub(/^HTTP_/n, '').downcase) do
  845. (val = env_table[env]) && Integer(val)
  846. end
  847. end
  848. %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
  849. PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
  850. REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
  851. SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
  852. HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
  853. HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
  854. HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
  855. define_method(env.sub(/^HTTP_/n, '').downcase) do
  856. env_table[env]
  857. end
  858. end
  859. # Get the raw cookies as a string.
  860. def raw_cookie
  861. env_table["HTTP_COOKIE"]
  862. end
  863. # Get the raw RFC2965 cookies as a string.
  864. def raw_cookie2
  865. env_table["HTTP_COOKIE2"]
  866. end
  867. # Get the cookies as a hash of cookie-name=>Cookie pairs.
  868. attr_accessor("cookies")
  869. # Get the parameters as a hash of name=>values pairs, where
  870. # values is an Array.
  871. attr("params")
  872. # Set all the parameters.
  873. def params=(hash)
  874. @params.clear
  875. @params.update(hash)
  876. end
  877. def read_multipart(boundary, content_length)
  878. params = Hash.new([])
  879. boundary = "--" + boundary
  880. quoted_boundary = Regexp.quote(boundary, "n")
  881. buf = ""
  882. bufsize = 10 * 1024
  883. boundary_end=""
  884. # start multipart/form-data
  885. stdinput.binmode if defined? stdinput.binmode
  886. boundary_size = boundary.size + EOL.size
  887. content_length -= boundary_size
  888. status = stdinput.read(boundary_size)
  889. if nil == status
  890. raise EOFError, "no content body"
  891. elsif boundary + EOL != status
  892. raise EOFError, "bad content body"
  893. end
  894. loop do
  895. head = nil
  896. if 10240 < content_length
  897. require "tempfile"
  898. body = Tempfile.new("CGI")
  899. else
  900. begin
  901. require "stringio"
  902. body = StringIO.new
  903. rescue LoadError
  904. require "tempfile"
  905. body = Tempfile.new("CGI")
  906. end
  907. end
  908. body.binmode if defined? body.binmode
  909. until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)
  910. if (not head) and /#{EOL}#{EOL}/n.match(buf)
  911. buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
  912. head = $1.dup
  913. ""
  914. end
  915. next
  916. end
  917. if head and ( (EOL + boundary + EOL).size < buf.size )
  918. body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
  919. buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
  920. end
  921. c = if bufsize < content_length
  922. stdinput.read(bufsize)
  923. else
  924. stdinput.read(content_length)
  925. end
  926. if c.nil? || c.empty?
  927. raise EOFError, "bad content body"
  928. end
  929. buf.concat(c)
  930. content_length -= c.size
  931. end
  932. buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
  933. body.print $1
  934. if "--" == $2
  935. content_length = -1
  936. end
  937. boundary_end = $2.dup
  938. ""
  939. end
  940. body.rewind
  941. /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni.match(head)
  942. filename = ($1 or $2 or "")
  943. if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
  944. /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
  945. (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
  946. filename = CGI::unescape(filename)
  947. end
  948. /Content-Type: ([^\s]*)/ni.match(head)
  949. content_type = ($1 or "")
  950. (class << body; self; end).class_eval do
  951. alias local_path path
  952. define_method(:original_filename) {filename.dup.taint}
  953. define_method(:content_type) {content_type.dup.taint}
  954. end
  955. /Content-Disposition:.* name="?([^\";\s]*)"?/ni.match(head)
  956. name = $1.dup
  957. if params.has_key?(name)
  958. params[name].push(body)
  959. else
  960. params[name] = [body]
  961. end
  962. break if buf.size == 0
  963. break if content_length == -1
  964. end
  965. raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
  966. params
  967. end # read_multipart
  968. private :read_multipart
  969. # offline mode. read name=value pairs on standard input.
  970. def read_from_cmdline
  971. require "shellwords"
  972. string = unless ARGV.empty?
  973. ARGV.join(' ')
  974. else
  975. if STDIN.tty?
  976. STDERR.print(
  977. %|(offline mode: enter name=value pairs on standard input)\n|
  978. )
  979. end
  980. readlines.join(' ').gsub(/\n/n, '')
  981. end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
  982. words = Shellwords.shellwords(string)
  983. if words.find{|x| /=/n.match(x) }
  984. words.join('&')
  985. else
  986. words.join('+')
  987. end
  988. end
  989. private :read_from_cmdline
  990. # Initialize the data from the query.
  991. #
  992. # Handles multipart forms (in particular, forms that involve file uploads).
  993. # Reads query parameters in the @params field, and cookies into @cookies.
  994. def initialize_query()
  995. if ("POST" == env_table['REQUEST_METHOD']) and
  996. %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE'])
  997. boundary = $1.dup
  998. @multipart = true
  999. @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
  1000. else
  1001. @multipart = false
  1002. @params = CGI::parse(
  1003. case env_table['REQUEST_METHOD']
  1004. when "GET", "HEAD"
  1005. if defined?(MOD_RUBY)
  1006. Apache::request.args or ""
  1007. else
  1008. env_table['QUERY_STRING'] or ""
  1009. end
  1010. when "POST"
  1011. stdinput.binmode if defined? stdinput.binmode
  1012. stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
  1013. else
  1014. read_from_cmdline
  1015. end
  1016. )
  1017. end
  1018. @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
  1019. end
  1020. private :initialize_query
  1021. def multipart?
  1022. @multipart
  1023. end
  1024. module Value # :nodoc:
  1025. def set_params(params)
  1026. @params = params
  1027. end
  1028. def [](idx, *args)
  1029. if args.size == 0
  1030. warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']"
  1031. @params[idx]
  1032. else
  1033. super[idx,*args]
  1034. end
  1035. end
  1036. def first
  1037. warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']"
  1038. self
  1039. end
  1040. alias last first
  1041. def to_a
  1042. @params || [self]
  1043. end
  1044. alias to_ary to_a # to be rhs of multiple assignment
  1045. end
  1046. # Get the value for the parameter with a given key.
  1047. #
  1048. # If the parameter has multiple values, only the first will be
  1049. # retrieved; use #params() to get the array of values.
  1050. def [](key)
  1051. params = @params[key]
  1052. return '' unless params
  1053. value = params[0]
  1054. if @multipart
  1055. if value
  1056. return value
  1057. elsif defined? StringIO
  1058. StringIO.new("")
  1059. else
  1060. Tempfile.new("CGI")
  1061. end
  1062. else
  1063. str = if value then value.dup else "" end
  1064. str.extend(Value)
  1065. str.set_params(params)
  1066. str
  1067. end
  1068. end
  1069. # Return all parameter keys as an array.
  1070. def keys(*args)
  1071. @params.keys(*args)
  1072. end
  1073. # Returns true if a given parameter key exists in the query.
  1074. def has_key?(*args)
  1075. @params.has_key?(*args)
  1076. end
  1077. alias key? has_key?
  1078. alias include? has_key?
  1079. end # QueryExtension
  1080. # Prettify (indent) an HTML string.
  1081. #
  1082. # +string+ is the HTML string to indent. +shift+ is the indentation
  1083. # unit to use; it defaults to two spaces.
  1084. #
  1085. # print CGI::pretty("<HTML><BODY></BODY></HTML>")
  1086. # # <HTML>
  1087. # # <BODY>
  1088. # # </BODY>
  1089. # # </HTML>
  1090. #
  1091. # print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
  1092. # # <HTML>
  1093. # # <BODY>
  1094. # # </BODY>
  1095. # # </HTML>
  1096. #
  1097. def CGI::pretty(string, shift = " ")
  1098. lines = string.gsub(/(?!\A)<(?:.|\n)*?>/n, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/n, "\\0\n")
  1099. end_pos = 0
  1100. while end_pos = lines.index(/^<\/(\w+)/n, end_pos)
  1101. element = $1.dup
  1102. start_pos = lines.rindex(/^\s*<#{element}/ni, end_pos)
  1103. lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/n, "\n" + shift) + "__"
  1104. end
  1105. lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/n, '\1')
  1106. end
  1107. # Base module for HTML-generation mixins.
  1108. #
  1109. # Provides methods for code generation for tags following
  1110. # the various DTD element types.
  1111. module TagMaker # :nodoc:
  1112. # Generate code for an element with required start and end tags.
  1113. #
  1114. # - -
  1115. def nn_element_def(element)
  1116. nOE_element_def(element, <<-END)
  1117. if block_given?
  1118. yield.to_s
  1119. else
  1120. ""
  1121. end +
  1122. "</#{element.upcase}>"
  1123. END
  1124. end
  1125. # Generate code for an empty element.
  1126. #
  1127. # - O EMPTY
  1128. def nOE_element_def(element, append = nil)
  1129. s = <<-END
  1130. "<#{element.upcase}" + attributes.collect{|name, value|
  1131. next unless value
  1132. " " + CGI::escapeHTML(name) +
  1133. if true == value
  1134. ""
  1135. else
  1136. '="' + CGI::escapeHTML(value) + '"'
  1137. end
  1138. }.to_s + ">"
  1139. END
  1140. s.sub!(/\Z/, " +") << append if append
  1141. s
  1142. end
  1143. # Generate code for an element for which the end (and possibly the
  1144. # start) tag is optional.
  1145. #
  1146. # O O or - O
  1147. def nO_element_def(element)
  1148. nOE_element_def(element, <<-END)
  1149. if block_given?
  1150. yield.to_s + "</#{element.upcase}>"
  1151. else
  1152. ""
  1153. end
  1154. END
  1155. end
  1156. end # TagMaker
  1157. #
  1158. # Mixin module providing HTML generation methods.
  1159. #
  1160. # For example,
  1161. # cgi.a("http://www.example.com") { "Example" }
  1162. # # => "<A HREF=\"http://www.example.com\">Example</A>"
  1163. #
  1164. # Modules Http3, Http4, etc., contain more basic HTML-generation methods
  1165. # (:title, :center, etc.).
  1166. #
  1167. # See class CGI for a detailed example.
  1168. #
  1169. module HtmlExtension
  1170. # Generate an Anchor element as a string.
  1171. #
  1172. # +href+ can either be a string, giving the URL
  1173. # for the HREF attribute, or it can be a hash of
  1174. # the element's attributes.
  1175. #
  1176. # The body of the element is the string returned by the no-argument
  1177. # block passed in.
  1178. #
  1179. # a("http://www.example.com") { "Example" }
  1180. # # => "<A HREF=\"http://www.example.com\">Example</A>"
  1181. #
  1182. # a("HREF" => "http://www.example.com", "TARGET" => "_top") { "Example" }
  1183. # # => "<A HREF=\"http://www.example.com\" TARGET=\"_top\">Example</A>"
  1184. #
  1185. def a(href = "") # :yield:
  1186. attributes = if href.kind_of?(String)
  1187. { "HREF" => href }
  1188. else
  1189. href
  1190. end
  1191. if block_given?
  1192. super(attributes){ yield }
  1193. else
  1194. super(attributes)
  1195. end
  1196. end
  1197. # Generate a Document Base URI element as a String.
  1198. #
  1199. # +href+ can either by a string, giving the base URL for the HREF
  1200. # attribute, or it can be a has of the element's attributes.
  1201. #
  1202. # The passed-in no-argument block is ignored.
  1203. #
  1204. # base("http://www.example.com/cgi")
  1205. # # => "<BASE HREF=\"http://www.example.com/cgi\">"
  1206. def base(href = "") # :yield:
  1207. attributes = if href.kind_of?(String)
  1208. { "HREF" => href }
  1209. else
  1210. href
  1211. end
  1212. if block_given?
  1213. super(attributes){ yield }
  1214. else
  1215. super(attributes)
  1216. end
  1217. end
  1218. # Generate a BlockQuote element as a string.
  1219. #
  1220. # +cite+ can either be a string, give the URI for the source of
  1221. # the quoted text, or a hash, giving all attributes of the element,
  1222. # or it can be omitted, in which case the element has no attributes.
  1223. #
  1224. # The body is provided by the passed-in no-argument block
  1225. #
  1226. # blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
  1227. # #=> "<BLOCKQUOTE CITE=\"http://www.example.com/quotes/foo.html\">Foo!</BLOCKQUOTE>
  1228. def blockquote(cite = nil) # :yield:
  1229. attributes = if cite.kind_of?(String)
  1230. { "CITE" => cite }
  1231. else
  1232. cite or ""
  1233. end
  1234. if block_given?
  1235. super(attributes){ yield }
  1236. else
  1237. super(attributes)
  1238. end
  1239. end
  1240. # Generate a Table Caption element as a string.
  1241. #
  1242. # +align+ can be a string, giving the alignment of the caption
  1243. # (one of top, bottom, left, or right). It can be a hash of
  1244. # all the attributes of the element. Or it can be omitted.
  1245. #
  1246. # The body of the element is provided by the passed-in no-argument block.
  1247. #
  1248. # caption("left") { "Capital Cities" }
  1249. # # => <CAPTION ALIGN=\"left\">Capital Cities</CAPTION>
  1250. def caption(align = nil) # :yield:
  1251. attributes = if align.kind_of?(String)
  1252. { "ALIGN" => align }
  1253. else
  1254. align or ""
  1255. end
  1256. if block_given?
  1257. super(attributes){ yield }
  1258. else
  1259. super(attributes)
  1260. end
  1261. end
  1262. # Generate a Checkbox Input element as a string.
  1263. #
  1264. # The attributes of the element can be specified as three arguments,
  1265. # +name+, +value+, and +checked+. +checked+ is a boolean value;
  1266. # if true, the CHECKED attribute will be included in the element.
  1267. #
  1268. # Alternatively, the attributes can be specified as a hash.
  1269. #
  1270. # checkbox("name")
  1271. # # = checkbox("NAME" => "name")
  1272. #
  1273. # checkbox("name", "value")
  1274. # # = checkbox("NAME" => "name", "VALUE" => "value")
  1275. #
  1276. # checkbox("name", "value", true)
  1277. # # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true)
  1278. def checkbox(name = "", value = nil, checked = nil)
  1279. attributes = if name.kind_of?(String)
  1280. { "TYPE" => "checkbox", "NAME" => name,
  1281. "VALUE" => value, "CHECKED" => checked }
  1282. else
  1283. name["TYPE"] = "checkbox"
  1284. name
  1285. end
  1286. input(attributes)
  1287. end
  1288. # Generate a sequence of checkbox elements, as a String.
  1289. #
  1290. # The checkboxes will all have the same +name+ attribute.
  1291. # Each checkbox is followed by a label.
  1292. # There will be one checkbox for each value. Each value
  1293. # can be specified as a String, which will be used both
  1294. # as the value of the VALUE attribute and as the label
  1295. # for that checkbox. A single-element array has the
  1296. # same effect.
  1297. #
  1298. # Each value can also be specified as a three-element array.
  1299. # The first element is the VALUE attribute; the second is the
  1300. # label; and the third is a boolean specifying whether this
  1301. # checkbox is CHECKED.
  1302. #
  1303. # Each value can also be specified as a two-element
  1304. # array, by omitting either the value element (defaults
  1305. # to the same as the label), or the boolean checked element
  1306. # (defaults to false).
  1307. #
  1308. # checkbox_group("name", "foo", "bar", "baz")
  1309. # # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
  1310. # # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
  1311. # # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
  1312. #
  1313. # checkbox_group("name", ["foo"], ["bar", true], "baz")
  1314. # # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
  1315. # # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
  1316. # # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
  1317. #
  1318. # checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
  1319. # # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
  1320. # # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
  1321. # # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
  1322. #
  1323. # checkbox_group("NAME" => "name",
  1324. # "VALUES" => ["foo", "bar", "baz"])
  1325. #
  1326. # checkbox_group("NAME" => "name",
  1327. # "VALUES" => [["foo"], ["bar", true], "baz"])
  1328. #
  1329. # checkbox_group("NAME" => "name",
  1330. # "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
  1331. def checkbox_group(name = "", *values)
  1332. if name.kind_of?(Hash)
  1333. values = name["VALUES"]
  1334. name = name["NAME"]
  1335. end
  1336. values.collect{|value|
  1337. if value.kind_of?(String)
  1338. checkbox(name, value) + value
  1339. else
  1340. if value[value.size - 1] == true
  1341. checkbox(name, value[0], true) +
  1342. value[value.size - 2]
  1343. else
  1344. checkbox(name, value[0]) +
  1345. value[value.size - 1]
  1346. end
  1347. end
  1348. }.to_s
  1349. end
  1350. # Generate an File Upload Input element as a string.
  1351. #
  1352. # The attributes of the element can be specified as three arguments,
  1353. # +name+, +size+, and +maxlength+. +maxlength+ is the maximum length
  1354. # of the file's _name_, not of the file's _contents_.
  1355. #
  1356. # Alternatively, the attributes can be specified as a hash.
  1357. #
  1358. # See #multipart_form() for forms that include file uploads.
  1359. #
  1360. # file_field("name")
  1361. # # <INPUT TYPE="file" NAME="name" SIZE="20">
  1362. #
  1363. # file_field("name", 40)
  1364. # # <INPUT TYPE="file" NAME="name" SIZE="40">
  1365. #
  1366. # file_field("name", 40, 100)
  1367. # # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
  1368. #
  1369. # file_field("NAME" => "name", "SIZE" => 40)
  1370. # # <INPUT TYPE="file" NAME="name" SIZE="40">
  1371. def file_field(name = "", size = 20, maxlength = nil)
  1372. attributes = if name.kind_of?(String)
  1373. { "TYPE" => "file", "NAME" => name,
  1374. "SIZE" => size.to_s }
  1375. else
  1376. name["TYPE"] = "file"
  1377. name
  1378. end
  1379. attributes["MAXLENGTH"] = maxlength.to_s if maxlength
  1380. input(attributes)
  1381. end
  1382. # Generate a Form element as a string.
  1383. #
  1384. # +method+ should be either "get" or "post", and defaults to the latter.
  1385. # +action+ defaults to the current CGI script name. +enctype+
  1386. # defaults to "application/x-www-form-urlencoded".
  1387. #
  1388. # Alternatively, the attributes can be specified as a hash.
  1389. #
  1390. # See also #multipart_form() for forms that include file uploads.
  1391. #
  1392. # form{ "string" }
  1393. # # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
  1394. #
  1395. # form("get") { "string" }
  1396. # # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
  1397. #
  1398. # form("get", "url") { "string" }
  1399. # # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
  1400. #
  1401. # form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" }
  1402. # # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
  1403. def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
  1404. attributes = if method.kind_of?(String

Large files files are truncated, but you can click here to view the full file