lib/cgi.rb
DEFINITIONS
This source file includes following functions.
1 =begin
2
3 == NAME
4
5 cgi.rb - cgi support library
6
7 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
8
9 Copyright (C) 2000 Information-technology Promotion Agency, Japan
10
11 Wakou Aoyama <wakou@ruby-lang.org>
12
13
14
15 == EXAMPLE
16
17 === GET FORM VALUES
18
19 require "cgi"
20 cgi = CGI.new
21 values = cgi['field_name'] # <== array of 'field_name'
22 # if not 'field_name' included, then return [].
23 fields = cgi.keys # <== array of field names
24
25 # returns true if form has 'field_name'
26 cgi.has_key?('field_name')
27 cgi.has_key?('field_name')
28 cgi.include?('field_name')
29
30
31 === GET FORM VALUES AS HASH
32
33 require "cgi"
34 cgi = CGI.new
35 params = cgi.params
36
37 cgi.params is a hash.
38
39 cgi.params['new_field_name'] = ["value"] # add new param
40 cgi.params['field_name'] = ["new_value"] # change value
41 cgi.params.delete('field_name') # delete param
42 cgi.params.clear # delete all params
43
44
45 === SAVE FORM VALUES TO FILE
46
47 require "pstore"
48 db = PStore.new("query.db")
49 db.transaction do
50 db["params"] = cgi.params
51 end
52
53
54 === RESTORE FORM VALUES FROM FILE
55
56 require "pstore"
57 db = PStore.new("query.db")
58 db.transaction do
59 cgi.params = db["params"]
60 end
61
62
63 === GET MULTIPART FORM VALUES
64
65 require "cgi"
66 cgi = CGI.new
67 values = cgi['field_name'] # <== array of 'field_name'
68 values[0].read # <== body of values[0]
69 values[0].local_path # <== path to local file of values[0]
70 values[0].original_filename # <== original filename of values[0]
71 values[0].content_type # <== content_type of values[0]
72
73 and values[0] has StringIO or Tempfile class methods.
74
75
76 === GET COOKIE VALUES
77
78 require "cgi"
79 cgi = CGI.new
80 values = cgi.cookies['name'] # <== array of 'name'
81 # if not 'name' included, then return [].
82 names = cgi.cookies.keys # <== array of cookie names
83
84 and cgi.cookies is a hash.
85
86
87 === GET COOKIE OBJECTS
88
89 require "cgi"
90 cgi = CGI.new
91 for name, cookie in cgi.cookies
92 cookie.expires = Time.now + 30
93 end
94 cgi.out("cookie" => cgi.cookies){"string"}
95
96 cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
97
98 require "cgi"
99 cgi = CGI.new
100 cgi.cookies['name'].expires = Time.now + 30
101 cgi.out("cookie" => cgi.cookies['name']){"string"}
102
103 and see MAKE COOKIE OBJECT.
104
105
106 === GET ENVIRONMENT VALUE
107
108 require "cgi"
109 cgi = CGI.new
110 value = cgi.auth_type
111 # ENV["AUTH_TYPE"]
112
113 see http:
114
115 AUTH_TYPE CONTENT_LENGTH CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
116 PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_IDENT
117 REMOTE_USER REQUEST_METHOD SCRIPT_NAME SERVER_NAME SERVER_PORT
118 SERVER_PROTOCOL SERVER_SOFTWARE
119
120 content_length and server_port return Integer. and the others return String.
121
122 and HTTP_COOKIE, HTTP_COOKIE2
123
124 value = cgi.raw_cookie
125 # ENV["HTTP_COOKIE"]
126 value = cgi.raw_cookie2
127 # ENV["HTTP_COOKIE2"]
128
129 and other HTTP_*
130
131 value = cgi.accept
132 # ENV["HTTP_ACCEPT"]
133 value = cgi.accept_charset
134 # ENV["HTTP_ACCEPT_CHARSET"]
135
136 HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
137 HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST HTTP_NEGOTIATE HTTP_PRAGMA
138 HTTP_REFERER HTTP_USER_AGENT
139
140
141 === PRINT HTTP HEADER AND HTML STRING TO $DEFAULT_OUTPUT ($>)
142
143 require "cgi"
144 cgi = CGI.new("html3") # add HTML generation methods
145 cgi.out() do
146 cgi.html() do
147 cgi.head{ cgi.title{"TITLE"} } +
148 cgi.body() do
149 cgi.form() do
150 cgi.textarea("get_text") +
151 cgi.br +
152 cgi.submit
153 end +
154 cgi.pre() do
155 CGI::escapeHTML(
156 "params: " + cgi.params.inspect + "\n" +
157 "cookies: " + cgi.cookies.inspect + "\n" +
158 ENV.collect() do |key, value|
159 key + " --> " + value + "\n"
160 end.join("")
161 )
162 end
163 end
164 end
165 end
166
167 # add HTML generation methods
168 CGI.new("html3") # html3.2
169 CGI.new("html4") # html4.01 (Strict)
170 CGI.new("html4Tr") # html4.01 Transitional
171 CGI.new("html4Fr") # html4.01 Frameset
172
173
174 =end
175
176 raise "Please, use ruby1.5.4 or later." if RUBY_VERSION < "1.5.4"
177
178 require 'English'
179
180 class CGI
181
182 CR = "\015"
183 LF = "\012"
184 EOL = CR + LF
185 REVISION = '$Id: cgi.rb,v 1.42 2002/08/25 20:15:05 wakou Exp $'
186
187 NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM)
188 PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
189
190 HTTP_STATUS = {
191 "OK" => "200 OK",
192 "PARTIAL_CONTENT" => "206 Partial Content",
193 "MULTIPLE_CHOICES" => "300 Multiple Choices",
194 "MOVED" => "301 Moved Permanently",
195 "REDIRECT" => "302 Found",
196 "NOT_MODIFIED" => "304 Not Modified",
197 "BAD_REQUEST" => "400 Bad Request",
198 "AUTH_REQUIRED" => "401 Authorization Required",
199 "FORBIDDEN" => "403 Forbidden",
200 "NOT_FOUND" => "404 Not Found",
201 "METHOD_NOT_ALLOWED" => "405 Method Not Allowed",
202 "NOT_ACCEPTABLE" => "406 Not Acceptable",
203 "LENGTH_REQUIRED" => "411 Length Required",
204 "PRECONDITION_FAILED" => "412 Rrecondition Failed",
205 "SERVER_ERROR" => "500 Internal Server Error",
206 "NOT_IMPLEMENTED" => "501 Method Not Implemented",
207 "BAD_GATEWAY" => "502 Bad Gateway",
208 "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
209 }
210
211 RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
212 RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
213
214 def env_table
215 ENV
216 end
217
218 def stdinput
219 $stdin
220 end
221
222 def stdoutput
223 $DEFAULT_OUTPUT
224 end
225
226 private :env_table, :stdinput, :stdoutput
227
228 =begin
229 == METHODS
230 =end
231
232 =begin
233 === ESCAPE URL ENCODE
234 url_encoded_string = CGI::escape("string")
235 =end
236 def CGI::escape(string)
237 string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
238 '%' + $1.unpack('H2' * $1.size).join('%').upcase
239 end.tr(' ', '+')
240 end
241
242
243 =begin
244 === UNESCAPE URL ENCODED
245 string = CGI::unescape("url encoded string")
246 =end
247 def CGI::unescape(string)
248 string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
249 [$1.delete('%')].pack('H*')
250 end
251 end
252
253
254 =begin
255 === ESCAPE HTML &\"<>
256 CGI::escapeHTML("string")
257 =end
258 def CGI::escapeHTML(string)
259 string.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/</n, '<')
260 end
261
262
263 =begin
264 === UNESCAPE HTML
265 CGI::unescapeHTML("HTML escaped string")
266 =end
267 def CGI::unescapeHTML(string)
268 string.gsub(/&(.*?);/n) do
269 match = $1.dup
270 case match
271 when /\Aamp\z/ni then '&'
272 when /\Aquot\z/ni then '"'
273 when /\Agt\z/ni then '>'
274 when /\Alt\z/ni then '<'
275 when /\A#0*(\d+)\z/n then
276 if Integer($1) < 256
277 Integer($1).chr
278 else
279 if Integer($1) < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
280 [Integer($1)].pack("U")
281 else
282 "&##{$1};"
283 end
284 end
285 when /\A#x([0-9a-f]+)\z/ni then
286 if $1.hex < 256
287 $1.hex.chr
288 else
289 if $1.hex < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
290 [$1.hex].pack("U")
291 else
292 "&#x#{$1};"
293 end
294 end
295 else
296 "&#{match};"
297 end
298 end
299 end
300
301
302 =begin
303 === ESCAPE ELEMENT
304 print CGI::escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
305 # "<BR><A HREF="url"></A>"
306
307 print CGI::escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
308 # "<BR><A HREF="url"></A>"
309 =end
310 def CGI::escapeElement(string, *elements)
311 elements = elements[0] if elements[0].kind_of?(Array)
312 unless elements.empty?
313 string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
314 CGI::escapeHTML($&)
315 end
316 else
317 string
318 end
319 end
320
321
322 =begin
323 === UNESCAPE ELEMENT
324 print CGI::unescapeElement(
325 CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
326 # "<BR><A HREF="url"></A>"
327
328 print CGI::unescapeElement(
329 CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
330 # "<BR><A HREF="url"></A>"
331 =end
332 def CGI::unescapeElement(string, *elements)
333 elements = elements[0] if elements[0].kind_of?(Array)
334 unless elements.empty?
335 string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
336 CGI::unescapeHTML($&)
337 end
338 else
339 string
340 end
341 end
342
343
344 =begin
345 === MAKE RFC1123 DATE STRING
346 CGI::rfc1123_date(Time.now)
347 # Sat, 01 Jan 2000 00:00:00 GMT
348 =end
349 def CGI::rfc1123_date(time)
350 t = time.clone.gmtime
351 return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
352 RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
353 t.hour, t.min, t.sec)
354 end
355
356
357 =begin
358 === MAKE HTTP HEADER STRING
359 header
360 # Content-Type: text/html
361
362 header("text/plain")
363 # Content-Type: text/plain
364
365 header({"nph" => true,
366 "status" => "OK", # == "200 OK"
367 # "status" => "200 GOOD",
368 "server" => ENV['SERVER_SOFTWARE'],
369 "connection" => "close",
370 "type" => "text/html",
371 "charset" => "iso-2022-jp",
372 # Content-Type: text/html; charset=iso-2022-jp
373 "language" => "ja",
374 "expires" => Time.now + 30,
375 "cookie" => [cookie1, cookie2],
376 "my_header1" => "my_value"
377 "my_header2" => "my_value"})
378
379 header will not convert charset.
380
381 status:
382
383 "OK" --> "200 OK"
384 "PARTIAL_CONTENT" --> "206 Partial Content"
385 "MULTIPLE_CHOICES" --> "300 Multiple Choices"
386 "MOVED" --> "301 Moved Permanently"
387 "REDIRECT" --> "302 Found"
388 "NOT_MODIFIED" --> "304 Not Modified"
389 "BAD_REQUEST" --> "400 Bad Request"
390 "AUTH_REQUIRED" --> "401 Authorization Required"
391 "FORBIDDEN" --> "403 Forbidden"
392 "NOT_FOUND" --> "404 Not Found"
393 "METHOD_NOT_ALLOWED" --> "405 Method Not Allowed"
394 "NOT_ACCEPTABLE" --> "406 Not Acceptable"
395 "LENGTH_REQUIRED" --> "411 Length Required"
396 "PRECONDITION_FAILED" --> "412 Rrecondition Failed"
397 "SERVER_ERROR" --> "500 Internal Server Error"
398 "NOT_IMPLEMENTED" --> "501 Method Not Implemented"
399 "BAD_GATEWAY" --> "502 Bad Gateway"
400 "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
401
402 =end
403 def header(options = "text/html")
404
405 buf = ""
406
407 case options
408 when String
409 options = { "type" => options }
410 when Hash
411 options = options.dup
412 end
413
414 unless options.has_key?("type")
415 options["type"] = "text/html"
416 end
417
418 if options.has_key?("charset")
419 options["type"] += "; charset=" + options.delete("charset")
420 end
421
422 options.delete("nph") if defined?(MOD_RUBY)
423 if options.delete("nph") or /IIS/n.match(env_table['SERVER_SOFTWARE'])
424 buf += (env_table["SERVER_PROTOCOL"] or "HTTP/1.0") + " " +
425 (HTTP_STATUS[options["status"]] or options["status"] or "200 OK") +
426 EOL +
427 "Date: " + CGI::rfc1123_date(Time.now) + EOL
428
429 unless options.has_key?("server")
430 options["server"] = (env_table['SERVER_SOFTWARE'] or "")
431 end
432
433 unless options.has_key?("connection")
434 options["connection"] = "close"
435 end
436
437 options.delete("status")
438 end
439
440 if options.has_key?("status")
441 buf += "Status: " +
442 (HTTP_STATUS[options["status"]] or options["status"]) + EOL
443 options.delete("status")
444 end
445
446 if options.has_key?("server")
447 buf += "Server: " + options.delete("server") + EOL
448 end
449
450 if options.has_key?("connection")
451 buf += "Connection: " + options.delete("connection") + EOL
452 end
453
454 buf += "Content-Type: " + options.delete("type") + EOL
455
456 if options.has_key?("length")
457 buf += "Content-Length: " + options.delete("length").to_s + EOL
458 end
459
460 if options.has_key?("language")
461 buf += "Content-Language: " + options.delete("language") + EOL
462 end
463
464 if options.has_key?("expires")
465 buf += "Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL
466 end
467
468 if options.has_key?("cookie")
469 if options["cookie"].kind_of?(String) or
470 options["cookie"].kind_of?(Cookie)
471 buf += "Set-Cookie: " + options.delete("cookie").to_s + EOL
472 elsif options["cookie"].kind_of?(Array)
473 options.delete("cookie").each{|cookie|
474 buf += "Set-Cookie: " + cookie.to_s + EOL
475 }
476 elsif options["cookie"].kind_of?(Hash)
477 options.delete("cookie").each_value{|cookie|
478 buf += "Set-Cookie: " + cookie.to_s + EOL
479 }
480 end
481 end
482 if @output_cookies
483 for cookie in @output_cookies
484 buf += "Set-Cookie: " + cookie.to_s + EOL
485 end
486 end
487
488 options.each{|key, value|
489 buf += key + ": " + value.to_s + EOL
490 }
491
492 if defined?(MOD_RUBY)
493 table = Apache::request.headers_out
494 buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value|
495 $stderr.printf("name:%s value:%s\n", name, value) if $DEBUG
496 case name
497 when 'Set-Cookie'
498 table.add($1, $2)
499 when /^status$/ni
500 Apache::request.status_line = value
501 Apache::request.status = value.to_i
502 when /^content-type$/ni
503 Apache::request.content_type = value
504 when /^content-encoding$/ni
505 Apache::request.content_encoding = value
506 when /^location$/ni
507 if Apache::request.status == 200
508 Apache::request.status = 302
509 end
510 Apache::request.headers_out[name] = value
511 else
512 Apache::request.headers_out[name] = value
513 end
514 }
515 Apache::request.send_http_header
516 ''
517 else
518 buf + EOL
519 end
520
521 end # header()
522
523
524 =begin
525 === PRINT HTTP HEADER AND STRING TO $DEFAULT_OUTPUT ($>)
526 cgi = CGI.new
527 cgi.out{ "string" }
528 # Content-Type: text/html
529 # Content-Length: 6
530 #
531 # string
532
533 cgi.out("text/plain"){ "string" }
534 # Content-Type: text/plain
535 # Content-Length: 6
536 #
537 # string
538
539 cgi.out({"nph" => true,
540 "status" => "OK", # == "200 OK"
541 "server" => ENV['SERVER_SOFTWARE'],
542 "connection" => "close",
543 "type" => "text/html",
544 "charset" => "iso-2022-jp",
545 # Content-Type: text/html; charset=iso-2022-jp
546 "language" => "ja",
547 "expires" => Time.now + (3600 * 24 * 30),
548 "cookie" => [cookie1, cookie2],
549 "my_header1" => "my_value",
550 "my_header2" => "my_value"}){ "string" }
551
552 if "HEAD" == REQUEST_METHOD then output only HTTP header.
553
554 if charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
555 convert string charset, and set language to "ja".
556
557 =end
558 def out(options = "text/html")
559
560 options = { "type" => options } if options.kind_of?(String)
561 content = yield
562
563 if options.has_key?("charset")
564 require "nkf"
565 case options["charset"]
566 when /iso-2022-jp/ni
567 content = NKF::nkf('-j', content)
568 options["language"] = "ja" unless options.has_key?("language")
569 when /euc-jp/ni
570 content = NKF::nkf('-e', content)
571 options["language"] = "ja" unless options.has_key?("language")
572 when /shift_jis/ni
573 content = NKF::nkf('-s', content)
574 options["language"] = "ja" unless options.has_key?("language")
575 end
576 end
577
578 options["length"] = content.length.to_s
579 output = stdoutput
580 output.binmode if defined? output.binmode
581 output.print header(options)
582 output.print content unless "HEAD" == env_table['REQUEST_METHOD']
583 end
584
585
586 =begin
587 === PRINT
588 cgi = CGI.new
589 cgi.print # default: cgi.print == $DEFAULT_OUTPUT.print
590 =end
591 def print(*options)
592 stdoutput.print(*options)
593 end
594
595
596 =begin
597 === MAKE COOKIE OBJECT
598 cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
599 cookie1 = CGI::Cookie::new({"name" => "name", "value" => "value"})
600 cookie1 = CGI::Cookie::new({'name' => 'name',
601 'value' => ['value1', 'value2', ...],
602 'path' => 'path', # optional
603 'domain' => 'domain', # optional
604 'expires' => Time.now, # optional
605 'secure' => true # optional
606 })
607
608 cgi.out({"cookie" => [cookie1, cookie2]}){ "string" }
609
610 name = cookie1.name
611 values = cookie1.value
612 path = cookie1.path
613 domain = cookie1.domain
614 expires = cookie1.expires
615 secure = cookie1.secure
616
617 cookie1.name = 'name'
618 cookie1.value = ['value1', 'value2', ...]
619 cookie1.path = 'path'
620 cookie1.domain = 'domain'
621 cookie1.expires = Time.now + 30
622 cookie1.secure = true
623 =end
624 require "delegate"
625 class Cookie < SimpleDelegator
626
627 def initialize(name = "", *value)
628 options = if name.kind_of?(String)
629 { "name" => name, "value" => value }
630 else
631 name
632 end
633 unless options.has_key?("name")
634 raise ArgumentError, "`name' required"
635 end
636
637 @name = options["name"]
638 @value = Array(options["value"])
639 # simple support for IE
640 if options["path"]
641 @path = options["path"]
642 else
643 %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
644 @path = ($1 or "")
645 end
646 @domain = options["domain"]
647 @expires = options["expires"]
648 @secure = options["secure"] == true ? true : false
649
650 super(@value)
651 end
652
653 attr_accessor("name", "value", "path", "domain", "expires")
654 attr_reader("secure")
655 def secure=(val)
656 @secure = val if val == true or val == false
657 @secure
658 end
659
660 def to_s
661 buf = ""
662 buf += @name + '='
663
664 if @value.kind_of?(String)
665 buf += CGI::escape(@value)
666 else
667 buf += @value.collect{|v| CGI::escape(v) }.join("&")
668 end
669
670 if @domain
671 buf += '; domain=' + @domain
672 end
673
674 if @path
675 buf += '; path=' + @path
676 end
677
678 if @expires
679 buf += '; expires=' + CGI::rfc1123_date(@expires)
680 end
681
682 if @secure == true
683 buf += '; secure'
684 end
685
686 buf
687 end
688
689 end # class Cookie
690
691
692 =begin
693 === PARSE RAW COOKIE STRING
694 cookies = CGI::Cookie::parse("raw_cookie_string")
695 # { "name1" => cookie1, "name2" => cookie2, ... }
696 =end
697 def Cookie::parse(raw_cookie)
698 cookies = Hash.new([])
699 return cookies unless raw_cookie
700
701 raw_cookie.split('; ').each do |pairs|
702 name, values = pairs.split('=',2)
703 name = CGI::unescape(name)
704 values ||= ""
705 values = values.split('&').collect{|v| CGI::unescape(v) }
706 unless cookies.has_key?(name)
707 cookies[name] = Cookie::new({ "name" => name, "value" => values })
708 end
709 end
710
711 cookies
712 end
713
714
715 =begin
716 === PARSE QUERY STRING
717 params = CGI::parse("query_string")
718 # {"name1" => ["value1", "value2", ...],
719 # "name2" => ["value1", "value2", ...], ... }
720 =end
721 def CGI::parse(query)
722 params = Hash.new([])
723
724 query.split(/[&;]/n).each do |pairs|
725 key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) }
726 if params.has_key?(key)
727 params[key].push(value)
728 else
729 params[key] = [value]
730 end
731 end
732
733 params
734 end
735
736
737 module QueryExtension
738
739 for env in %w[ CONTENT_LENGTH SERVER_PORT ]
740 eval( <<-END )
741 def #{env.sub(/^HTTP_/n, '').downcase}
742 env_table["#{env}"] && Integer(env_table["#{env}"])
743 end
744 END
745 end
746
747 for env in %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
748 PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
749 REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
750 SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
751
752 HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
753 HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
754 HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ]
755 eval( <<-END )
756 def #{env.sub(/^HTTP_/n, '').downcase}
757 env_table["#{env}"]
758 end
759 END
760 end
761
762 def raw_cookie
763 env_table["HTTP_COOKIE"]
764 end
765
766 def raw_cookie2
767 env_table["HTTP_COOKIE2"]
768 end
769
770 attr_accessor("cookies")
771 attr("params")
772 def params=(hash)
773 @params.clear
774 @params.update(hash)
775 end
776
777 def read_multipart(boundary, content_length)
778 params = Hash.new([])
779 boundary = "--" + boundary
780 buf = ""
781 bufsize = 10 * 1024
782
783 # start multipart/form-data
784 stdinput.binmode
785 boundary_size = boundary.size + EOL.size
786 content_length -= boundary_size
787 status = stdinput.read(boundary_size)
788 if nil == status
789 raise EOFError, "no content body"
790 elsif boundary + EOL != status
791 raise EOFError, "bad content body"
792 end
793
794 until -1 == content_length
795 head = nil
796 if 10240 < content_length
797 require "tempfile"
798 body = Tempfile.new("CGI")
799 else
800 begin
801 require "stringio" if not defined? StringIO
802 body = StringIO.new
803 rescue LoadError
804 require "tempfile"
805 body = Tempfile.new("CGI")
806 end
807 end
808 body.binmode
809
810 until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
811
812 if (not head) and /#{EOL}#{EOL}/n.match(buf)
813 buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
814 head = $1.dup
815 ""
816 end
817 next
818 end
819
820 if head and ( (EOL + boundary + EOL).size < buf.size )
821 body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
822 buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
823 end
824
825 c = if bufsize < content_length
826 stdinput.read(bufsize) or ''
827 else
828 stdinput.read(content_length) or ''
829 end
830 buf += c
831 content_length -= c.size
832
833 end
834
835 buf = buf.sub(/\A((?:.|\n)*?)(?:#{EOL})?#{boundary}(#{EOL}|--)/n) do
836 body.print $1
837 if "--" == $2
838 content_length = -1
839 end
840 ""
841 end
842
843 body.rewind
844
845 eval <<-END
846 def body.local_path
847 #{body.path.dump}
848 end
849 END
850
851 /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
852 eval <<-END
853 def body.original_filename
854 #{
855 filename = ($1 or "").dup
856 if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
857 /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
858 (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
859 CGI::unescape(filename)
860 else
861 filename
862 end.dump.untaint
863 }.taint
864 end
865 END
866
867 /Content-Type: (.*)/ni.match(head)
868 eval <<-END
869 def body.content_type
870 #{($1 or "").dump.untaint}.taint
871 end
872 END
873
874 /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
875 name = $1.dup
876
877 if params.has_key?(name)
878 params[name].push(body)
879 else
880 params[name] = [body]
881 end
882
883 end
884
885 params
886 end # read_multipart
887 private :read_multipart
888
889 # offline mode. read name=value pairs on standard input.
890 def read_from_cmdline
891 require "shellwords"
892
893 string = unless ARGV.empty?
894 ARGV.join(' ')
895 else
896 if STDIN.tty?
897 STDERR.print(
898 %|(offline mode: enter name=value pairs on standard input)\n|
899 )
900 end
901 readlines.join(' ').gsub(/\n/n, '')
902 end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
903
904 words = Shellwords.shellwords(string)
905
906 if words.find{|x| /=/n.match(x) }
907 words.join('&')
908 else
909 words.join('+')
910 end
911 end
912 private :read_from_cmdline
913
914 def initialize_query()
915 if ("POST" == env_table['REQUEST_METHOD']) and
916 %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE'])
917 boundary = $1.dup
918 @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
919 else
920 @params = CGI::parse(
921 case env_table['REQUEST_METHOD']
922 when "GET", "HEAD"
923 if defined?(MOD_RUBY)
924 Apache::request.args or ""
925 else
926 env_table['QUERY_STRING'] or ""
927 end
928 when "POST"
929 stdinput.binmode
930 stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
931 else
932 read_from_cmdline
933 end
934 )
935 end
936
937 @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
938
939 end
940 private :initialize_query
941
942 def [](*args)
943 @params[*args]
944 end
945
946 def keys(*args)
947 @params.keys(*args)
948 end
949
950 def has_key?(*args)
951 @params.has_key?(*args)
952 end
953 alias key? has_key?
954 alias include? has_key?
955
956 end # QueryExtension
957
958
959 =begin
960 === HTML PRETTY FORMAT
961 print CGI::pretty("<HTML><BODY></BODY></HTML>")
962 # <HTML>
963 # <BODY>
964 # </BODY>
965 # </HTML>
966
967 print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
968 # <HTML>
969 # <BODY>
970 # </BODY>
971 # </HTML>
972 =end
973 def CGI::pretty(string, shift = " ")
974 lines = string.gsub(/(?!\A)<(?:.|\n)*?>/n, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/n, "\\0\n")
975 end_pos = 0
976 while end_pos = lines.index(/^<\/(\w+)/n, end_pos)
977 element = $1.dup
978 start_pos = lines.rindex(/^\s*<#{element}/ni, end_pos)
979 lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/n, "\n" + shift) + "__"
980 end
981 lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/n, '\1')
982 end
983
984
985 =begin
986 == HTML ELEMENTS
987
988 cgi = CGI.new("html3") # add HTML generation methods
989 cgi.element
990 cgi.element{ "string" }
991 cgi.element({ "ATTRIBUTE1" => "value1", "ATTRIBUTE2" => "value2" })
992 cgi.element({ "ATTRIBUTE1" => "value1", "ATTRIBUTE2" => "value2" }){ "string" }
993
994 # add HTML generation methods
995 CGI.new("html3") # html3.2
996 CGI.new("html4") # html4.0 (Strict)
997 CGI.new("html4Tr") # html4.0 Transitional
998 CGI.new("html4Fr") # html4.0 Frameset
999
1000 =end
1001
1002
1003 module TagMaker
1004
1005 # - -
1006 def nn_element_def(element)
1007 <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase)
1008 "<element.upcase" + attributes.collect{|name, value|
1009 next unless value
1010 " " + CGI::escapeHTML(name) +
1011 if true == value
1012 ""
1013 else
1014 '="' + CGI::escapeHTML(value) + '"'
1015 end
1016 }.to_s + ">" +
1017 if block_given?
1018 yield.to_s
1019 else
1020 ""
1021 end +
1022 "</element.upcase>"
1023 END
1024 end
1025
1026 # - O EMPTY
1027 def nOE_element_def(element)
1028 <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase)
1029 "<element.upcase" + attributes.collect{|name, value|
1030 next unless value
1031 " " + CGI::escapeHTML(name) +
1032 if true == value
1033 ""
1034 else
1035 '="' + CGI::escapeHTML(value) + '"'
1036 end
1037 }.to_s + ">"
1038 END
1039 end
1040
1041 # O O or - O
1042 def nO_element_def(element)
1043 <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase)
1044 "<element.upcase" + attributes.collect{|name, value|
1045 next unless value
1046 " " + CGI::escapeHTML(name) +
1047 if true == value
1048 ""
1049 else
1050 '="' + CGI::escapeHTML(value) + '"'
1051 end
1052 }.to_s + ">" +
1053 if block_given?
1054 yield.to_s + "</element.upcase>"
1055 else
1056 ""
1057 end
1058 END
1059 end
1060
1061 end # TagMaker
1062
1063
1064 module HtmlExtension
1065
1066
1067 =begin
1068 === A ELEMENT
1069 a("url")
1070 # = a({ "HREF" => "url" })
1071 =end
1072 def a(href = "")
1073 attributes = if href.kind_of?(String)
1074 { "HREF" => href }
1075 else
1076 href
1077 end
1078 if block_given?
1079 super(attributes){ yield }
1080 else
1081 super(attributes)
1082 end
1083 end
1084
1085
1086 =begin
1087 === BASE ELEMENT
1088 base("url")
1089 # = base({ "HREF" => "url" })
1090 =end
1091 def base(href = "")
1092 attributes = if href.kind_of?(String)
1093 { "HREF" => href }
1094 else
1095 href
1096 end
1097 if block_given?
1098 super(attributes){ yield }
1099 else
1100 super(attributes)
1101 end
1102 end
1103
1104
1105 =begin
1106 === BLOCKQUOTE ELEMENT
1107 blockquote("url"){ "string" }
1108 # = blockquote({ "CITE" => "url" }){ "string" }
1109 =end
1110 def blockquote(cite = nil)
1111 attributes = if cite.kind_of?(String)
1112 { "CITE" => cite }
1113 else
1114 cite or ""
1115 end
1116 if block_given?
1117 super(attributes){ yield }
1118 else
1119 super(attributes)
1120 end
1121 end
1122
1123
1124 =begin
1125 === CAPTION ELEMENT
1126 caption("align"){ "string" }
1127 # = caption({ "ALIGN" => "align" }){ "string" }
1128 =end
1129 def caption(align = nil)
1130 attributes = if align.kind_of?(String)
1131 { "ALIGN" => align }
1132 else
1133 align or ""
1134 end
1135 if block_given?
1136 super(attributes){ yield }
1137 else
1138 super(attributes)
1139 end
1140 end
1141
1142
1143 =begin
1144 === CHECKBOX
1145 checkbox("name")
1146 # = checkbox({ "NAME" => "name" })
1147
1148 checkbox("name", "value")
1149 # = checkbox({ "NAME" => "name", "VALUE" => "value" })
1150
1151 checkbox("name", "value", true)
1152 # = checkbox({ "NAME" => "name", "VALUE" => "value", "CHECKED" => true })
1153 =end
1154 def checkbox(name = "", value = nil, checked = nil)
1155 attributes = if name.kind_of?(String)
1156 { "TYPE" => "checkbox", "NAME" => name,
1157 "VALUE" => value, "CHECKED" => checked }
1158 else
1159 name["TYPE"] = "checkbox"
1160 name
1161 end
1162 input(attributes)
1163 end
1164
1165
1166 =begin
1167 === CHECKBOX_GROUP
1168 checkbox_group("name", "foo", "bar", "baz")
1169 # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
1170 # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
1171 # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
1172
1173 checkbox_group("name", ["foo"], ["bar", true], "baz")
1174 # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
1175 # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
1176 # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
1177
1178 checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
1179 # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
1180 # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
1181 # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
1182
1183 checkbox_group({ "NAME" => "name",
1184 "VALUES" => ["foo", "bar", "baz"] })
1185
1186 checkbox_group({ "NAME" => "name",
1187 "VALUES" => [["foo"], ["bar", true], "baz"] })
1188
1189 checkbox_group({ "NAME" => "name",
1190 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
1191 =end
1192 def checkbox_group(name = "", *values)
1193 if name.kind_of?(Hash)
1194 values = name["VALUES"]
1195 name = name["NAME"]
1196 end
1197 values.collect{|value|
1198 if value.kind_of?(String)
1199 checkbox(name, value) + value
1200 else
1201 if value[value.size - 1] == true
1202 checkbox(name, value[0], true) +
1203 value[value.size - 2]
1204 else
1205 checkbox(name, value[0]) +
1206 value[value.size - 1]
1207 end
1208 end
1209 }.to_s
1210 end
1211
1212
1213 =begin
1214 === FILE_FIELD
1215 file_field("name")
1216 # <INPUT TYPE="file" NAME="name" SIZE="20">
1217
1218 file_field("name", 40)
1219 # <INPUT TYPE="file" NAME="name" SIZE="40">
1220
1221 file_field("name", 40, 100)
1222 # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
1223
1224 file_field({ "NAME" => "name", "SIZE" => 40 })
1225 # <INPUT TYPE="file" NAME="name" SIZE="40">
1226 =end
1227 def file_field(name = "", size = 20, maxlength = nil)
1228 attributes = if name.kind_of?(String)
1229 { "TYPE" => "file", "NAME" => name,
1230 "SIZE" => size.to_s }
1231 else
1232 name["TYPE"] = "file"
1233 name
1234 end
1235 attributes["MAXLENGTH"] = maxlength.to_s if maxlength
1236 input(attributes)
1237 end
1238
1239
1240 =begin
1241 === FORM ELEMENT
1242 form{ "string" }
1243 # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
1244
1245 form("get"){ "string" }
1246 # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
1247
1248 form("get", "url"){ "string" }
1249 # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
1250
1251 form({"METHOD" => "post", "ENCTYPE" => "enctype"}){ "string" }
1252 # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
1253
1254 The hash keys are case sensitive. Ask the samples.
1255 =end
1256 def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
1257 attributes = if method.kind_of?(String)
1258 { "METHOD" => method, "ACTION" => action,
1259 "ENCTYPE" => enctype }
1260 else
1261 unless method.has_key?("METHOD")
1262 method["METHOD"] = "post"
1263 end
1264 unless method.has_key?("ENCTYPE")
1265 method["ENCTYPE"] = enctype
1266 end
1267 method
1268 end
1269 if block_given?
1270 body = yield
1271 else
1272 body = ""
1273 end
1274 if @output_hidden
1275 hidden = @output_hidden.collect{|k,v|
1276 "<INPUT TYPE=HIDDEN NAME=\"#{k}\" VALUE=\"#{v}\">"
1277 }.to_s
1278 if defined? fieldset
1279 body += fieldset{ hidden }
1280 else
1281 body += hidden
1282 end
1283 end
1284 super(attributes){body}
1285 end
1286
1287 =begin
1288 === HIDDEN FIELD
1289 hidden("name")
1290 # <INPUT TYPE="hidden" NAME="name">
1291
1292 hidden("name", "value")
1293 # <INPUT TYPE="hidden" NAME="name" VALUE="value">
1294
1295 hidden({ "NAME" => "name", "VALUE" => "reset", "ID" => "foo" })
1296 # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
1297 =end
1298 def hidden(name = "", value = nil)
1299 attributes = if name.kind_of?(String)
1300 { "TYPE" => "hidden", "NAME" => name, "VALUE" => value }
1301 else
1302 name["TYPE"] = "hidden"
1303 name
1304 end
1305 input(attributes)
1306 end
1307
1308
1309 =begin
1310 === HTML ELEMENT
1311
1312 html{ "string" }
1313 # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
1314
1315 html({ "LANG" => "ja" }){ "string" }
1316 # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
1317
1318 html({ "DOCTYPE" => false }){ "string" }
1319 # <HTML>string</HTML>
1320
1321 html({ "DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">' }){ "string" }
1322 # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
1323
1324 html({ "PRETTY" => " " }){ "<BODY></BODY>" }
1325 # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
1326 # <HTML>
1327 # <BODY>
1328 # </BODY>
1329 # </HTML>
1330
1331 html({ "PRETTY" => "\t" }){ "<BODY></BODY>" }
1332 # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
1333 # <HTML>
1334 # <BODY>
1335 # </BODY>
1336 # </HTML>
1337
1338 html("PRETTY"){ "<BODY></BODY>" }
1339 # = html({ "PRETTY" => " " }){ "<BODY></BODY>" }
1340
1341 html(if $VERBOSE then "PRETTY" end){ "HTML string" }
1342
1343 =end
1344 def html(attributes = {})
1345 if nil == attributes
1346 attributes = {}
1347 elsif "PRETTY" == attributes
1348 attributes = { "PRETTY" => true }
1349 end
1350 pretty = attributes.delete("PRETTY")
1351 pretty = " " if true == pretty
1352 buf = ""
1353
1354 if attributes.has_key?("DOCTYPE")
1355 if attributes["DOCTYPE"]
1356 buf += attributes.delete("DOCTYPE")
1357 else
1358 attributes.delete("DOCTYPE")
1359 end
1360 else
1361 buf += doctype
1362 end
1363
1364 if block_given?
1365 buf += super(attributes){ yield }
1366 else
1367 buf += super(attributes)
1368 end
1369
1370 if pretty
1371 CGI::pretty(buf, pretty)
1372 else
1373 buf
1374 end
1375
1376 end
1377
1378
1379 =begin
1380 === IMAGE_BUTTON
1381 image_button("url")
1382 # <INPUT TYPE="image" SRC="url">
1383
1384 image_button("url", "name", "string")
1385 # <INPUT TYPE="image" SRC="url" NAME="name" ALT="string">
1386
1387 image_button({ "SRC" => "url", "ATL" => "strng" })
1388 # <INPUT TYPE="image" SRC="url" ALT="string">
1389 =end
1390 def image_button(src = "", name = nil, alt = nil)
1391 attributes = if src.kind_of?(String)
1392 { "TYPE" => "image", "SRC" => src, "NAME" => name,
1393 "ALT" => alt }
1394 else
1395 src["TYPE"] = "image"
1396 src["SRC"] ||= ""
1397 src
1398 end
1399 input(attributes)
1400 end
1401
1402
1403 =begin
1404 === IMG ELEMENT
1405 img("src", "alt", 100, 50)
1406 # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
1407
1408 img({ "SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50 })
1409 # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
1410 =end
1411 def img(src = "", alt = "", width = nil, height = nil)
1412 attributes = if src.kind_of?(String)
1413 { "SRC" => src, "ALT" => alt }
1414 else
1415 src
1416 end
1417 attributes["WIDTH"] = width.to_s if width
1418 attributes["HEIGHT"] = height.to_s if height
1419 super(attributes)
1420 end
1421
1422
1423 =begin
1424 === MULTIPART FORM
1425 multipart_form{ "string" }
1426 # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
1427
1428 multipart_form("url"){ "string" }
1429 # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
1430 =end
1431 def multipart_form(action = nil, enctype = "multipart/form-data")
1432 attributes = if action == nil
1433 { "METHOD" => "post", "ENCTYPE" => enctype }
1434 elsif action.kind_of?(String)
1435 { "METHOD" => "post", "ACTION" => action,
1436 "ENCTYPE" => enctype }
1437 else
1438 unless action.has_key?("METHOD")
1439 action["METHOD"] = "post"
1440 end
1441 unless action.has_key?("ENCTYPE")
1442 action["ENCTYPE"] = enctype
1443 end
1444 action
1445 end
1446 if block_given?
1447 form(attributes){ yield }
1448 else
1449 form(attributes)
1450 end
1451 end
1452
1453
1454 =begin
1455 === PASSWORD_FIELD
1456 password_field("name")
1457 # <INPUT TYPE="password" NAME="name" SIZE="40">
1458
1459 password_field("name", "value")
1460 # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
1461
1462 password_field("password", "value", 80, 200)
1463 # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
1464
1465 password_field({ "NAME" => "name", "VALUE" => "value" })
1466 # <INPUT TYPE="password" NAME="name" VALUE="value">
1467 =end
1468 def password_field(name = "", value = nil, size = 40, maxlength = nil)
1469 attributes = if name.kind_of?(String)
1470 { "TYPE" => "password", "NAME" => name,
1471 "VALUE" => value, "SIZE" => size.to_s }
1472 else
1473 name["TYPE"] = "password"
1474 name
1475 end
1476 attributes["MAXLENGTH"] = maxlength.to_s if maxlength
1477 input(attributes)
1478 end
1479
1480
1481 =begin
1482 === POPUP_MENU
1483 popup_menu("name", "foo", "bar", "baz")
1484 # <SELECT NAME="name">
1485 # <OPTION VALUE="foo">foo</OPTION>
1486 # <OPTION VALUE="bar">bar</OPTION>
1487 # <OPTION VALUE="baz">baz</OPTION>
1488 # </SELECT>
1489
1490 popup_menu("name", ["foo"], ["bar", true], "baz")
1491 # <SELECT NAME="name">
1492 # <OPTION VALUE="foo">foo</OPTION>
1493 # <OPTION VALUE="bar" SELECTED>bar</OPTION>
1494 # <OPTION VALUE="baz">baz</OPTION>
1495 # </SELECT>
1496
1497 popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
1498 # <SELECT NAME="name">
1499 # <OPTION VALUE="1">Foo</OPTION>
1500 # <OPTION SELECTED VALUE="2">Bar</OPTION>
1501 # <OPTION VALUE="Baz">Baz</OPTION>
1502 # </SELECT>
1503
1504 popup_menu({"NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
1505 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
1506 # <SELECT NAME="name" MULTIPLE SIZE="2">
1507 # <OPTION VALUE="1">Foo</OPTION>
1508 # <OPTION SELECTED VALUE="2">Bar</OPTION>
1509 # <OPTION VALUE="Baz">Baz</OPTION>
1510 # </SELECT>
1511 =end
1512 def popup_menu(name = "", *values)
1513
1514 if name.kind_of?(Hash)
1515 values = name["VALUES"]
1516 size = name["SIZE"].to_s if name["SIZE"]
1517 multiple = name["MULTIPLE"]
1518 name = name["NAME"]
1519 else
1520 size = nil
1521 multiple = nil
1522 end
1523
1524 select({ "NAME" => name, "SIZE" => size,
1525 "MULTIPLE" => multiple }){
1526 values.collect{|value|
1527 if value.kind_of?(String)
1528 option({ "VALUE" => value }){ value }
1529 else
1530 if value[value.size - 1] == true
1531 option({ "VALUE" => value[0], "SELECTED" => true }){
1532 value[value.size - 2]
1533 }
1534 else
1535 option({ "VALUE" => value[0] }){
1536 value[value.size - 1]
1537 }
1538 end
1539 end
1540 }.to_s
1541 }
1542
1543 end
1544
1545
1546 =begin
1547 === RADIO_BUTTON
1548 radio_button("name", "value")
1549 # <INPUT TYPE="radio" NAME="name" VALUE="value">
1550
1551 radio_button("name", "value", true)
1552 # <INPUT TYPE="radio" NAME="name" VALUE="value" CHECKED>
1553
1554 radio_button({ "NAME" => "name", "VALUE" => "value", "ID" => "foo" })
1555 # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
1556 =end
1557 def radio_button(name = "", value = nil, checked = nil)
1558 attributes = if name.kind_of?(String)
1559 { "TYPE" => "radio", "NAME" => name,
1560 "VALUE" => value, "CHECKED" => checked }
1561 else
1562 name["TYPE"] = "radio"
1563 name
1564 end
1565 input(attributes)
1566 end
1567
1568
1569 =begin
1570 === RADIO_GROUP
1571 radio_group("name", "foo", "bar", "baz")
1572 # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
1573 # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
1574 # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
1575
1576 radio_group("name", ["foo"], ["bar", true], "baz")
1577 # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
1578 # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="bar">bar
1579 # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
1580
1581 radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
1582 # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
1583 # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="2">Bar
1584 # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
1585
1586 radio_group({ "NAME" => "name",
1587 "VALUES" => ["foo", "bar", "baz"] })
1588
1589 radio_group({ "NAME" => "name",
1590 "VALUES" => [["foo"], ["bar", true], "baz"] })
1591
1592 radio_group({ "NAME" => "name",
1593 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
1594 =end
1595 def radio_group(name = "", *values)
1596 if name.kind_of?(Hash)
1597 values = name["VALUES"]
1598 name = name["NAME"]
1599 end
1600 values.collect{|value|
1601 if value.kind_of?(String)
1602 radio_button(name, value) + value
1603 else
1604 if value[value.size - 1] == true
1605 radio_button(name, value[0], true) +
1606 value[value.size - 2]
1607 else
1608 radio_button(name, value[0]) +
1609 value[value.size - 1]
1610 end
1611 end
1612 }.to_s
1613 end
1614
1615
1616 =begin
1617 === RESET BUTTON
1618 reset
1619 # <INPUT TYPE="reset">
1620
1621 reset("reset")
1622 # <INPUT TYPE="reset" VALUE="reset">
1623
1624 reset({ "VALUE" => "reset", "ID" => "foo" })
1625 # <INPUT TYPE="reset" VALUE="reset" ID="foo">
1626 =end
1627 def reset(value = nil, name = nil)
1628 attributes = if (not value) or value.kind_of?(String)
1629 { "TYPE" => "reset", "VALUE" => value, "NAME" => name }
1630 else
1631 value["TYPE"] = "reset"
1632 value
1633 end
1634 input(attributes)
1635 end
1636
1637
1638 =begin
1639 === SCROLLING_LIST
1640 scrolling_list({"NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
1641 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
1642 # <SELECT NAME="name" MULTIPLE SIZE="2">
1643 # <OPTION VALUE="1">Foo</OPTION>
1644 # <OPTION SELECTED VALUE="2">Bar</OPTION>
1645 # <OPTION VALUE="Baz">Baz</OPTION>
1646 # </SELECT>
1647 =end
1648 alias scrolling_list popup_menu
1649
1650
1651 =begin
1652 === SUBMIT BUTTON
1653 submit
1654 # <INPUT TYPE="submit">
1655
1656 submit("ok")
1657 # <INPUT TYPE="submit" VALUE="ok">
1658
1659 submit("ok", "button1")
1660 # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
1661
1662 submit({ "VALUE" => "ok", "NAME" => "button1", "ID" => "foo" })
1663 # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
1664 =end
1665 def submit(value = nil, name = nil)
1666 attributes = if (not value) or value.kind_of?(String)
1667 { "TYPE" => "submit", "VALUE" => value, "NAME" => name }
1668 else
1669 value["TYPE"] = "submit"
1670 value
1671 end
1672 input(attributes)
1673 end
1674
1675
1676 =begin
1677 === TEXT_FIELD
1678 text_field("name")
1679 # <INPUT TYPE="text" NAME="name" SIZE="40">
1680
1681 text_field("name", "value")
1682 # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
1683
1684 text_field("name", "value", 80)
1685 # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80">
1686
1687 text_field("name", "value", 80, 200)
1688 # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
1689
1690 text_field({ "NAME" => "name", "VALUE" => "value" })
1691 # <INPUT TYPE="text" NAME="name" VALUE="value">
1692 =end
1693 def text_field(name = "", value = nil, size = 40, maxlength = nil)
1694 attributes = if name.kind_of?(String)
1695 { "TYPE" => "text", "NAME" => name, "VALUE" => value,
1696 "SIZE" => size.to_s }
1697 else
1698 name["TYPE"] = "text"
1699 name
1700 end
1701 attributes["MAXLENGTH"] = maxlength.to_s if maxlength
1702 input(attributes)
1703 end
1704
1705
1706 =begin
1707 === TEXTAREA ELEMENT
1708 textarea("name")
1709 # = textarea({ "NAME" => "name", "COLS" => 70, "ROWS" => 10 })
1710
1711 textarea("name", 40, 5)
1712 # = textarea({ "NAME" => "name", "COLS" => 40, "ROWS" => 5 })
1713 =end
1714 def textarea(name = "", cols = 70, rows = 10)
1715 attributes = if name.kind_of?(String)
1716 { "NAME" => name, "COLS" => cols.to_s,
1717 "ROWS" => rows.to_s }
1718 else
1719 name
1720 end
1721 if block_given?
1722 super(attributes){ yield }
1723 else
1724 super(attributes)
1725 end
1726 end
1727
1728 end # HtmlExtension
1729
1730
1731 module Html3
1732
1733 def doctype
1734 %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">|
1735 end
1736
1737 def element_init
1738 extend TagMaker
1739 methods = ""
1740 # - -
1741 for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
1742 DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
1743 APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
1744 STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
1745 CAPTION ]
1746 methods += <<-BEGIN + nn_element_def(element) + <<-END
1747 def #{element.downcase}(attributes = {})
1748 BEGIN
1749 end
1750 END
1751 end
1752
1753 # - O EMPTY
1754 for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
1755 ISINDEX META ]
1756 methods += <<-BEGIN + nOE_element_def(element) + <<-END
1757 def #{element.downcase}(attributes = {})
1758 BEGIN
1759 end
1760 END
1761 end
1762
1763 # O O or - O
1764 for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr
1765 th td ]
1766 methods += <<-BEGIN + nO_element_def(element) + <<-END
1767 def #{element.downcase}(attributes = {})
1768 BEGIN
1769 end
1770 END
1771 end
1772 eval(methods)
1773 end
1774
1775 end # Html3
1776
1777
1778 module Html4
1779
1780 def doctype
1781 %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|
1782 end
1783
1784 def element_init
1785 extend TagMaker
1786 methods = ""
1787 # - -
1788 for element in %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD
1789 VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
1790 H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP
1791 FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
1792 TEXTAREA FORM A BLOCKQUOTE CAPTION ]
1793 methods += <<-BEGIN + nn_element_def(element) + <<-END
1794 def #{element.downcase}(attributes = {})
1795 BEGIN
1796 end
1797 END
1798 end
1799
1800 # - O EMPTY
1801 for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ]
1802 methods += <<-BEGIN + nOE_element_def(element) + <<-END
1803 def #{element.downcase}(attributes = {})
1804 BEGIN
1805 end
1806 END
1807 end
1808
1809 # O O or - O
1810 for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
1811 COLGROUP TR TH TD HEAD]
1812 methods += <<-BEGIN + nO_element_def(element) + <<-END
1813 def #{element.downcase}(attributes = {})
1814 BEGIN
1815 end
1816 END
1817 end
1818 eval(methods)
1819 end
1820
1821 end # Html4
1822
1823
1824 module Html4Tr
1825
1826 def doctype
1827 %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|
1828 end
1829
1830 def element_init
1831 extend TagMaker
1832 methods = ""
1833 # - -
1834 for element in %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN
1835 CODE SAMP KBD VAR CITE ABBR ACRONYM FONT SUB SUP SPAN BDO
1836 ADDRESS DIV CENTER MAP OBJECT APPLET H1 H2 H3 H4 H5 H6 PRE Q
1837 INS DEL DL OL UL DIR MENU LABEL SELECT OPTGROUP FIELDSET
1838 LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE SCRIPT
1839 NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ]
1840 methods += <<-BEGIN + nn_element_def(element) + <<-END
1841 def #{element.downcase}(attributes = {})
1842 BEGIN
1843 end
1844 END
1845 end
1846
1847 # - O EMPTY
1848 for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
1849 COL ISINDEX META ]
1850 methods += <<-BEGIN + nOE_element_def(element) + <<-END
1851 def #{element.downcase}(attributes = {})
1852 BEGIN
1853 end
1854 END
1855 end
1856
1857 # O O or - O
1858 for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
1859 COLGROUP TR TH TD HEAD ]
1860 methods += <<-BEGIN + nO_element_def(element) + <<-END
1861 def #{element.downcase}(attributes = {})
1862 BEGIN
1863 end
1864 END
1865 end
1866 eval(methods)
1867 end
1868
1869 end # Html4Tr
1870
1871
1872 module Html4Fr
1873
1874 def doctype
1875 %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|
1876 end
1877
1878 def element_init
1879 methods = ""
1880 # - -
1881 for element in %w[ FRAMESET ]
1882 methods += <<-BEGIN + nn_element_def(element) + <<-END
1883 def #{element.downcase}(attributes = {})
1884 BEGIN
1885 end
1886 END
1887 end
1888
1889 # - O EMPTY
1890 for element in %w[ FRAME ]
1891 methods += <<-BEGIN + nOE_element_def(element) + <<-END
1892 def #{element.downcase}(attributes = {})
1893 BEGIN
1894 end
1895 END
1896 end
1897 eval(methods)
1898 end
1899
1900 end # Html4Fr
1901
1902
1903 def initialize(type = "query")
1904 if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
1905 Apache.request.setup_cgi_env
1906 end
1907
1908 extend QueryExtension
1909 if "POST" != env_table['REQUEST_METHOD']
1910 initialize_query() # set @params, @cookies
1911 else
1912 if defined?(CGI_PARAMS)
1913 @params = CGI_PARAMS.nil? ? nil : CGI_PARAMS.dup
1914 @cookies = CGI_COOKIES.nil? ? nil : CGI_COOKIES.dup
1915 else
1916 initialize_query() # set @params, @cookies
1917 eval "CGI_PARAMS = @params.nil? ? nil : @params.dup"
1918 eval "CGI_COOKIES = @cookies.nil? ? nil : @cookies.dup"
1919 if defined?(MOD_RUBY) and (RUBY_VERSION < "1.4.3")
1920 raise "Please, use ruby1.4.3 or later."
1921 else
1922 at_exit() do
1923 if defined?(CGI_PARAMS)
1924 self.class.class_eval("remove_const(:CGI_PARAMS)")
1925 self.class.class_eval("remove_const(:CGI_COOKIES)")
1926 end
1927 end
1928 end
1929 end
1930 end
1931 @output_cookies = nil
1932 @output_hidden = nil
1933
1934 case type
1935 when "html3"
1936 extend Html3
1937 element_init()
1938 extend HtmlExtension
1939 when "html4"
1940 extend Html4
1941 element_init()
1942 extend HtmlExtension
1943 when "html4Tr"
1944 extend Html4Tr
1945 element_init()
1946 extend HtmlExtension
1947 when "html4Fr"
1948 extend Html4Tr
1949 element_init()
1950 extend Html4Fr
1951 element_init()
1952 extend HtmlExtension
1953 end
1954
1955 end
1956 end
1957
1958
1959 =begin
1960
1961 == HISTORY
1962
1963 delete. see cvs log.
1964
1965
1966 =end
1967
1968 # vi:set tw=0: