source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/webrick/httputils.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 10.1 KB
Line 
1#
2# httputils.rb -- HTTPUtils Module
3#
4# Author: IPR -- Internet Programming with Ruby -- writers
5# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
6# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
7# reserved.
8#
9# $IPR: httputils.rb,v 1.34 2003/06/05 21:34:08 gotoyuzo Exp $
10
11require 'socket'
12require 'tempfile'
13
14module WEBrick
15 CR = "\x0d"
16 LF = "\x0a"
17 CRLF = "\x0d\x0a"
18
19 module HTTPUtils
20
21 def normalize_path(path)
22 raise "abnormal path `#{path}'" if path[0] != ?/
23 ret = path.dup
24
25 ret.gsub!(%r{/+}o, '/') # // => /
26 while ret.sub!(%r{/\.(/|\Z)}o, '/'); end # /. => /
27 begin # /foo/.. => /foo
28 match = ret.sub!(%r{/([^/]+)/\.\.(/|\Z)}o){
29 if $1 == ".."
30 raise "abnormal path `#{path}'"
31 else
32 "/"
33 end
34 }
35 end while match
36
37 raise "abnormal path `#{path}'" if %r{/\.\.(/|\Z)} =~ ret
38 ret
39 end
40 module_function :normalize_path
41
42 #####
43
44 DefaultMimeTypes = {
45 "ai" => "application/postscript",
46 "asc" => "text/plain",
47 "avi" => "video/x-msvideo",
48 "bin" => "application/octet-stream",
49 "bmp" => "image/bmp",
50 "class" => "application/octet-stream",
51 "cer" => "application/pkix-cert",
52 "crl" => "application/pkix-crl",
53 "crt" => "application/x-x509-ca-cert",
54 #"crl" => "application/x-pkcs7-crl",
55 "css" => "text/css",
56 "dms" => "application/octet-stream",
57 "doc" => "application/msword",
58 "dvi" => "application/x-dvi",
59 "eps" => "application/postscript",
60 "etx" => "text/x-setext",
61 "exe" => "application/octet-stream",
62 "gif" => "image/gif",
63 "htm" => "text/html",
64 "html" => "text/html",
65 "jpe" => "image/jpeg",
66 "jpeg" => "image/jpeg",
67 "jpg" => "image/jpeg",
68 "lha" => "application/octet-stream",
69 "lzh" => "application/octet-stream",
70 "mov" => "video/quicktime",
71 "mpe" => "video/mpeg",
72 "mpeg" => "video/mpeg",
73 "mpg" => "video/mpeg",
74 "pbm" => "image/x-portable-bitmap",
75 "pdf" => "application/pdf",
76 "pgm" => "image/x-portable-graymap",
77 "png" => "image/png",
78 "pnm" => "image/x-portable-anymap",
79 "ppm" => "image/x-portable-pixmap",
80 "ppt" => "application/vnd.ms-powerpoint",
81 "ps" => "application/postscript",
82 "qt" => "video/quicktime",
83 "ras" => "image/x-cmu-raster",
84 "rb" => "text/plain",
85 "rd" => "text/plain",
86 "rtf" => "application/rtf",
87 "sgm" => "text/sgml",
88 "sgml" => "text/sgml",
89 "tif" => "image/tiff",
90 "tiff" => "image/tiff",
91 "txt" => "text/plain",
92 "xbm" => "image/x-xbitmap",
93 "xls" => "application/vnd.ms-excel",
94 "xml" => "text/xml",
95 "xpm" => "image/x-xpixmap",
96 "xwd" => "image/x-xwindowdump",
97 "zip" => "application/zip",
98 }
99
100 # Load Apache compatible mime.types file.
101 def load_mime_types(file)
102 open(file){ |io|
103 hash = Hash.new
104 io.each{ |line|
105 next if /^#/ =~ line
106 line.chomp!
107 mimetype, ext0 = line.split(/\s+/, 2)
108 next unless ext0
109 next if ext0.empty?
110 ext0.split(/\s+/).each{ |ext| hash[ext] = mimetype }
111 }
112 hash
113 }
114 end
115 module_function :load_mime_types
116
117 def mime_type(filename, mime_tab)
118 suffix1 = (/\.(\w+)$/ =~ filename && $1.downcase)
119 suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ filename && $1.downcase)
120 mime_tab[suffix1] || mime_tab[suffix2] || "application/octet-stream"
121 end
122 module_function :mime_type
123
124 #####
125
126 def parse_header(raw)
127 header = Hash.new([].freeze)
128 field = nil
129 raw.each{|line|
130 case line
131 when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):\s*(.*?)\s*\z/om
132 field, value = $1, $2
133 field.downcase!
134 header[field] = [] unless header.has_key?(field)
135 header[field] << value
136 when /^\s+(.*?)\s*\z/om
137 value = $1
138 unless field
139 raise "bad header '#{line.inspect}'."
140 end
141 header[field][-1] << " " << value
142 else
143 raise "bad header '#{line.inspect}'."
144 end
145 }
146 header.each{|key, values|
147 values.each{|value|
148 value.strip!
149 value.gsub!(/\s+/, " ")
150 }
151 }
152 header
153 end
154 module_function :parse_header
155
156 def split_header_value(str)
157 str.scan(/((?:"(?:\\.|[^"])+?"|[^",]+)+)
158 (?:,\s*|\Z)/xn).collect{|v| v[0] }
159 end
160 module_function :split_header_value
161
162 def parse_range_header(ranges_specifier)
163 if /^bytes=(.*)/ =~ ranges_specifier
164 byte_range_set = split_header_value($1)
165 byte_range_set.collect{|range_spec|
166 case range_spec
167 when /^(\d+)-(\d+)/ then $1.to_i .. $2.to_i
168 when /^(\d+)-/ then $1.to_i .. -1
169 when /^-(\d+)/ then -($1.to_i) .. -1
170 else return nil
171 end
172 }
173 end
174 end
175 module_function :parse_range_header
176
177 def parse_qvalues(value)
178 tmp = []
179 if value
180 parts = value.split(/,\s*/)
181 parts.each {|part|
182 if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
183 val = m[1]
184 q = (m[2] or 1).to_f
185 tmp.push([val, q])
186 end
187 }
188 tmp = tmp.sort_by{|val, q| -q}
189 tmp.collect!{|val, q| val}
190 end
191 return tmp
192 end
193 module_function :parse_qvalues
194
195 #####
196
197 def dequote(str)
198 ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
199 ret.gsub!(/\\(.)/, "\\1")
200 ret
201 end
202 module_function :dequote
203
204 def quote(str)
205 '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
206 end
207 module_function :quote
208
209 #####
210
211 class FormData < String
212 EmptyRawHeader = [].freeze
213 EmptyHeader = {}.freeze
214
215 attr_accessor :name, :filename, :next_data
216 protected :next_data
217
218 def initialize(*args)
219 @name = @filename = @next_data = nil
220 if args.empty?
221 @raw_header = []
222 @header = nil
223 super("")
224 else
225 @raw_header = EmptyRawHeader
226 @header = EmptyHeader
227 super(args.shift)
228 unless args.empty?
229 @next_data = self.class.new(*args)
230 end
231 end
232 end
233
234 def [](*key)
235 begin
236 @header[key[0].downcase].join(", ")
237 rescue StandardError, NameError
238 super
239 end
240 end
241
242 def <<(str)
243 if @header
244 super
245 elsif str == CRLF
246 @header = HTTPUtils::parse_header(@raw_header)
247 if cd = self['content-disposition']
248 if /\s+name="(.*?)"/ =~ cd then @name = $1 end
249 if /\s+filename="(.*?)"/ =~ cd then @filename = $1 end
250 end
251 else
252 @raw_header << str
253 end
254 self
255 end
256
257 def append_data(data)
258 tmp = self
259 while tmp
260 unless tmp.next_data
261 tmp.next_data = data
262 break
263 end
264 tmp = tmp.next_data
265 end
266 self
267 end
268
269 def each_data
270 tmp = self
271 while tmp
272 next_data = tmp.next_data
273 yield(tmp)
274 tmp = next_data
275 end
276 end
277
278 def list
279 ret = []
280 each_data{|data|
281 ret << data.to_s
282 }
283 ret
284 end
285
286 alias :to_ary :list
287
288 def to_s
289 String.new(self)
290 end
291 end
292
293 def parse_query(str)
294 query = Hash.new
295 if str
296 str.split(/[&;]/).each{|x|
297 next if x.empty?
298 key, val = x.split(/=/,2)
299 key = unescape_form(key)
300 val = unescape_form(val.to_s)
301 val = FormData.new(val)
302 val.name = key
303 if query.has_key?(key)
304 query[key].append_data(val)
305 next
306 end
307 query[key] = val
308 }
309 end
310 query
311 end
312 module_function :parse_query
313
314 def parse_form_data(io, boundary)
315 boundary_regexp = /\A--#{boundary}(--)?#{CRLF}\z/
316 form_data = Hash.new
317 return form_data unless io
318 data = nil
319 io.each{|line|
320 if boundary_regexp =~ line
321 if data
322 data.chop!
323 key = data.name
324 if form_data.has_key?(key)
325 form_data[key].append_data(data)
326 else
327 form_data[key] = data
328 end
329 end
330 data = FormData.new
331 next
332 else
333 if data
334 data << line
335 end
336 end
337 }
338 return form_data
339 end
340 module_function :parse_form_data
341
342 #####
343
344 reserved = ';/?:@&=+$,'
345 num = '0123456789'
346 lowalpha = 'abcdefghijklmnopqrstuvwxyz'
347 upalpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
348 mark = '-_.!~*\'()'
349 unreserved = num + lowalpha + upalpha + mark
350 control = (0x0..0x1f).collect{|c| c.chr }.join + "\x7f"
351 space = " "
352 delims = '<>#%"'
353 unwise = '{}|\\^[]`'
354 nonascii = (0x80..0xff).collect{|c| c.chr }.join
355
356 module_function
357
358 def _make_regex(str) /([#{Regexp.escape(str)}])/n end
359 def _make_regex!(str) /([^#{Regexp.escape(str)}])/n end
360 def _escape(str, regex) str.gsub(regex){ "%%%02X" % $1[0] } end
361 def _unescape(str, regex) str.gsub(regex){ $1.hex.chr } end
362
363 UNESCAPED = _make_regex(control+space+delims+unwise+nonascii)
364 UNESCAPED_FORM = _make_regex(reserved+control+delims+unwise+nonascii)
365 NONASCII = _make_regex(nonascii)
366 ESCAPED = /%([0-9a-fA-F]{2})/
367 UNESCAPED_PCHAR = _make_regex!(unreserved+":@&=+$,")
368
369 def escape(str)
370 _escape(str, UNESCAPED)
371 end
372
373 def unescape(str)
374 _unescape(str, ESCAPED)
375 end
376
377 def escape_form(str)
378 ret = _escape(str, UNESCAPED_FORM)
379 ret.gsub!(/ /, "+")
380 ret
381 end
382
383 def unescape_form(str)
384 _unescape(str.gsub(/\+/, " "), ESCAPED)
385 end
386
387 def escape_path(str)
388 result = ""
389 str.scan(%r{/([^/]*)}).each{|i|
390 result << "/" << _escape(i[0], UNESCAPED_PCHAR)
391 }
392 return result
393 end
394
395 def escape8bit(str)
396 _escape(str, NONASCII)
397 end
398 end
399end
Note: See TracBrowser for help on using the repository browser.