DEFINITIONS
This source file includes following functions.
1 #
2 # $Id: generic.rb,v 1.4 2002/06/12 09:31:41 akira Exp $
3 #
4 # Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
5 # You can redistribute it and/or modify it under the same term as Ruby.
6 #
7
8 require 'uri/common'
9
10 module URI
11
12 =begin
13
14 == URI::Generic
15
16 === Super Class
17
18 Object
19
20 =end
21
22 class Generic
23 include REGEXP
24
25 =begin
26
27 === Class Methods
28
29 --- URI::Generic::default_port
30
31 =end
32 DEFAULT_PORT = nil
33
34 def self.default_port
35 self::DEFAULT_PORT
36 end
37
38 def default_port
39 self.type.default_port
40 end
41
42 =begin
43 --- URI::Generic::component
44 =end
45 COMPONENT = [
46 :scheme,
47 :userinfo, :host, :port, :registry,
48 :path, :opaque,
49 :query,
50 :fragment
51 ].freeze
52
53 def self.component
54 self::COMPONENT
55 end
56
57 =begin
58 --- URI::Generic::use_registry
59 =end
60 USE_REGISTRY = false
61
62 def self.use_registry
63 self::USE_REGISTRY
64 end
65
66 =begin
67
68 --- URI::Generic::build2
69 At first, try to create a new URI::Generic object using
70 URI::Generic::build. But, if you get a exception
71 URI::InvalidComponentError, then re-try to create an object with
72 escaped components.
73
74 --- URI::Generic::build
75 Create a new URI::Generic object from components of URI::Generic
76 with check. It is scheme, userinfo, host, port, registry, path,
77 opaque, query and fragment. It provided by an Array of a Hash.
78
79 --- URI::Generic::new
80 Create new URI::Generic object from ``generic'' components with no
81 check.
82
83 =end
84 def self.build2(args)
85 begin
86 return self.build(args)
87 rescue InvalidComponentError
88 if args.kind_of?(Array)
89 return self.build(args.collect{|x|
90 if x
91 URI.escape(x)
92 else
93 x
94 end
95 })
96 elsif args.kind_of?(Hash)
97 tmp = {}
98 args.each do |key, value|
99 tmp[key] = if value
100 URI.escape(value)
101 else
102 value
103 end
104 end
105 return self.build(tmp)
106 end
107 end
108 end
109
110 def self.build(args)
111 if args.kind_of?(Array) &&
112 args.size == ::URI::Generic::COMPONENT.size
113 tmp = args
114 elsif args.kind_of?(Hash)
115 tmp = ::URI::Generic::COMPONENT.collect do |c|
116 if args.include?(c)
117 args[c]
118 else
119 nil
120 end
121 end
122 else
123 raise ArgumentError,
124 "expected Array of or Hash of components of #{self.type} (#{self.type.component.join(', ')})"
125 end
126
127 tmp << true
128 return self.new(*tmp)
129 end
130
131 def initialize(scheme,
132 userinfo, host, port, registry,
133 path, opaque,
134 query,
135 fragment,
136 arg_check = false)
137 @scheme = nil
138 @user = nil
139 @password = nil
140 @host = nil
141 @port = nil
142 @path = nil
143 @query = nil
144 @opaque = nil
145 @registry = nil
146 @fragment = nil
147
148 if arg_check
149 self.scheme = scheme
150 self.userinfo = userinfo
151 self.host = host
152 self.port = port
153 self.path = path
154 self.query = query
155 self.opaque = opaque
156 self.registry = registry
157 self.fragment = fragment
158 else
159 self.set_scheme(scheme)
160 self.set_userinfo(userinfo)
161 self.set_host(host)
162 self.set_port(port)
163 self.set_path(path)
164 self.set_query(query)
165 self.set_opaque(opaque)
166 self.set_registry(registry)
167 self.set_fragment(fragment)
168 end
169 if @registry && !self.class.use_registry
170 raise InvalidURIError, "the scheme #{@scheme} does not accept registry part: #{@registry} (or bad hostname?)"
171 end
172
173 @scheme.freeze if @scheme
174 self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
175 self.set_port(self.default_port) if self.default_port && !@port
176 end
177 attr_reader :scheme
178 attr_reader :host
179 attr_reader :port
180 attr_reader :registry
181 attr_reader :path
182 attr_reader :query
183 attr_reader :opaque
184 attr_reader :fragment
185
186 =begin
187
188 === Instance Methods
189
190 =end
191
192 =begin
193
194 --- URI::Generic#component
195
196 =end
197 def component
198 self.type.component
199 end
200
201 # set_XXX method sets value to @XXX instance variable with no check,
202 # so be careful if you use these methods. or, you use these method
203 # with check_XXX method, or you use XXX= methods.
204
205 =begin
206
207 --- URI::Generic#scheme
208
209 --- URI::Generic#scheme=(v)
210
211 =end
212 #
213 # methods for scheme
214 #
215 def check_scheme(v)
216 if v && SCHEME !~ v
217 raise InvalidComponentError,
218 "bad component(expected scheme component): #{v}"
219 end
220
221 return true
222 end
223 private :check_scheme
224
225 def set_scheme(v)
226 @scheme = v
227 end
228 protected :set_scheme
229
230 def scheme=(v)
231 check_scheme(v)
232 set_scheme(v)
233 end
234
235 =begin
236
237 --- URI::Generic#userinfo
238
239 --- URI::Generic#userinfo=(v)
240
241 --- URI::Generic#user
242
243 --- URI::Generic#user=(v)
244
245 --- URI::Generic#password
246
247 --- URI::Generic#password=(v)
248
249 =end
250 #
251 # methods for userinfo
252 #
253 def check_userinfo(user, password = nil)
254 if (user || password) &&
255 (@registry || @opaque)
256 raise InvalidURIError,
257 "can not set userinfo with registry or opaque"
258 end
259
260 if !password
261 user, password = split_userinfo(user)
262 end
263 check_user(user)
264 check_password(password)
265
266 return true
267 end
268 private :check_userinfo
269
270 def check_user(v)
271 return v unless v
272
273 if USERINFO !~ v
274 raise InvalidComponentError,
275 "bad component(expected userinfo component or user component): #{v}"
276 end
277
278 return true
279 end
280 private :check_user
281
282 def check_password(v)
283 return v unless v
284
285 if !@password
286 raise InvalidURIError,
287 "password component depends user component"
288 end
289
290 if USERINFO !~ v
291 raise InvalidComponentError,
292 "bad component(expected user component): #{v}"
293 end
294
295 return true
296 end
297 private :check_password
298
299 def userinfo=(userinfo)
300 if userinfo.nil?
301 return nil
302 end
303 check_userinfo(*userinfo)
304 set_userinfo(*userinfo)
305 end
306
307 def user=(user)
308 check_user(user)
309 set_user(user)
310 end
311
312 def password=(password)
313 check_password(password)
314 set_password(password)
315 end
316
317 def set_userinfo(user, password = nil)
318 unless password
319 user, password = split_userinfo(user)
320 end
321 @user = user
322 @password = password if password
323
324 [@user, @password]
325 end
326 protected :set_userinfo
327
328 def set_user(v)
329 set_userinfo(v, @password)
330 v
331 end
332 protected :set_user
333
334 def set_password(v)
335 set_userinfo(@user, v)
336 v
337 end
338 protected :set_password
339
340 def split_userinfo(ui)
341 return nil, nil unless ui
342 tmp = ui.index(':')
343 if tmp
344 user = ui[0..tmp - 1]
345 password = ui[tmp + 1..-1]
346 else
347 user = ui
348 password = nil
349 end
350
351 return user, password
352 end
353 private :split_userinfo
354
355 def escape_userpass(v)
356 v = URI.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
357 end
358 private :escape_userpass
359
360 def userinfo
361 if !@password
362 @user
363 else
364 @user + ':' + @password
365 end
366 end
367
368 def user
369 @user
370 end
371
372 def password
373 @password
374 end
375
376 =begin
377
378 --- URI::Generic#host
379
380 --- URI::Generic#host=(v)
381
382 =end
383 #
384 # methods for host
385 #
386
387 def check_host(v)
388 return v unless v
389
390 if @registry || @opaque
391 raise InvalidURIError,
392 "can not set host with registry or opaque"
393 elsif HOST !~ v
394 raise InvalidComponentError,
395 "bad component(expected host component): #{v}"
396 end
397
398 return true
399 end
400 private :check_host
401
402 def set_host(v)
403 @host = v
404 end
405 protected :set_host
406
407 def host=(v)
408 check_host(v)
409 set_host(v)
410 end
411
412 =begin
413
414 --- URI::Generic#port
415
416 --- URI::Generic#port=(v)
417
418 =end
419 #
420 # methods for port
421 #
422
423 def check_port(v)
424 return v unless v
425
426 if @registry || @opaque
427 raise InvalidURIError,
428 "can not set port with registry or opaque"
429 elsif !v.kind_of?(Fixnum) && PORT !~ v
430 raise InvalidComponentError,
431 "bad component(expected port component): #{v}"
432 end
433
434 return true
435 end
436 private :check_port
437
438 def set_port(v)
439 v = v.to_i if v && !v.kind_of?(Fixnum)
440 @port = v
441 end
442 protected :set_port
443
444 def port=(v)
445 check_port(v)
446 set_port(v)
447 end
448
449 =begin
450
451 --- URI::Generic#registry
452
453 --- URI::Generic#registry=(v)
454
455 =end
456 #
457 # methods for registry
458 #
459
460 def check_registry(v)
461 return v unless v
462
463 # raise if both server and registry are not nil, because:
464 # authority = server | reg_name
465 # server = [ [ userinfo "@" ] hostport ]
466 if @host || @port || @user # userinfo = @user + ':' + @password
467 raise InvalidURIError,
468 "can not set registry with host, port, or userinfo"
469 elsif v && REGISTRY !~ v
470 raise InvalidComponentError,
471 "bad component(expected registry component): #{v}"
472 end
473
474 return true
475 end
476 private :check_registry
477
478 def set_registry(v)
479 @registry = v
480 end
481 protected :set_registry
482
483 def registry=(v)
484 check_registry(v)
485 set_registry(v)
486 end
487
488 =begin
489
490 --- URI::Generic#path
491
492 --- URI::Generic#path=(v)
493
494 =end
495 #
496 # methods for path
497 #
498
499 def check_path(v)
500 # raise if both hier and opaque are not nil, because:
501 # absoluteURI = scheme ":" ( hier_part | opaque_part )
502 # hier_part = ( net_path | abs_path ) [ "?" query ]
503 if v && @opaque
504 raise InvalidURIError,
505 "path conflicts with opaque"
506 end
507
508 if @scheme
509 if v && v != '' && ABS_PATH !~ v
510 raise InvalidComponentError,
511 "bad component(expected absolute path component): #{v}"
512 end
513 else
514 if v && v != '' && ABS_PATH !~ v && REL_PATH !~ v
515 raise InvalidComponentError,
516 "bad component(expected relative path component): #{v}"
517 end
518 end
519
520 return true
521 end
522 private :check_path
523
524 def set_path(v)
525 @path = v
526 end
527 protected :set_path
528
529 def path=(v)
530 check_path(v)
531 set_path(v)
532 end
533
534 =begin
535
536 --- URI::Generic#query
537
538 --- URI::Generic#query=(v)
539
540 =end
541 #
542 # methods for query
543 #
544
545 def check_query(v)
546 return v unless v
547
548 # raise if both hier and opaque are not nil, because:
549 # absoluteURI = scheme ":" ( hier_part | opaque_part )
550 # hier_part = ( net_path | abs_path ) [ "?" query ]
551 if @opaque
552 raise InvalidURIError,
553 "query conflicts with opaque"
554 end
555
556 if v && v != '' && QUERY !~ v
557 raise InvalidComponentError,
558 "bad component(expected query component): #{v}"
559 end
560
561 return true
562 end
563 private :check_query
564
565 def set_query(v)
566 @query = v
567 end
568 protected :set_query
569
570 def query=(v)
571 check_query(v)
572 set_query(v)
573 end
574
575 =begin
576
577 --- URI::Generic#opaque
578
579 --- URI::Generic#opaque=(v)
580
581 =end
582 #
583 # methods for opaque
584 #
585
586 def check_opaque(v)
587 return v unless v
588
589 # raise if both hier and opaque are not nil, because:
590 # absoluteURI = scheme ":" ( hier_part | opaque_part )
591 # hier_part = ( net_path | abs_path ) [ "?" query ]
592 if @host || @port || @usr || @path # userinfo = @user + ':' + @password
593 raise InvalidURIError,
594 "can not set opaque with host, port, userinfo or path"
595 elsif v && OPAQUE !~ v
596 raise InvalidComponentError,
597 "bad component(expected opaque component): #{v}"
598 end
599
600 return true
601 end
602 private :check_opaque
603
604 def set_opaque(v)
605 @opaque = v
606 end
607 protected :set_opaque
608
609 def opaque=(v)
610 check_opaque(v)
611 set_opaque(v)
612 end
613
614 =begin
615
616 --- URI::Generic#fragment
617
618 --- URI::Generic#fragment=(v)
619
620 =end
621 #
622 # methods for fragment
623 #
624
625 def check_fragment(v)
626 return v unless v
627
628 if v && v != '' && FRAGMENT !~ v
629 raise InvalidComponentError,
630 "bad component(expected fragment component): #{v}"
631 end
632
633 return true
634 end
635 private :check_fragment
636
637 def set_fragment(v)
638 @fragment = v
639 end
640 protected :set_fragment
641
642 def fragment=(v)
643 check_fragment(v)
644 set_fragment(v)
645 end
646
647 =begin
648
649 --- URI::Generic#hierarchical?
650
651 =end
652 def hierarchical?
653 if @path
654 true
655 else
656 false
657 end
658 end
659
660 =begin
661
662 --- URI::Generic#absolute?
663
664 =end
665 def absolute?
666 if @scheme
667 true
668 else
669 false
670 end
671 end
672 alias absolute absolute?
673
674 =begin
675
676 --- URI::Generic#relative?
677
678 =end
679 def relative?
680 !absolute?
681 end
682
683 =begin
684
685 --- URI::Generic#merge(rel)
686 --- URI::Generic#+(rel)
687
688 =end
689 def split_path(path)
690 path.split(%r{/+}, -1)
691 end
692 private :split_path
693
694 def merge_path(base, rel)
695 # RFC2396, Section 5.2, 5)
696 if rel[0] == ?/ #/
697 # RFC2396, Section 5.2, 5)
698 return rel
699
700 else
701 # RFC2396, Section 5.2, 6)
702 base_path = split_path(base)
703 rel_path = split_path(rel)
704
705 if base_path.empty?
706 base_path = [''] # XXX
707 end
708
709 # RFC2396, Section 5.2, 6), a)
710 base_path.pop unless base_path.size == 1
711
712 # RFC2396, Section 5.2, 6), c)
713 # RFC2396, Section 5.2, 6), d)
714 rel_path.push('') if rel_path.last == '.'
715 rel_path.delete('.')
716
717 # RFC2396, Section 5.2, 6), e)
718 tmp = []
719 rel_path.each do |x|
720 if x == '..' &&
721 !(tmp.empty? || tmp.last == '..')
722 tmp.pop
723 else
724 tmp << x
725 end
726 end
727
728 add_trailer_slash = true
729 while x = tmp.shift
730 if x == '..' && base_path.size > 1
731 # RFC2396, Section 4
732 # a .. or . in an absolute path has no special meaning
733 base_path.pop
734 else
735 # if x == '..'
736 # valid absolute (but abnormal) path "/../..."
737 # else
738 # valid absolute path
739 # end
740 base_path << x
741 tmp.each {|t| base_path << t}
742 add_trailer_slash = false
743 break
744 end
745 end
746 base_path.push('') if add_trailer_slash
747
748 return base_path.join('/')
749 end
750 end
751 private :merge_path
752
753 # abs(self) + rel(oth) => abs(new)
754 def merge(oth)
755 base, rel = merge0(oth)
756 if base == rel
757 return base
758 end
759
760 authority = rel.userinfo || rel.host || rel.port
761
762 # RFC2396, Section 5.2, 2)
763 if rel.path.empty? && !authority && !rel.query
764 base.set_fragment(rel.fragment) if rel.fragment
765 return base
766 end
767
768 base.set_query(nil)
769 base.set_fragment(nil)
770
771 # RFC2396, Section 5.2, 4)
772 if !authority
773 base.set_path(merge_path(base.path, rel.path))
774 else
775 # RFC2396, Section 5.2, 4)
776 base.set_path(rel.path)
777 end
778
779 # RFC2396, Section 5.2, 7)
780 base.set_userinfo(rel.userinfo) if rel.userinfo
781 base.set_host(rel.host) if rel.host
782 base.set_port(rel.port) if rel.port
783 base.set_query(rel.query) if rel.query
784 base.set_fragment(rel.fragment) if rel.fragment
785
786 return base
787 end # merge
788 alias + merge
789
790 # return base and rel.
791 # you can modify `base', but can not `rel'.
792 def merge0(oth)
793 case oth
794 when Generic
795 when String
796 oth = URI.parse(oth)
797 else
798 raise ArgumentError,
799 "bad argument(expected URI object or URI string)"
800 end
801
802 if self.relative? && oth.relative?
803 raise BadURIError,
804 "both URI are relative"
805 end
806
807 if self.absolute? && oth.absolute?
808 #raise BadURIError,
809 # "both URI are absolute"
810 # hmm... should return oth for usability?
811 return oth, oth
812 end
813
814 if !self.hierarchical?
815 raise BadURIError,
816 "not hierarchical URI: #{self}"
817 elsif !oth.hierarchical?
818 raise BadURIError,
819 "not hierarchical URI: #{oth}"
820 end
821
822 if self.absolute?
823 return self.dup, oth
824 else
825 return oth, oth
826 end
827 end
828 private :merge0
829
830 =begin
831
832 --- URI::Generic#route_from(src)
833 --- URI::Generic#-(src)
834
835 =end
836 def route_from_path(src, dst)
837 # RFC2396, Section 4.2
838 return '' if src == dst
839
840 src_path = split_path(src)
841 dst_path = split_path(dst)
842
843 # hmm... dst has abnormal absolute path,
844 # like "/./", "/../", "/x/../", ...
845 if dst_path.include?('..') ||
846 dst_path.include?('.')
847 return dst.dup
848 end
849
850 src_path.pop
851
852 # discard same parts
853 while dst_path.first == src_path.first
854 break if dst_path.empty?
855
856 src_path.shift
857 dst_path.shift
858 end
859
860 tmp = dst_path.join('/')
861
862 # calculate
863 if src_path.empty?
864 if tmp.empty?
865 return './'
866 elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
867 return './' + tmp
868 else
869 return tmp
870 end
871 end
872
873 return '../' * src_path.size + tmp
874 end
875 private :route_from_path
876
877 def route_from0(oth)
878 case oth
879 when Generic
880 when String
881 oth = URI.parse(oth)
882 else
883 raise ArgumentError,
884 "bad argument(expected URI object or URI string)"
885 end
886
887 if self.relative?
888 raise BadURIError,
889 "relative URI: #{self}"
890 end
891 if oth.relative?
892 raise BadURIError,
893 "relative URI: #{oth}"
894 end
895
896 if !self.hierarchical? || !oth.hierarchical?
897 return self, self.dup
898 end
899
900 if self.scheme != oth.scheme
901 return oth, oth.dup
902 end
903 rel = URI::Generic.new(nil, # it is relative URI
904 self.userinfo, self.host, self.port,
905 self.registry, self.path, self.opaque,
906 self.query, self.fragment)
907
908 if rel.userinfo != oth.userinfo ||
909 rel.host != oth.host ||
910 rel.port != oth.port
911 rel.set_port(nil) if rel.port == oth.default_port
912 return rel, rel
913 end
914 rel.set_userinfo(nil)
915 rel.set_host(nil)
916 rel.set_port(nil)
917
918 if rel.path == oth.path
919 rel.set_path('')
920 rel.set_query(nil) if rel.query == oth.query
921 return rel, rel
922 end
923
924 # you can modify `rel', but can not `oth'.
925 return oth, rel
926 end
927 private :route_from0
928
929 # calculate relative path from oth to self
930 def route_from(oth)
931 # you can modify `rel', but can not `oth'.
932 oth, rel = route_from0(oth)
933 if oth == rel
934 return rel
935 end
936
937 rel.set_path(route_from_path(oth.path, self.path))
938 if rel.path == './' && self.query
939 # "./?foo" -> "?foo"
940 rel.set_path('')
941 end
942
943 return rel
944 end
945 # abs1 - abs2 => relative_path_to_abs1_from_abs2
946 # (see http:
947 alias - route_from
948
949 =begin
950
951 --- URI::Generic#route_to(dst)
952
953 =end
954 # calculate relative path to oth from self
955 def route_to(oth)
956 case oth
957 when Generic
958 when String
959 oth = URI.parse(oth)
960 else
961 raise ArgumentError,
962 "bad argument(expected URI object or URI string)"
963 end
964
965 oth.route_from(self)
966 end
967
968 =begin
969
970 --- URI::Generic#normalize
971 --- URI::Generic#normalize!
972
973 =end
974 def normalize
975 uri = dup
976 uri.normalize!
977 uri
978 end
979
980 def normalize!
981 if path && path == ''
982 set_path('/')
983 end
984 if host && host != host.downcase
985 set_host(self.host.downcase)
986 end
987 end
988
989 =begin
990
991 --- URI::Generic#to_s
992
993 =end
994 def path_query
995 str = @path
996 if @query
997 str += '?' + @query
998 end
999 str
1000 end
1001 private :path_query
1002
1003 def to_str
1004 str = ''
1005 if @scheme
1006 str << @scheme
1007 str << ':'
1008 end
1009
1010 if @opaque
1011 str << @opaque
1012
1013 else
1014 if @registry
1015 str << @registry
1016 else
1017 if @host
1018 str << '
1019 end
1020 if self.userinfo
1021 str << self.userinfo
1022 str << '@'
1023 end
1024 if @host
1025 str << @host
1026 end
1027 if @port && @port != self.default_port
1028 str << ':'
1029 str << @port.to_s
1030 end
1031 end
1032
1033 str << path_query
1034 end
1035
1036 if @fragment
1037 str << '#'
1038 str << @fragment
1039 end
1040
1041 str
1042 end
1043
1044 def to_s
1045 to_str
1046 end
1047
1048 =begin
1049
1050 --- URI::Generic#==(oth)
1051
1052 =end
1053 def ==(oth)
1054 if oth.kind_of?(String)
1055 oth = URI.parse(oth)
1056 end
1057
1058 if self.class == oth.class
1059 self.normalize.to_ary == oth.normalize.to_ary
1060 else
1061 false
1062 end
1063 end
1064
1065 =begin
1066
1067 --- URI::Generic#===(oth)
1068
1069 =end
1070 # def ===(oth)
1071 # raise NotImplementedError
1072 # end
1073
1074 =begin
1075 --- URI::Generic#to_a
1076 =end
1077 def to_ary
1078 component.collect do |x|
1079 self.send(x)
1080 end
1081 end
1082
1083 def to_a
1084 to_ary
1085 end
1086
1087 =begin
1088 =end
1089 def inspect
1090 sprintf("#<%s:0x%x URL:%s>", self.type.to_s, self.id, self.to_s)
1091 end
1092
1093 =begin
1094 =end
1095 def coerce(oth)
1096 case oth
1097 when String
1098 oth = URI.parse(oth)
1099 else
1100 super
1101 end
1102
1103 return oth, self
1104 end
1105 end # Generic
1106 end # URI