webrick 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of webrick might be problematic. Click here for more details.

@@ -10,10 +10,11 @@
10
10
  # $IPR: httpresponse.rb,v 1.45 2003/07/11 11:02:25 gotoyuzo Exp $
11
11
 
12
12
  require 'time'
13
- require 'webrick/httpversion'
14
- require 'webrick/htmlutils'
15
- require 'webrick/httputils'
16
- require 'webrick/httpstatus'
13
+ require 'uri'
14
+ require_relative 'httpversion'
15
+ require_relative 'htmlutils'
16
+ require_relative 'httputils'
17
+ require_relative 'httpstatus'
17
18
 
18
19
  module WEBrick
19
20
  ##
@@ -21,6 +22,8 @@ module WEBrick
21
22
  # WEBrick HTTP Servlet.
22
23
 
23
24
  class HTTPResponse
25
+ class InvalidHeader < StandardError
26
+ end
24
27
 
25
28
  ##
26
29
  # HTTP Response version
@@ -110,13 +113,14 @@ module WEBrick
110
113
  @chunked = false
111
114
  @filename = nil
112
115
  @sent_size = 0
116
+ @bodytempfile = nil
113
117
  end
114
118
 
115
119
  ##
116
120
  # The response's HTTP status line
117
121
 
118
122
  def status_line
119
- "HTTP/#@http_version #@status #@reason_phrase #{CRLF}"
123
+ "HTTP/#@http_version #@status #@reason_phrase".rstrip << CRLF
120
124
  end
121
125
 
122
126
  ##
@@ -250,8 +254,11 @@ module WEBrick
250
254
  elsif %r{^multipart/byteranges} =~ @header['content-type']
251
255
  @header.delete('content-length')
252
256
  elsif @header['content-length'].nil?
253
- unless @body.is_a?(IO)
254
- @header['content-length'] = @body ? @body.bytesize : 0
257
+ if @body.respond_to? :readpartial
258
+ elsif @body.respond_to? :call
259
+ make_body_tempfile
260
+ else
261
+ @header['content-length'] = (@body ? @body.bytesize : 0).to_s
255
262
  end
256
263
  end
257
264
 
@@ -274,11 +281,38 @@ module WEBrick
274
281
  # Location is a single absoluteURI.
275
282
  if location = @header['location']
276
283
  if @request_uri
277
- @header['location'] = @request_uri.merge(location)
284
+ @header['location'] = @request_uri.merge(location).to_s
278
285
  end
279
286
  end
280
287
  end
281
288
 
289
+ def make_body_tempfile # :nodoc:
290
+ return if @bodytempfile
291
+ bodytempfile = Tempfile.create("webrick")
292
+ if @body.nil?
293
+ # nothing
294
+ elsif @body.respond_to? :readpartial
295
+ IO.copy_stream(@body, bodytempfile)
296
+ @body.close
297
+ elsif @body.respond_to? :call
298
+ @body.call(bodytempfile)
299
+ else
300
+ bodytempfile.write @body
301
+ end
302
+ bodytempfile.rewind
303
+ @body = @bodytempfile = bodytempfile
304
+ @header['content-length'] = bodytempfile.stat.size.to_s
305
+ end
306
+
307
+ def remove_body_tempfile # :nodoc:
308
+ if @bodytempfile
309
+ @bodytempfile.close
310
+ File.unlink @bodytempfile.path
311
+ @bodytempfile = nil
312
+ end
313
+ end
314
+
315
+
282
316
  ##
283
317
  # Sends the headers on +socket+
284
318
 
@@ -287,14 +321,19 @@ module WEBrick
287
321
  data = status_line()
288
322
  @header.each{|key, value|
289
323
  tmp = key.gsub(/\bwww|^te$|\b\w/){ $&.upcase }
290
- data << "#{tmp}: #{value}" << CRLF
324
+ data << "#{tmp}: #{check_header(value)}" << CRLF
291
325
  }
292
326
  @cookies.each{|cookie|
293
- data << "Set-Cookie: " << cookie.to_s << CRLF
327
+ data << "Set-Cookie: " << check_header(cookie.to_s) << CRLF
294
328
  }
295
329
  data << CRLF
296
- _write_data(socket, data)
330
+ socket.write(data)
297
331
  end
332
+ rescue InvalidHeader => e
333
+ @header.clear
334
+ @cookies.clear
335
+ set_error e
336
+ retry
298
337
  end
299
338
 
300
339
  ##
@@ -310,12 +349,6 @@ module WEBrick
310
349
  end
311
350
  end
312
351
 
313
- def to_s # :nodoc:
314
- ret = ""
315
- send_response(ret)
316
- ret
317
- end
318
-
319
352
  ##
320
353
  # Redirects to +url+ with a WEBrick::HTTPStatus::Redirect +status+.
321
354
  #
@@ -324,8 +357,9 @@ module WEBrick
324
357
  # res.set_redirect WEBrick::HTTPStatus::TemporaryRedirect
325
358
 
326
359
  def set_redirect(status, url)
360
+ url = URI(url).to_s
327
361
  @body = "<HTML><A HREF=\"#{url}\">#{url}</A>.</HTML>\n"
328
- @header['location'] = url.to_s
362
+ @header['location'] = url
329
363
  raise status
330
364
  end
331
365
 
@@ -359,6 +393,15 @@ module WEBrick
359
393
 
360
394
  private
361
395
 
396
+ def check_header(header_value)
397
+ header_value = header_value.to_s
398
+ if /[\r\n]/ =~ header_value
399
+ raise InvalidHeader
400
+ else
401
+ header_value
402
+ end
403
+ end
404
+
362
405
  # :stopdoc:
363
406
 
364
407
  def error_body(backtrace, ex, host, port)
@@ -401,22 +444,34 @@ module WEBrick
401
444
  @body.readpartial(@buffer_size, buf)
402
445
  size = buf.bytesize
403
446
  data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
404
- _write_data(socket, data)
447
+ socket.write(data)
405
448
  data.clear
406
449
  @sent_size += size
407
450
  rescue EOFError
408
451
  break
409
452
  end while true
410
453
  buf.clear
411
- _write_data(socket, "0#{CRLF}#{CRLF}")
454
+ socket.write("0#{CRLF}#{CRLF}")
412
455
  else
413
- size = @header['content-length'].to_i
414
- _send_file(socket, @body, 0, size)
415
- @sent_size = size
456
+ if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ @header['content-range']
457
+ offset = $1.to_i
458
+ size = $2.to_i - offset + 1
459
+ else
460
+ offset = nil
461
+ size = @header['content-length']
462
+ size = size.to_i if size
463
+ end
464
+ begin
465
+ @sent_size = IO.copy_stream(@body, socket, size, offset)
466
+ rescue NotImplementedError
467
+ @body.seek(offset, IO::SEEK_SET)
468
+ @sent_size = IO.copy_stream(@body, socket, size)
469
+ end
416
470
  end
417
471
  ensure
418
472
  @body.close
419
473
  end
474
+ remove_body_tempfile
420
475
  end
421
476
 
422
477
  def send_body_string(socket)
@@ -429,13 +484,13 @@ module WEBrick
429
484
  size = buf.bytesize
430
485
  data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
431
486
  buf.clear
432
- _write_data(socket, data)
487
+ socket.write(data)
433
488
  @sent_size += size
434
489
  end
435
- _write_data(socket, "0#{CRLF}#{CRLF}")
490
+ socket.write("0#{CRLF}#{CRLF}")
436
491
  else
437
492
  if @body && @body.bytesize > 0
438
- _write_data(socket, @body)
493
+ socket.write(@body)
439
494
  @sent_size = @body.bytesize
440
495
  end
441
496
  end
@@ -446,10 +501,15 @@ module WEBrick
446
501
  # do nothing
447
502
  elsif chunked?
448
503
  @body.call(ChunkedWrapper.new(socket, self))
449
- _write_data(socket, "0#{CRLF}#{CRLF}")
504
+ socket.write("0#{CRLF}#{CRLF}")
450
505
  else
451
506
  size = @header['content-length'].to_i
452
- @body.call(socket)
507
+ if @bodytempfile
508
+ @bodytempfile.rewind
509
+ IO.copy_stream(@bodytempfile, socket)
510
+ else
511
+ @body.call(socket)
512
+ end
453
513
  @sent_size = size
454
514
  end
455
515
  end
@@ -461,40 +521,25 @@ module WEBrick
461
521
  end
462
522
 
463
523
  def write(buf)
464
- return if buf.empty?
524
+ return 0 if buf.empty?
465
525
  socket = @socket
466
526
  @resp.instance_eval {
467
527
  size = buf.bytesize
468
528
  data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
469
- _write_data(socket, data)
529
+ socket.write(data)
470
530
  data.clear
471
531
  @sent_size += size
532
+ size
472
533
  }
473
534
  end
474
- alias :<< :write
475
- end
476
-
477
- def _send_file(output, input, offset, size)
478
- while offset > 0
479
- sz = @buffer_size < size ? @buffer_size : size
480
- buf = input.read(sz)
481
- offset -= buf.bytesize
482
- end
483
535
 
484
- if size == 0
485
- while buf = input.read(@buffer_size)
486
- _write_data(output, buf)
487
- end
488
- else
489
- while size > 0
490
- sz = @buffer_size < size ? @buffer_size : size
491
- buf = input.read(sz)
492
- _write_data(output, buf)
493
- size -= buf.bytesize
494
- end
536
+ def <<(*buf)
537
+ write(buf)
538
+ self
495
539
  end
496
540
  end
497
541
 
542
+ # preserved for compatibility with some 3rd-party handlers
498
543
  def _write_data(socket, data)
499
544
  socket << data
500
545
  end
data/lib/webrick/https.rb CHANGED
@@ -9,8 +9,8 @@
9
9
  #
10
10
  # $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
11
11
 
12
- require 'webrick/ssl'
13
- require 'webrick/httpserver'
12
+ require_relative 'ssl'
13
+ require_relative 'httpserver'
14
14
 
15
15
  module WEBrick
16
16
  module Config
@@ -10,13 +10,13 @@
10
10
  # $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $
11
11
 
12
12
  require 'io/wait'
13
- require 'webrick/server'
14
- require 'webrick/httputils'
15
- require 'webrick/httpstatus'
16
- require 'webrick/httprequest'
17
- require 'webrick/httpresponse'
18
- require 'webrick/httpservlet'
19
- require 'webrick/accesslog'
13
+ require_relative 'server'
14
+ require_relative 'httputils'
15
+ require_relative 'httpstatus'
16
+ require_relative 'httprequest'
17
+ require_relative 'httpresponse'
18
+ require_relative 'httpservlet'
19
+ require_relative 'accesslog'
20
20
 
21
21
  module WEBrick
22
22
  class HTTPServerError < ServerError; end
@@ -68,8 +68,8 @@ module WEBrick
68
68
 
69
69
  def run(sock)
70
70
  while true
71
- res = HTTPResponse.new(@config)
72
- req = HTTPRequest.new(@config)
71
+ req = create_request(@config)
72
+ res = create_response(@config)
73
73
  server = self
74
74
  begin
75
75
  timeout = @config[:RequestTimeout]
@@ -224,6 +224,20 @@ module WEBrick
224
224
  }
225
225
  end
226
226
 
227
+ ##
228
+ # Creates the HTTPRequest used when handling the HTTP
229
+ # request. Can be overridden by subclasses.
230
+ def create_request(with_webrick_config)
231
+ HTTPRequest.new(with_webrick_config)
232
+ end
233
+
234
+ ##
235
+ # Creates the HTTPResponse used when handling the HTTP
236
+ # request. Can be overridden by subclasses.
237
+ def create_response(with_webrick_config)
238
+ HTTPResponse.new(with_webrick_config)
239
+ end
240
+
227
241
  ##
228
242
  # Mount table for the path a servlet is mounted on in the directory space
229
243
  # of the server. Users of WEBrick can only access this indirectly via
@@ -9,9 +9,9 @@
9
9
  #
10
10
  # $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $
11
11
 
12
- require 'webrick/htmlutils'
13
- require 'webrick/httputils'
14
- require 'webrick/httpstatus'
12
+ require_relative '../htmlutils'
13
+ require_relative '../httputils'
14
+ require_relative '../httpstatus'
15
15
 
16
16
  module WEBrick
17
17
  module HTTPServlet
@@ -23,11 +23,11 @@ STDIN.binmode
23
23
 
24
24
  len = sysread(STDIN, 8).to_i
25
25
  out = sysread(STDIN, len)
26
- STDOUT.reopen(open(out, "w"))
26
+ STDOUT.reopen(File.open(out, "w"))
27
27
 
28
28
  len = sysread(STDIN, 8).to_i
29
29
  err = sysread(STDIN, len)
30
- STDERR.reopen(open(err, "w"))
30
+ STDERR.reopen(File.open(err, "w"))
31
31
 
32
32
  len = sysread(STDIN, 8).to_i
33
33
  dump = sysread(STDIN, len)
@@ -11,8 +11,8 @@
11
11
 
12
12
  require 'rbconfig'
13
13
  require 'tempfile'
14
- require 'webrick/config'
15
- require 'webrick/httpservlet/abstract'
14
+ require_relative '../config'
15
+ require_relative 'abstract'
16
16
 
17
17
  module WEBrick
18
18
  module HTTPServlet
@@ -65,9 +65,7 @@ module WEBrick
65
65
  cgi_in.write("%8d" % dump.bytesize)
66
66
  cgi_in.write(dump)
67
67
 
68
- if req.body and req.body.bytesize > 0
69
- cgi_in.write(req.body)
70
- end
68
+ req.body { |chunk| cgi_in.write(chunk) }
71
69
  ensure
72
70
  cgi_in.close
73
71
  status = $?.exitstatus
@@ -9,7 +9,7 @@
9
9
  #
10
10
  # $IPR: erbhandler.rb,v 1.25 2003/02/24 19:25:31 gotoyuzo Exp $
11
11
 
12
- require 'webrick/httpservlet/abstract.rb'
12
+ require_relative 'abstract'
13
13
 
14
14
  require 'erb'
15
15
 
@@ -53,7 +53,7 @@ module WEBrick
53
53
  raise HTTPStatus::Forbidden, "ERBHandler cannot work."
54
54
  end
55
55
  begin
56
- data = open(@script_filename){|io| io.read }
56
+ data = File.open(@script_filename, &:read)
57
57
  res.body = evaluate(ERB.new(data), req, res)
58
58
  res['content-type'] ||=
59
59
  HTTPUtils::mime_type(@script_filename, @config[:MimeTypes])
@@ -11,9 +11,9 @@
11
11
 
12
12
  require 'time'
13
13
 
14
- require 'webrick/htmlutils'
15
- require 'webrick/httputils'
16
- require 'webrick/httpstatus'
14
+ require_relative '../htmlutils'
15
+ require_relative '../httputils'
16
+ require_relative '../httpstatus'
17
17
 
18
18
  module WEBrick
19
19
  module HTTPServlet
@@ -55,9 +55,9 @@ module WEBrick
55
55
  else
56
56
  mtype = HTTPUtils::mime_type(@local_path, @config[:MimeTypes])
57
57
  res['content-type'] = mtype
58
- res['content-length'] = st.size
58
+ res['content-length'] = st.size.to_s
59
59
  res['last-modified'] = mtime.httpdate
60
- res.body = open(@local_path, "rb")
60
+ res.body = File.open(@local_path, "rb")
61
61
  end
62
62
  end
63
63
 
@@ -86,47 +86,66 @@ module WEBrick
86
86
  return false
87
87
  end
88
88
 
89
+ # returns a lambda for webrick/httpresponse.rb send_body_proc
90
+ def multipart_body(body, parts, boundary, mtype, filesize)
91
+ lambda do |socket|
92
+ begin
93
+ begin
94
+ first = parts.shift
95
+ last = parts.shift
96
+ socket.write(
97
+ "--#{boundary}#{CRLF}" \
98
+ "Content-Type: #{mtype}#{CRLF}" \
99
+ "Content-Range: bytes #{first}-#{last}/#{filesize}#{CRLF}" \
100
+ "#{CRLF}"
101
+ )
102
+
103
+ begin
104
+ IO.copy_stream(body, socket, last - first + 1, first)
105
+ rescue NotImplementedError
106
+ body.seek(first, IO::SEEK_SET)
107
+ IO.copy_stream(body, socket, last - first + 1)
108
+ end
109
+ socket.write(CRLF)
110
+ end while parts[0]
111
+ socket.write("--#{boundary}--#{CRLF}")
112
+ ensure
113
+ body.close
114
+ end
115
+ end
116
+ end
117
+
89
118
  def make_partial_content(req, res, filename, filesize)
90
119
  mtype = HTTPUtils::mime_type(filename, @config[:MimeTypes])
91
120
  unless ranges = HTTPUtils::parse_range_header(req['range'])
92
121
  raise HTTPStatus::BadRequest,
93
122
  "Unrecognized range-spec: \"#{req['range']}\""
94
123
  end
95
- open(filename, "rb"){|io|
124
+ File.open(filename, "rb"){|io|
96
125
  if ranges.size > 1
97
126
  time = Time.now
98
127
  boundary = "#{time.sec}_#{time.usec}_#{Process::pid}"
99
- body = ''
100
- ranges.each{|range|
101
- first, last = prepare_range(range, filesize)
102
- next if first < 0
103
- io.pos = first
104
- content = io.read(last-first+1)
105
- body << "--" << boundary << CRLF
106
- body << "Content-Type: #{mtype}" << CRLF
107
- body << "Content-Range: bytes #{first}-#{last}/#{filesize}" << CRLF
108
- body << CRLF
109
- body << content
110
- body << CRLF
128
+ parts = []
129
+ ranges.each {|range|
130
+ prange = prepare_range(range, filesize)
131
+ next if prange[0] < 0
132
+ parts.concat(prange)
111
133
  }
112
- raise HTTPStatus::RequestRangeNotSatisfiable if body.empty?
113
- body << "--" << boundary << "--" << CRLF
134
+ raise HTTPStatus::RequestRangeNotSatisfiable if parts.empty?
114
135
  res["content-type"] = "multipart/byteranges; boundary=#{boundary}"
115
- res.body = body
136
+ if req.http_version < '1.1'
137
+ res['connection'] = 'close'
138
+ else
139
+ res.chunked = true
140
+ end
141
+ res.body = multipart_body(io.dup, parts, boundary, mtype, filesize)
116
142
  elsif range = ranges[0]
117
143
  first, last = prepare_range(range, filesize)
118
144
  raise HTTPStatus::RequestRangeNotSatisfiable if first < 0
119
- if last == filesize - 1
120
- content = io.dup
121
- content.pos = first
122
- else
123
- io.pos = first
124
- content = io.read(last-first+1)
125
- end
126
145
  res['content-type'] = mtype
127
146
  res['content-range'] = "bytes #{first}-#{last}/#{filesize}"
128
- res['content-length'] = last - first + 1
129
- res.body = content
147
+ res['content-length'] = (last - first + 1).to_s
148
+ res.body = io.dup
130
149
  else
131
150
  raise HTTPStatus::BadRequest
132
151
  end
@@ -9,7 +9,7 @@
9
9
  #
10
10
  # $IPR: prochandler.rb,v 1.7 2002/09/21 12:23:42 gotoyuzo Exp $
11
11
 
12
- require 'webrick/httpservlet/abstract.rb'
12
+ require_relative 'abstract'
13
13
 
14
14
  module WEBrick
15
15
  module HTTPServlet
@@ -9,11 +9,11 @@
9
9
  #
10
10
  # $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $
11
11
 
12
- require 'webrick/httpservlet/abstract'
13
- require 'webrick/httpservlet/filehandler'
14
- require 'webrick/httpservlet/cgihandler'
15
- require 'webrick/httpservlet/erbhandler'
16
- require 'webrick/httpservlet/prochandler'
12
+ require_relative 'httpservlet/abstract'
13
+ require_relative 'httpservlet/filehandler'
14
+ require_relative 'httpservlet/cgihandler'
15
+ require_relative 'httpservlet/erbhandler'
16
+ require_relative 'httpservlet/prochandler'
17
17
 
18
18
  module WEBrick
19
19
  module HTTPServlet
@@ -9,7 +9,7 @@
9
9
  #
10
10
  # $IPR: httpstatus.rb,v 1.11 2003/03/24 20:18:55 gotoyuzo Exp $
11
11
 
12
- require 'webrick/accesslog'
12
+ require_relative 'accesslog'
13
13
 
14
14
  module WEBrick
15
15
 
@@ -95,6 +95,7 @@ module WEBrick
95
95
  "tif" => "image/tiff",
96
96
  "tiff" => "image/tiff",
97
97
  "txt" => "text/plain",
98
+ "wasm" => "application/wasm",
98
99
  "xbm" => "image/x-xbitmap",
99
100
  "xhtml" => "text/html",
100
101
  "xls" => "application/vnd.ms-excel",
@@ -108,6 +109,8 @@ module WEBrick
108
109
  # Loads Apache-compatible mime.types in +file+.
109
110
 
110
111
  def load_mime_types(file)
112
+ # note: +file+ may be a "| command" for now; some people may
113
+ # rely on this, but currently we do not use this method by default.
111
114
  open(file){ |io|
112
115
  hash = Hash.new
113
116
  io.each{ |line|
data/lib/webrick/log.rb CHANGED
@@ -51,7 +51,7 @@ module WEBrick
51
51
  @level = level || INFO
52
52
  case log_file
53
53
  when String
54
- @log = open(log_file, "a+")
54
+ @log = File.open(log_file, "a+")
55
55
  @log.sync = true
56
56
  @opened = true
57
57
  when NilClass
@@ -10,8 +10,8 @@
10
10
  # $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
11
11
 
12
12
  require 'socket'
13
- require 'webrick/config'
14
- require 'webrick/log'
13
+ require_relative 'config'
14
+ require_relative 'log'
15
15
 
16
16
  module WEBrick
17
17
 
data/lib/webrick/ssl.rb CHANGED
@@ -130,7 +130,7 @@ module WEBrick
130
130
  aki = ef.create_extension("authorityKeyIdentifier",
131
131
  "keyid:always,issuer:always")
132
132
  cert.add_extension(aki)
133
- cert.sign(rsa, OpenSSL::Digest::SHA1.new)
133
+ cert.sign(rsa, OpenSSL::Digest::SHA256.new)
134
134
 
135
135
  return [ cert, rsa ]
136
136
  end
@@ -181,7 +181,7 @@ module WEBrick
181
181
  unless config[:SSLCertificate]
182
182
  cn = config[:SSLCertName]
183
183
  comment = config[:SSLCertComment]
184
- cert, key = Utils::create_self_signed_cert(1024, cn, comment)
184
+ cert, key = Utils::create_self_signed_cert(2048, cn, comment)
185
185
  config[:SSLCertificate] = cert
186
186
  config[:SSLPrivateKey] = key
187
187
  end
@@ -14,5 +14,5 @@ module WEBrick
14
14
  ##
15
15
  # The WEBrick version
16
16
 
17
- VERSION = "1.4.0"
17
+ VERSION = "1.5.0"
18
18
  end
data/lib/webrick.rb CHANGED
@@ -212,7 +212,7 @@ require 'webrick/version.rb'
212
212
  require 'webrick/config.rb'
213
213
  require 'webrick/log.rb'
214
214
  require 'webrick/server.rb'
215
- require 'webrick/utils.rb'
215
+ require_relative 'webrick/utils.rb'
216
216
  require 'webrick/accesslog'
217
217
 
218
218
  require 'webrick/htmlutils.rb'