Skip to content

Commit

Permalink
Showing 414 changed files with 9,782 additions and 952 deletions.
3 changes: 1 addition & 2 deletions core/pom.rb
Original file line number Diff line number Diff line change
@@ -252,8 +252,7 @@
'shadedPattern' => 'org.jruby.org.objectweb' } ],
'outputFile' => '${jruby.basedir}/lib/jruby.jar',
'transformers' => [ { '@implementation' => 'org.apache.maven.plugins.shade.resource.ManifestResourceTransformer',
'mainClass' => 'org.jruby.Main' } ],
:artifactSet => { :excludes => ['com.github.jnr:jffi:native'] } )
'mainClass' => 'org.jruby.Main' } ] )
end

[:release, :main, :osgi, :j2ee, :complete, :dist, :'jruby_complete_jar_extended', :'jruby-jars' ].each do |name|
5 changes: 0 additions & 5 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -544,11 +544,6 @@
<mainClass>org.jruby.Main</mainClass>
</transformer>
</transformers>
<artifactSet>
<excludes>
<exclude>com.github.jnr:jffi:native</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyArray.java
Original file line number Diff line number Diff line change
@@ -2797,7 +2797,7 @@ private boolean flatten(ThreadContext context, int level, RubyArray result) {
IRubyObject tmp;
while (i < ary.realLength) {
IRubyObject elt = ary.values[ary.begin + i++];
tmp = elt.checkArrayType();
tmp = TypeConverter.checkArrayType(elt);
if (tmp.isNil() || (level >= 0 && stack.realLength / 2 >= level)) {
result.append(elt);
} else {
14 changes: 3 additions & 11 deletions core/src/main/java/org/jruby/RubyBasicObject.java
Original file line number Diff line number Diff line change
@@ -784,11 +784,7 @@ public IRubyObject anyToString() {
*/
@Override
public IRubyObject checkStringType() {
IRubyObject str = TypeConverter.convertToTypeWithCheck(this, getRuntime().getString(), "to_str");
if(!str.isNil() && !(str instanceof RubyString)) {
str = RubyString.newEmptyString(getRuntime());
}
return str;
return TypeConverter.checkStringType(getRuntime(), this);
}

/** rb_check_string_type
@@ -800,11 +796,7 @@ public IRubyObject checkStringType() {
*/
@Override
public IRubyObject checkStringType19() {
IRubyObject str = TypeConverter.convertToTypeWithCheck19(this, getRuntime().getString(), "to_str");
if(!str.isNil() && !(str instanceof RubyString)) {
str = RubyString.newEmptyString(getRuntime());
}
return str;
return TypeConverter.checkStringType(getRuntime(), this);
}

/** rb_check_array_type
@@ -814,7 +806,7 @@ public IRubyObject checkStringType19() {
*/
@Override
public IRubyObject checkArrayType() {
return TypeConverter.convertToTypeWithCheck(this, getRuntime().getArray(), "to_ary");
return TypeConverter.checkArrayType(getRuntime(), this);
}

/**
11 changes: 10 additions & 1 deletion core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
@@ -616,6 +616,11 @@ public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name)
return method.call(context, self, this, name);
}

/**
* Safely attempt to invoke the given method name on self, using respond_to? and method_missing as appropriate.
*
* MRI: rb_check_funcall
*/
public IRubyObject finvokeChecked(ThreadContext context, IRubyObject self, String name) {
RubyClass klass = self.getMetaClass();
DynamicMethod me;
@@ -645,7 +650,11 @@ private static IRubyObject checkFuncallFailed(ThreadContext context, IRubyObject
return null;
}

// MRI: check_funcall_respond_to
/**
* Check if the method has a custom respond_to? and call it if so with the method ID we're hoping to call.
*
* MRI: check_funcall_respond_to
*/
private static boolean checkFuncallRespondTo(ThreadContext context, RubyClass klass, IRubyObject recv, String mid) {
Ruby runtime = context.runtime;
RubyClass defined_class;
9 changes: 8 additions & 1 deletion core/src/main/java/org/jruby/lexer/yacc/RubyLexer.java
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@
import org.joni.Option;
import org.joni.Regex;
import org.jruby.Ruby;
import org.jruby.RubyEncoding;
import org.jruby.RubyRegexp;
import org.jruby.ast.BackRefNode;
import org.jruby.ast.BignumNode;
@@ -314,7 +315,13 @@ public String createTokenString() {
// FIXME: We should be able to move some faster non-exception cache using Encoding.isDefined
try {
charset = current_enc.getCharset();
if (charset != null) return new String(bytes, begin + tokp, lex_p - tokp, charset);
if (charset != null) {
if (charset == RubyEncoding.UTF8) {
return RubyEncoding.decodeUTF8(bytes, begin + tokp, lex_p - tokp);
} else {
return new String(bytes, begin + tokp, lex_p - tokp, charset);
}
}
} catch (UnsupportedCharsetException e) {}


1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/runtime/Helpers.java
Original file line number Diff line number Diff line change
@@ -456,6 +456,7 @@ public static IRubyObject invokeAs(ThreadContext context, RubyClass asClass, IRu
return asClass.finvoke(context, self, name, arg0, arg1, arg2, block);
}

// MRI: rb_check_funcall
public static IRubyObject invokeChecked(ThreadContext context, IRubyObject self, String name) {
return self.getMetaClass().finvokeChecked(context, self, name);
}
6 changes: 5 additions & 1 deletion core/src/main/java/org/jruby/util/io/OpenFile.java
Original file line number Diff line number Diff line change
@@ -895,7 +895,7 @@ public void finalize(ThreadContext context, boolean noraise) {
// MRI: NEED_READCONV
public boolean needsReadConversion() {
return Platform.IS_WINDOWS ?
(encs.enc2 != null || (encs.ecflags & ~EConvFlags.CRLF_NEWLINE_DECORATOR) != 0)
(encs.enc2 != null || (encs.ecflags & ~EConvFlags.CRLF_NEWLINE_DECORATOR) != 0) || isTextMode()
:
(encs.enc2 != null || NEED_NEWLINE_DECORATOR_ON_READ());
}
@@ -917,6 +917,10 @@ public void makeReadConversion(ThreadContext context, int size) {
IRubyObject ecopts;
byte[] sname, dname;
ecflags = encs.ecflags & ~EConvFlags.NEWLINE_DECORATOR_WRITE_MASK;
if (isTextMode() && Platform.IS_WINDOWS) {
// we can't do O_TEXT so we always do CRLF translation on Windows
ecflags = ecflags | EConvFlags.UNIVERSAL_NEWLINE_DECORATOR;
}
ecopts = encs.ecopts;
if (encs.enc2 != null) {
sname = encs.enc2.getName();
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/util/io/PosixShim.java
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ public int write(ChannelFD fd, byte[] bytes, int offset, int length, boolean non

int written = fd.chWrite.write(tmp);

if (written == 0) {
if (written == 0 && length > 0) {
// if it's a nonblocking write against a file and we've hit EOF, do EAGAIN
if (nonblock) {
errno = Errno.EAGAIN;
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/bigdecimal/jacobian.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/bigdecimal/jacobian'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/bigdecimal/ludcmp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/bigdecimal/ludcmp'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/bigdecimal/math.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/bigdecimal/math'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/bigdecimal/newton.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/bigdecimal/newton'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/bigdecimal/util.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/bigdecimal/util'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/csv.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/csv'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/drb'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/acl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/acl'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/drb.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/drb'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/eq.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/eq'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/extserv.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/extserv'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/extservm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/extsrvm'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/gw.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/gw'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/invokemethod.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/invokemethod'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/observer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/observer'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/ssl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/ssl'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/timeridconv.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/timeridconv'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/drb/unix.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/drb/unix'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/expect.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/expect'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/ftp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/backward.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/exceptions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/generic_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/header.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/proxy_delta.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/requests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/http/responses.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../../stdlib/net/http/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/https.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/imap.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/pop.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/protocol.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/smtp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/net/telnet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../../stdlib/net/' + File.basename(__FILE__)
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/open-uri.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/open-uri'
1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/pstore.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/pstore'
6 changes: 0 additions & 6 deletions lib/ruby/truffle/mri/timeout.rb

This file was deleted.

1 change: 1 addition & 0 deletions lib/ruby/truffle/mri/webrick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative '../../stdlib/' + File.basename(__FILE__)
2 changes: 2 additions & 0 deletions lib/ruby/truffle/rubysl/README.md
Original file line number Diff line number Diff line change
@@ -12,3 +12,5 @@ Commits for each library are:
* rubysl-tempfile `97c4464b4d235f773aab537fbc80608a730a58fc`
* rubysl-socket `3a8c965b36643208da81360ddb4ca7ba867cd3c4`
* rubysl-securerandom `00e31daaf492f7987aa50750dfc3ebc8e8c42a7e`
* rubysl-timeout `4208724abdbd4651b970f7340bffcd83c0458e8e`
* rubysl-webrick `2de980d1e9b889060cdc204d9d153dd40b53425d`
25 changes: 25 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-timeout/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright (c) 2013, Brian Shirai
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the library nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2 changes: 2 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-timeout/lib/rubysl/timeout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require "rubysl/timeout/version"
require "rubysl/timeout/timeout"
197 changes: 197 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-timeout/lib/rubysl/timeout/timeout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#--
# = timeout.rb
#
# execution timeout
#
# = Copyright
#
# Copyright - (C) 2008 Evan Phoenix
# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
#
#++
#
# = Description
#
# A way of performing a potentially long-running operation in a thread, and
# terminating it's execution if it hasn't finished within fixed amount of
# time.
#
# Previous versions of timeout didn't use a module for namespace. This version
# provides both Timeout.timeout, and a backwards-compatible #timeout.
#
# = Synopsis
#
# require 'timeout'
# status = Timeout::timeout(5) {
# # Something that should be interrupted if it takes too much time...
# }
#

require 'thread'

module Timeout

##
# Raised by Timeout#timeout when the block times out.

class Error < RuntimeError
end

# A mutex to protect @requests
@mutex = Mutex.new

# All the outstanding TimeoutRequests
@requests = []

# Represents +thr+ asking for it to be timeout at in +secs+
# seconds. At timeout, raise +exc+.
class TimeoutRequest
def initialize(secs, thr, exc)
@left = secs
@thread = thr
@exception = exc
end

attr_reader :thread, :left

# Called because +time+ seconds have gone by. Returns
# true if the request has no more time left to run.
def elapsed(time)
@left -= time
@left <= 0
end

# Raise @exception if @thread.
def cancel
if @thread and @thread.alive?
@thread.raise @exception, "execution expired"
end

@left = 0
end

# Abort this request, ie, we don't care about tracking
# the thread anymore.
def abort
@thread = nil
@left = 0
end
end

@chan = Rubinius::Channel.new

def self.watch_channel
reqs = []

while true
begin
while reqs.empty?
req = @chan.receive
reqs << req if req
end

min = reqs.min { |a,b| a.left <=> b.left }
new_req = nil

if min.left > 0
before = Time.now

new_req = @chan.receive_timeout(min.left)

slept_for = Time.now - before
else
slept_for = 0
end

reqs.delete_if do |r|
if r.elapsed(slept_for)
r.cancel
true
else
false
end
end
reqs << new_req if new_req

rescue Exception => e
e.render("ERROR IN TIMEOUT THREAD")
end
end
end

# Spin up the thread up front to avoid a thread collision problem spinning
# it up lazily.
@controller = Thread.new { watch_channel }

def self.add_timeout(time, exc)
r = TimeoutRequest.new(time, Thread.current, exc)
@chan << r
return r
end

##
# Executes the method's block. If the block execution terminates before +sec+
# seconds has passed, it returns true. If not, it terminates the execution
# and raises +exception+ (which defaults to Timeout::Error).
#
# Note that this is both a method of module Timeout, so you can 'include
# Timeout' into your classes so they have a #timeout method, as well as a
# module method, so you can call it directly as Timeout.timeout().

def timeout(sec, exception=Error)
return yield if sec == nil or sec.zero?
raise ThreadError, "timeout within critical session" if Thread.respond_to?(:critical) && Thread.critical

req = Timeout.add_timeout sec, exception

begin
yield sec
ensure
req.abort
end
end

module_function :timeout

end

##
# Identical to:
#
# Timeout::timeout(n, e, &block).
#
# Defined for backwards compatibility with earlier versions of timeout.rb, see
# Timeout#timeout.

def timeout(n, e=Timeout::Error, &block) # :nodoc:
Timeout.timeout(n, e, &block)
end

##
# Another name for Timeout::Error, defined for backwards compatibility with
# earlier versions of timeout.rb.

TimeoutError = Timeout::Error # :nodoc:

if __FILE__ == $0
p timeout(5) {
45
}
p timeout(5, TimeoutError) {
45
}
p timeout(nil) {
54
}
p timeout(0) {
54
}
p timeout(5) {
loop {
p 10
sleep 1
}
}
end

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module RubySL
module Timeout
VERSION = "2.0.0"
end
end
1 change: 1 addition & 0 deletions lib/ruby/truffle/rubysl/rubysl-timeout/lib/timeout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require "rubysl/timeout"
25 changes: 25 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright (c) 2013, Brian Shirai
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the library nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2 changes: 2 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/rubysl/webrick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require "rubysl/webrick/webrick"
require "rubysl/webrick/version"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module RubySL
module WEBrick
VERSION = "2.0.0"
end
end
226 changes: 226 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/rubysl/webrick/webrick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
##
# = WEB server toolkit.
#
# WEBrick is an HTTP server toolkit that can be configured as an HTTPS server,
# a proxy server, and a virtual-host server. WEBrick features complete
# logging of both server operations and HTTP access. WEBrick supports both
# basic and digest authentication in addition to algorithms not in RFC 2617.
#
# A WEBrick server can be composed of multiple WEBrick servers or servlets to
# provide differing behavior on a per-host or per-path basis. WEBrick
# includes servlets for handling CGI scripts, ERb pages, ruby blocks and
# directory listings.
#
# WEBrick also includes tools for daemonizing a process and starting a process
# at a higher privilege level and dropping permissions.
#
# == Starting an HTTP server
#
# To create a new WEBrick::HTTPServer that will listen to connections on port
# 8000 and serve documents from the current user's public_html folder:
#
# require 'webrick'
#
# root = File.expand_path '~/public_html'
# server = WEBrick::HTTPServer.new :Port => 8000, :DocumentRoot => root
#
# To run the server you will need to provide a suitable shutdown hook as
# starting the server blocks the current thread:
#
# trap 'INT' do server.shutdown end
#
# server.start
#
# == Custom Behavior
#
# The easiest way to have a server perform custom operations is through
# WEBrick::HTTPServer#mount_proc. The block given will be called with a
# WEBrick::HTTPRequest with request info and a WEBrick::HTTPResponse which
# must be filled in appropriately:
#
# server.mount_proc '/' do |req, res|
# res.body = 'Hello, world!'
# end
#
# Remember that <tt>server.mount_proc</tt> must <tt>server.start</tt>.
#
# == Servlets
#
# Advanced custom behavior can be obtained through mounting a subclass of
# WEBrick::HTTPServlet::AbstractServlet. Servlets provide more modularity
# when writing an HTTP server than mount_proc allows. Here is a simple
# servlet:
#
# class Simple < WEBrick::HTTPServlet::AbstractServlet
# def do_GET request, response
# status, content_type, body = do_stuff_with request
#
# response.status = 200
# response['Content-Type'] = 'text/plain'
# response.body = 'Hello, World!'
# end
# end
#
# To initialize the servlet you mount it on the server:
#
# server.mount '/simple', Simple
#
# See WEBrick::HTTPServlet::AbstractServlet for more details.
#
# == Virtual Hosts
#
# A server can act as a virtual host for multiple host names. After creating
# the listening host, additional hosts that do not listen can be created and
# attached as virtual hosts:
#
# server = WEBrick::HTTPServer.new # ...
#
# vhost = WEBrick::HTTPServer.new :ServerName => 'vhost.example',
# :DoNotListen => true, # ...
# vhost.mount '/', ...
#
# server.virtual_host vhost
#
# If no +:DocumentRoot+ is provided and no servlets or procs are mounted on the
# main server it will return 404 for all URLs.
#
# == HTTPS
#
# To create an HTTPS server you only need to enable SSL and provide an SSL
# certificate name:
#
# require 'webrick'
# require 'webrick/https'
#
# cert_name = [
# %w[CN localhost],
# ]
#
# server = WEBrick::HTTPServer.new(:Port => 8000,
# :SSLEnable => true,
# :SSLCertName => cert_name)
#
# This will start the server with a self-generated self-signed certificate.
# The certificate will be changed every time the server is restarted.
#
# To create a server with a pre-determined key and certificate you can provide
# them:
#
# require 'webrick'
# require 'webrick/https'
# require 'openssl'
#
# cert = OpenSSL::X509::Certificate.new File.read '/path/to/cert.pem'
# pkey = OpenSSL::PKey::RSA.new File.read '/path/to/pkey.pem'
#
# server = WEBrick::HTTPServer.new(:Port => 8000,
# :SSLEnable => true,
# :SSLCertificate => cert,
# :SSLPrivateKey => pkey)
#
# == Proxy Server
#
# WEBrick can act as a proxy server:
#
# require 'webrick'
# require 'webrick/httpproxy'
#
# proxy = WEBrick::HTTPProxyServer.new :Port => 8000
#
# trap 'INT' do proxy.shutdown end
#
# See WEBrick::HTTPProxy for further details including modifying proxied
# responses.
#
# == Basic and Digest authentication
#
# WEBrick provides both Basic and Digest authentication for regular and proxy
# servers. See WEBrick::HTTPAuth, WEBrick::HTTPAuth::BasicAuth and
# WEBrick::HTTPAuth::DigestAuth.
#
# == WEBrick as a Production Web Server
#
# WEBrick can be run as a production server for small loads.
#
# === Daemonizing
#
# To start a WEBrick server as a daemon simple run WEBrick::Daemon.start
# before starting the server.
#
# === Dropping Permissions
#
# WEBrick can be started as one user to gain permission to bind to port 80 or
# 443 for serving HTTP or HTTPS traffic then can drop these permissions for
# regular operation. To listen on all interfaces for HTTP traffic:
#
# sockets = WEBrick::Utils.create_listeners nil, 80
#
# Then drop privileges:
#
# WEBrick::Utils.su 'www'
#
# Then create a server that does not listen by default:
#
# server = WEBrick::HTTPServer.new :DoNotListen => true, # ...
#
# Then overwrite the listening sockets with the port 80 sockets:
#
# server.listeners.replace sockets
#
# === Logging
#
# WEBrick can separately log server operations and end-user access. For
# server operations:
#
# log_file = File.open '/var/log/webrick.log', 'a+'
# log = WEBrick::Log.new log_file
#
# For user access logging:
#
# access_log = [
# [log_file, WEBrick::AccessLog::COMBINED_LOG_FORMAT],
# ]
#
# server = WEBrick::HTTPServer.new :Logger => log, :AccessLog => access_log
#
# See WEBrick::AccessLog for further log formats.
#
# === Log Rotation
#
# To rotate logs in WEBrick on a HUP signal (like syslogd can send), open the
# log file in 'a+' mode (as above) and trap 'HUP' to reopen the log file:
#
# trap 'HUP' do log_file.reopen '/path/to/webrick.log', 'a+'
#
# == Copyright
#
# Author: IPR -- Internet Programming with Ruby -- writers
#
# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#--
# $IPR: webrick.rb,v 1.12 2002/10/01 17:16:31 gotoyuzo Exp $

module WEBrick
end

require 'webrick/compat.rb'

require 'webrick/version.rb'
require 'webrick/config.rb'
require 'webrick/log.rb'
require 'webrick/server.rb'
require 'webrick/utils.rb'
require 'webrick/accesslog'

require 'webrick/htmlutils.rb'
require 'webrick/httputils.rb'
require 'webrick/cookie.rb'
require 'webrick/httpversion.rb'
require 'webrick/httpstatus.rb'
require 'webrick/httprequest.rb'
require 'webrick/httpresponse.rb'
require 'webrick/httpserver.rb'
require 'webrick/httpservlet.rb'
require 'webrick/httpauth.rb'
1 change: 1 addition & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require "rubysl/webrick"
158 changes: 158 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/accesslog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#--
# accesslog.rb -- Access log handling utilities
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2002 keita yamaguchi
# Copyright (c) 2002 Internet Programming with Ruby writers
#
# $IPR: accesslog.rb,v 1.1 2002/10/01 17:16:32 gotoyuzo Exp $

module WEBrick

##
# AccessLog provides logging to various files in various formats.
#
# Multiple logs may be written to at the same time:
#
# access_log = [
# [$stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT],
# [$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT],
# ]
#
# server = WEBrick::HTTPServer.new :AccessLog => access_log
#
# Custom log formats may be defined. WEBrick::AccessLog provides a subset
# of the formatting from Apache's mod_log_config
# http://httpd.apache.org/docs/mod/mod_log_config.html#formats. See
# AccessLog::setup_params for a list of supported options

module AccessLog

##
# Raised if a parameter such as %e, %i, %o or %n is used without fetching
# a specific field.

class AccessLogError < StandardError; end

##
# The Common Log Format's time format

CLF_TIME_FORMAT = "[%d/%b/%Y:%H:%M:%S %Z]"

##
# Common Log Format

COMMON_LOG_FORMAT = "%h %l %u %t \"%r\" %s %b"

##
# Short alias for Common Log Format

CLF = COMMON_LOG_FORMAT

##
# Referer Log Format

REFERER_LOG_FORMAT = "%{Referer}i -> %U"

##
# User-Agent Log Format

AGENT_LOG_FORMAT = "%{User-Agent}i"

##
# Combined Log Format

COMBINED_LOG_FORMAT = "#{CLF} \"%{Referer}i\" \"%{User-agent}i\""

module_function

# This format specification is a subset of mod_log_config of Apache:
#
# %a:: Remote IP address
# %b:: Total response size
# %e{variable}:: Given variable in ENV
# %f:: Response filename
# %h:: Remote host name
# %{header}i:: Given request header
# %l:: Remote logname, always "-"
# %m:: Request method
# %{attr}n:: Given request attribute from <tt>req.attributes</tt>
# %{header}o:: Given response header
# %p:: Server's request port
# %{format}p:: The canonical port of the server serving the request or the
# actual port or the client's actual port. Valid formats are
# canonical, local or remote.
# %q:: Request query string
# %r:: First line of the request
# %s:: Request status
# %t:: Time the request was recieved
# %T:: Time taken to process the request
# %u:: Remote user from auth
# %U:: Unparsed URI
# %%:: Literal %

def setup_params(config, req, res)
params = Hash.new("")
params["a"] = req.peeraddr[3]
params["b"] = res.sent_size
params["e"] = ENV
params["f"] = res.filename || ""
params["h"] = req.peeraddr[2]
params["i"] = req
params["l"] = "-"
params["m"] = req.request_method
params["n"] = req.attributes
params["o"] = res
params["p"] = req.port
params["q"] = req.query_string
params["r"] = req.request_line.sub(/\x0d?\x0a\z/o, '')
params["s"] = res.status # won't support "%>s"
params["t"] = req.request_time
params["T"] = Time.now - req.request_time
params["u"] = req.user || "-"
params["U"] = req.unparsed_uri
params["v"] = config[:ServerName]
params
end

##
# Formats +params+ according to +format_string+ which is described in
# setup_params.

def format(format_string, params)
format_string.gsub(/\%(?:\{(.*?)\})?>?([a-zA-Z%])/){
param, spec = $1, $2
case spec[0]
when ?e, ?i, ?n, ?o
raise AccessLogError,
"parameter is required for \"#{spec}\"" unless param
(param = params[spec][param]) ? escape(param) : "-"
when ?t
params[spec].strftime(param || CLF_TIME_FORMAT)
when ?p
case param
when 'remote'
escape(params["i"].peeraddr[1].to_s)
else
escape(params["p"].to_s)
end
when ?%
"%"
else
escape(params[spec].to_s)
end
}
end

##
# Escapes control characters in +data+

def escape(data)
if data.tainted?
data.gsub(/[[:cntrl:]\\]+/) {$&.dump[1...-1]}.untaint
else
data
end
end
end
end
308 changes: 308 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/cgi.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
#
# cgi.rb -- Yet another CGI library
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $Id$

require "webrick/httprequest"
require "webrick/httpresponse"
require "webrick/config"
require "stringio"

module WEBrick

# A CGI library using WEBrick requests and responses.
#
# Example:
#
# class MyCGI < WEBrick::CGI
# def do_GET req, res
# res.body = 'it worked!'
# res.status = 200
# end
# end
#
# MyCGI.new.start

class CGI

# The CGI error exception class

CGIError = Class.new(StandardError)

##
# The CGI configuration. This is based on WEBrick::Config::HTTP

attr_reader :config

##
# The CGI logger

attr_reader :logger

##
# Creates a new CGI interface.
#
# The first argument in +args+ is a configuration hash which would update
# WEBrick::Config::HTTP.
#
# Any remaining arguments are stored in the <code>@options</code> instance
# variable for use by a subclass.

def initialize(*args)
if defined?(MOD_RUBY)
unless ENV.has_key?("GATEWAY_INTERFACE")
Apache.request.setup_cgi_env
end
end
if %r{HTTP/(\d+\.\d+)} =~ ENV["SERVER_PROTOCOL"]
httpv = $1
end
@config = WEBrick::Config::HTTP.dup.update(
:ServerSoftware => ENV["SERVER_SOFTWARE"] || "null",
:HTTPVersion => HTTPVersion.new(httpv || "1.0"),
:RunOnCGI => true, # to detect if it runs on CGI.
:NPH => false # set true to run as NPH script.
)
if config = args.shift
@config.update(config)
end
@config[:Logger] ||= WEBrick::BasicLog.new($stderr)
@logger = @config[:Logger]
@options = args
end

##
# Reads +key+ from the configuration

def [](key)
@config[key]
end

##
# Starts the CGI process with the given environment +env+ and standard
# input and output +stdin+ and +stdout+.

def start(env=ENV, stdin=$stdin, stdout=$stdout)
sock = WEBrick::CGI::Socket.new(@config, env, stdin, stdout)
req = HTTPRequest.new(@config)
res = HTTPResponse.new(@config)
unless @config[:NPH] or defined?(MOD_RUBY)
def res.setup_header
unless @header["status"]
phrase = HTTPStatus::reason_phrase(@status)
@header["status"] = "#{@status} #{phrase}"
end
super
end
def res.status_line
""
end
end

begin
req.parse(sock)
req.script_name = (env["SCRIPT_NAME"] || File.expand_path($0)).dup
req.path_info = (env["PATH_INFO"] || "").dup
req.query_string = env["QUERY_STRING"]
req.user = env["REMOTE_USER"]
res.request_method = req.request_method
res.request_uri = req.request_uri
res.request_http_version = req.http_version
res.keep_alive = req.keep_alive?
self.service(req, res)
rescue HTTPStatus::Error => ex
res.set_error(ex)
rescue HTTPStatus::Status => ex
res.status = ex.code
rescue Exception => ex
@logger.error(ex)
res.set_error(ex, true)
ensure
req.fixup
if defined?(MOD_RUBY)
res.setup_header
Apache.request.status_line = "#{res.status} #{res.reason_phrase}"
Apache.request.status = res.status
table = Apache.request.headers_out
res.header.each{|key, val|
case key
when /^content-encoding$/i
Apache::request.content_encoding = val
when /^content-type$/i
Apache::request.content_type = val
else
table[key] = val.to_s
end
}
res.cookies.each{|cookie|
table.add("Set-Cookie", cookie.to_s)
}
Apache.request.send_http_header
res.send_body(sock)
else
res.send_response(sock)
end
end
end

##
# Services the request +req+ which will fill in the response +res+. See
# WEBrick::HTTPServlet::AbstractServlet#service for details.

def service(req, res)
method_name = "do_" + req.request_method.gsub(/-/, "_")
if respond_to?(method_name)
__send__(method_name, req, res)
else
raise HTTPStatus::MethodNotAllowed,
"unsupported method `#{req.request_method}'."
end
end

##
# Provides HTTP socket emulation from the CGI environment

class Socket # :nodoc:
include Enumerable

private

def initialize(config, env, stdin, stdout)
@config = config
@env = env
@header_part = StringIO.new
@body_part = stdin
@out_port = stdout
@out_port.binmode

@server_addr = @env["SERVER_ADDR"] || "0.0.0.0"
@server_name = @env["SERVER_NAME"]
@server_port = @env["SERVER_PORT"]
@remote_addr = @env["REMOTE_ADDR"]
@remote_host = @env["REMOTE_HOST"] || @remote_addr
@remote_port = @env["REMOTE_PORT"] || 0

begin
@header_part << request_line << CRLF
setup_header
@header_part << CRLF
@header_part.rewind
rescue Exception
raise CGIError, "invalid CGI environment"
end
end

def request_line
meth = @env["REQUEST_METHOD"] || "GET"
unless url = @env["REQUEST_URI"]
url = (@env["SCRIPT_NAME"] || File.expand_path($0)).dup
url << @env["PATH_INFO"].to_s
url = WEBrick::HTTPUtils.escape_path(url)
if query_string = @env["QUERY_STRING"]
unless query_string.empty?
url << "?" << query_string
end
end
end
# we cannot get real HTTP version of client ;)
httpv = @config[:HTTPVersion]
return "#{meth} #{url} HTTP/#{httpv}"
end

def setup_header
@env.each{|key, value|
case key
when "CONTENT_TYPE", "CONTENT_LENGTH"
add_header(key.gsub(/_/, "-"), value)
when /^HTTP_(.*)/
add_header($1.gsub(/_/, "-"), value)
end
}
end

def add_header(hdrname, value)
unless value.empty?
@header_part << hdrname << ": " << value << CRLF
end
end

def input
@header_part.eof? ? @body_part : @header_part
end

public

def peeraddr
[nil, @remote_port, @remote_host, @remote_addr]
end

def addr
[nil, @server_port, @server_name, @server_addr]
end

def gets(eol=LF, size=nil)
input.gets(eol, size)
end

def read(size=nil)
input.read(size)
end

def each
input.each{|line| yield(line) }
end

def eof?
input.eof?
end

def <<(data)
@out_port << data
end

def cert
return nil unless defined?(OpenSSL)
if pem = @env["SSL_SERVER_CERT"]
OpenSSL::X509::Certificate.new(pem) unless pem.empty?
end
end

def peer_cert
return nil unless defined?(OpenSSL)
if pem = @env["SSL_CLIENT_CERT"]
OpenSSL::X509::Certificate.new(pem) unless pem.empty?
end
end

def peer_cert_chain
return nil unless defined?(OpenSSL)
if @env["SSL_CLIENT_CERT_CHAIN_0"]
keys = @env.keys
certs = keys.sort.collect{|k|
if /^SSL_CLIENT_CERT_CHAIN_\d+$/ =~ k
if pem = @env[k]
OpenSSL::X509::Certificate.new(pem) unless pem.empty?
end
end
}
certs.compact
end
end

def cipher
return nil unless defined?(OpenSSL)
if cipher = @env["SSL_CIPHER"]
ret = [ cipher ]
ret << @env["SSL_PROTOCOL"]
ret << @env["SSL_CIPHER_USEKEYSIZE"]
ret << @env["SSL_CIPHER_ALGKEYSIZE"]
ret
end
end
end
end
end
35 changes: 35 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/compat.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#
# compat.rb -- cross platform compatibility
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2002 GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: compat.rb,v 1.6 2002/10/01 17:16:32 gotoyuzo Exp $

##
# System call error module used by webrick for cross platform compatability.
#
# EPROTO:: protocol error
# ECONNRESET:: remote host reset the connection request
# ECONNABORTED:: Client sent TCP reset (RST) before server has accepted the
# connection requested by client.
#
module Errno
##
# Protocol error.

class EPROTO < SystemCallError; end

##
# Remote host reset the connection request.

class ECONNRESET < SystemCallError; end

##
# Client sent TCP reset (RST) before server has accepted the connection
# requested by client.

class ECONNABORTED < SystemCallError; end
end
151 changes: 151 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#
# config.rb -- Default configurations.
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: config.rb,v 1.52 2003/07/22 19:20:42 gotoyuzo Exp $

require 'webrick/version'
require 'webrick/httpversion'
require 'webrick/httputils'
require 'webrick/utils'
require 'webrick/log'

module WEBrick
module Config
LIBDIR = File::dirname(__FILE__) # :nodoc:

# for GenericServer
General = {
:ServerName => Utils::getservername,
:BindAddress => nil, # "0.0.0.0" or "::" or nil
:Port => nil, # users MUST specify this!!
:MaxClients => 100, # maximum number of the concurrent connections
:ServerType => nil, # default: WEBrick::SimpleServer
:Logger => nil, # default: WEBrick::Log.new
:ServerSoftware => "WEBrick/#{WEBrick::VERSION} " +
"(Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})",
:TempDir => ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp',
:DoNotListen => false,
:StartCallback => nil,
:StopCallback => nil,
:AcceptCallback => nil,
:DoNotReverseLookup => nil,
:ShutdownSocketWithoutClose => false,
}

# for HTTPServer, HTTPRequest, HTTPResponse ...
HTTP = General.dup.update(
:Port => 80,
:RequestTimeout => 30,
:HTTPVersion => HTTPVersion.new("1.1"),
:AccessLog => nil,
:MimeTypes => HTTPUtils::DefaultMimeTypes,
:DirectoryIndex => ["index.html","index.htm","index.cgi","index.rhtml"],
:DocumentRoot => nil,
:DocumentRootOptions => { :FancyIndexing => true },
:RequestCallback => nil,
:ServerAlias => nil,
:InputBufferSize => 65536, # input buffer size in reading request body
:OutputBufferSize => 65536, # output buffer size in sending File or IO

# for HTTPProxyServer
:ProxyAuthProc => nil,
:ProxyContentHandler => nil,
:ProxyVia => true,
:ProxyTimeout => true,
:ProxyURI => nil,

:CGIInterpreter => nil,
:CGIPathEnv => nil,

# workaround: if Request-URIs contain 8bit chars,
# they should be escaped before calling of URI::parse().
:Escape8bitURI => false
)

##
# Default configuration for WEBrick::HTTPServlet::FileHandler
#
# :AcceptableLanguages::
# Array of languages allowed for accept-language. There is no default
# :DirectoryCallback::
# Allows preprocessing of directory requests. There is no default
# callback.
# :FancyIndexing::
# If true, show an index for directories. The default is true.
# :FileCallback::
# Allows preprocessing of file requests. There is no default callback.
# :HandlerCallback::
# Allows preprocessing of requests. There is no default callback.
# :HandlerTable::
# Maps file suffixes to file handlers. DefaultFileHandler is used by
# default but any servlet can be used.
# :NondisclosureName::
# Do not show files matching this array of globs. .ht* and *~ are
# excluded by default.
# :UserDir::
# Directory inside ~user to serve content from for /~user requests.
# Only works if mounted on /. Disabled by default.

FileHandler = {
:NondisclosureName => [".ht*", "*~"],
:FancyIndexing => false,
:HandlerTable => {},
:HandlerCallback => nil,
:DirectoryCallback => nil,
:FileCallback => nil,
:UserDir => nil, # e.g. "public_html"
:AcceptableLanguages => [] # ["en", "ja", ... ]
}

##
# Default configuration for WEBrick::HTTPAuth::BasicAuth
#
# :AutoReloadUserDB:: Reload the user database provided by :UserDB
# automatically?

BasicAuth = {
:AutoReloadUserDB => true,
}

##
# Default configuration for WEBrick::HTTPAuth::DigestAuth.
#
# :Algorithm:: MD5, MD5-sess (default), SHA1, SHA1-sess
# :Domain:: An Array of URIs that define the protected space
# :Qop:: 'auth' for authentication, 'auth-int' for integrity protection or
# both
# :UseOpaque:: Should the server send opaque values to the client? This
# helps prevent replay attacks.
# :CheckNc:: Should the server check the nonce count? This helps the
# server detect replay attacks.
# :UseAuthenticationInfoHeader:: Should the server send an
# AuthenticationInfo header?
# :AutoReloadUserDB:: Reload the user database provided by :UserDB
# automatically?
# :NonceExpirePeriod:: How long should we store used nonces? Default is
# 30 minutes.
# :NonceExpireDelta:: How long is a nonce valid? Default is 1 minute
# :InternetExplorerHack:: Hack which allows Internet Explorer to work.
# :OperaHack:: Hack which allows Opera to work.

DigestAuth = {
:Algorithm => 'MD5-sess', # or 'MD5'
:Domain => nil, # an array includes domain names.
:Qop => [ 'auth' ], # 'auth' or 'auth-int' or both.
:UseOpaque => true,
:UseNextNonce => false,
:CheckNc => false,
:UseAuthenticationInfoHeader => true,
:AutoReloadUserDB => true,
:NonceExpirePeriod => 30*60,
:NonceExpireDelta => 60,
:InternetExplorerHack => true,
:OperaHack => true,
}
end
end
171 changes: 171 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/cookie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#
# cookie.rb -- Cookie class
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: cookie.rb,v 1.16 2002/09/21 12:23:35 gotoyuzo Exp $

require 'time'
require 'webrick/httputils'

module WEBrick

##
# Processes HTTP cookies

class Cookie

##
# The cookie name

attr_reader :name

##
# The cookie value

attr_accessor :value

##
# The cookie version

attr_accessor :version

##
# The cookie domain
attr_accessor :domain

##
# The cookie path

attr_accessor :path

##
# Is this a secure cookie?

attr_accessor :secure

##
# The cookie comment

attr_accessor :comment

##
# The maximum age of the cookie

attr_accessor :max_age

#attr_accessor :comment_url, :discard, :port

##
# Creates a new cookie with the given +name+ and +value+

def initialize(name, value)
@name = name
@value = value
@version = 0 # Netscape Cookie

@domain = @path = @secure = @comment = @max_age =
@expires = @comment_url = @discard = @port = nil
end

##
# Sets the cookie expiration to the time +t+. The expiration time may be
# a false value to disable expiration or a Time or HTTP format time string
# to set the expiration date.

def expires=(t)
@expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
end

##
# Retrieves the expiration time as a Time

def expires
@expires && Time.parse(@expires)
end

##
# The cookie string suitable for use in an HTTP header

def to_s
ret = ""
ret << @name << "=" << @value
ret << "; " << "Version=" << @version.to_s if @version > 0
ret << "; " << "Domain=" << @domain if @domain
ret << "; " << "Expires=" << @expires if @expires
ret << "; " << "Max-Age=" << @max_age.to_s if @max_age
ret << "; " << "Comment=" << @comment if @comment
ret << "; " << "Path=" << @path if @path
ret << "; " << "Secure" if @secure
ret
end

##
# Parses a Cookie field sent from the user-agent. Returns an array of
# cookies.

def self.parse(str)
if str
ret = []
cookie = nil
ver = 0
str.split(/[;,]\s+/).each{|x|
key, val = x.split(/=/,2)
val = val ? HTTPUtils::dequote(val) : ""
case key
when "$Version"; ver = val.to_i
when "$Path"; cookie.path = val
when "$Domain"; cookie.domain = val
when "$Port"; cookie.port = val
else
ret << cookie if cookie
cookie = self.new(key, val)
cookie.version = ver
end
}
ret << cookie if cookie
ret
end
end

##
# Parses the cookie in +str+

def self.parse_set_cookie(str)
cookie_elem = str.split(/;/)
first_elem = cookie_elem.shift
first_elem.strip!
key, value = first_elem.split(/=/, 2)
cookie = new(key, HTTPUtils.dequote(value))
cookie_elem.each{|pair|
pair.strip!
key, value = pair.split(/=/, 2)
if value
value = HTTPUtils.dequote(value.strip)
end
case key.downcase
when "domain" then cookie.domain = value
when "path" then cookie.path = value
when "expires" then cookie.expires = value
when "max-age" then cookie.max_age = Integer(value)
when "comment" then cookie.comment = value
when "version" then cookie.version = Integer(value)
when "secure" then cookie.secure = true
end
}
return cookie
end

##
# Parses the cookies in +str+

def self.parse_set_cookies(str)
return str.split(/,(?=[^;,]*=)|,$/).collect{|c|
parse_set_cookie(c)
}
end
end
end
28 changes: 28 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/htmlutils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#--
# htmlutils.rb -- HTMLUtils Module
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: htmlutils.rb,v 1.7 2002/09/21 12:23:35 gotoyuzo Exp $

module WEBrick
module HTMLUtils

##
# Escapes &, ", > and < in +string+

def escape(string)
str = string ? string.dup : ""
str.gsub!(/&/n, '&amp;')
str.gsub!(/\"/n, '&quot;')
str.gsub!(/>/n, '&gt;')
str.gsub!(/</n, '&lt;')
str
end
module_function :escape

end
end
95 changes: 95 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/httpauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#
# httpauth.rb -- HTTP access authentication
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: httpauth.rb,v 1.14 2003/07/22 19:20:42 gotoyuzo Exp $

require 'webrick/httpauth/basicauth'
require 'webrick/httpauth/digestauth'
require 'webrick/httpauth/htpasswd'
require 'webrick/httpauth/htdigest'
require 'webrick/httpauth/htgroup'

module WEBrick

##
# HTTPAuth provides both basic and digest authentication.
#
# To enable authentication for requests in WEBrick you will need a user
# database and an authenticator. To start, here's an Htpasswd database for
# use with a DigestAuth authenticator:
#
# config = { :Realm => 'DigestAuth example realm' }
#
# htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file'
# htpasswd.auth_type = WEBrick::HTTPAuth::DigestAuth
# htpasswd.set_passwd config[:Realm], 'username', 'password'
# htpasswd.flush
#
# The +:Realm+ is used to provide different access to different groups
# across several resources on a server. Typically you'll need only one
# realm for a server.
#
# This database can be used to create an authenticator:
#
# config[:UserDB] = htpasswd
#
# digest_auth = WEBrick::HTTPAuth::DigestAuth.new config
#
# To authenticate a request call #authenticate with a request and response
# object in a servlet:
#
# def do_GET req, res
# @authenticator.authenticate req, res
# end
#
# For digest authentication the authenticator must not be created every
# request, it must be passed in as an option via WEBrick::HTTPServer#mount.

module HTTPAuth
module_function

def _basic_auth(req, res, realm, req_field, res_field, err_type,
block) # :nodoc:
user = pass = nil
if /^Basic\s+(.*)/o =~ req[req_field]
userpass = $1
user, pass = userpass.unpack("m*")[0].split(":", 2)
end
if block.call(user, pass)
req.user = user
return
end
res[res_field] = "Basic realm=\"#{realm}\""
raise err_type
end

##
# Simple wrapper for providing basic authentication for a request. When
# called with a request +req+, response +res+, authentication +realm+ and
# +block+ the block will be called with a +username+ and +password+. If
# the block returns true the request is allowed to continue, otherwise an
# HTTPStatus::Unauthorized error is raised.

def basic_auth(req, res, realm, &block) # :yield: username, password
_basic_auth(req, res, realm, "Authorization", "WWW-Authenticate",
HTTPStatus::Unauthorized, block)
end

##
# Simple wrapper for providing basic authentication for a proxied request.
# When called with a request +req+, response +res+, authentication +realm+
# and +block+ the block will be called with a +username+ and +password+.
# If the block returns true the request is allowed to continue, otherwise
# an HTTPStatus::ProxyAuthenticationRequired error is raised.

def proxy_basic_auth(req, res, realm, &block) # :yield: username, password
_basic_auth(req, res, realm, "Proxy-Authorization", "Proxy-Authenticate",
HTTPStatus::ProxyAuthenticationRequired, block)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#--
# httpauth/authenticator.rb -- Authenticator mix-in module.
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: authenticator.rb,v 1.3 2003/02/20 07:15:47 gotoyuzo Exp $

module WEBrick
module HTTPAuth

##
# Module providing generic support for both Digest and Basic
# authentication schemes.

module Authenticator

RequestField = "Authorization" # :nodoc:
ResponseField = "WWW-Authenticate" # :nodoc:
ResponseInfoField = "Authentication-Info" # :nodoc:
AuthException = HTTPStatus::Unauthorized # :nodoc:

##
# Method of authentication, must be overridden by the including class

AuthScheme = nil

##
# The realm this authenticator covers

attr_reader :realm

##
# The user database for this authenticator

attr_reader :userdb

##
# The logger for this authenticator

attr_reader :logger

private

# :stopdoc:

##
# Initializes the authenticator from +config+

def check_init(config)
[:UserDB, :Realm].each{|sym|
unless config[sym]
raise ArgumentError, "Argument #{sym.inspect} missing."
end
}
@realm = config[:Realm]
@userdb = config[:UserDB]
@logger = config[:Logger] || Log::new($stderr)
@reload_db = config[:AutoReloadUserDB]
@request_field = self::class::RequestField
@response_field = self::class::ResponseField
@resp_info_field = self::class::ResponseInfoField
@auth_exception = self::class::AuthException
@auth_scheme = self::class::AuthScheme
end

##
# Ensures +req+ has credentials that can be authenticated.

def check_scheme(req)
unless credentials = req[@request_field]
error("no credentials in the request.")
return nil
end
unless match = /^#{@auth_scheme}\s+/i.match(credentials)
error("invalid scheme in %s.", credentials)
info("%s: %s", @request_field, credentials) if $DEBUG
return nil
end
return match.post_match
end

def log(meth, fmt, *args)
msg = format("%s %s: ", @auth_scheme, @realm)
msg << fmt % args
@logger.send(meth, msg)
end

def error(fmt, *args)
if @logger.error?
log(:error, fmt, *args)
end
end

def info(fmt, *args)
if @logger.info?
log(:info, fmt, *args)
end
end

# :startdoc:
end

##
# Module providing generic support for both Digest and Basic
# authentication schemes for proxies.

module ProxyAuthenticator
RequestField = "Proxy-Authorization" # :nodoc:
ResponseField = "Proxy-Authenticate" # :nodoc:
InfoField = "Proxy-Authentication-Info" # :nodoc:
AuthException = HTTPStatus::ProxyAuthenticationRequired # :nodoc:
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#
# httpauth/basicauth.rb -- HTTP basic access authentication
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: basicauth.rb,v 1.5 2003/02/20 07:15:47 gotoyuzo Exp $

require 'webrick/config'
require 'webrick/httpstatus'
require 'webrick/httpauth/authenticator'

module WEBrick
module HTTPAuth

##
# Basic Authentication for WEBrick
#
# Use this class to add basic authentication to a WEBrick servlet.
#
# Here is an example of how to set up a BasicAuth:
#
# config = { :Realm => 'BasicAuth example realm' }
#
# htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file'
# htpasswd.set_passwd config[:Realm], 'username', 'password'
# htpasswd.flush
#
# config[:UserDB] = htpasswd
#
# basic_auth = WEBrick::HTTPAuth::BasicAuth.new config

class BasicAuth
include Authenticator

AuthScheme = "Basic" # :nodoc:

##
# Used by UserDB to create a basic password entry

def self.make_passwd(realm, user, pass)
pass ||= ""
pass.crypt(Utils::random_string(2))
end

attr_reader :realm, :userdb, :logger

##
# Creates a new BasicAuth instance.
#
# See WEBrick::Config::BasicAuth for default configuration entries
#
# You must supply the following configuration entries:
#
# :Realm:: The name of the realm being protected.
# :UserDB:: A database of usernames and passwords.
# A WEBrick::HTTPAuth::Htpasswd instance should be used.

def initialize(config, default=Config::BasicAuth)
check_init(config)
@config = default.dup.update(config)
end

##
# Authenticates a +req+ and returns a 401 Unauthorized using +res+ if
# the authentication was not correct.

def authenticate(req, res)
unless basic_credentials = check_scheme(req)
challenge(req, res)
end
userid, password = basic_credentials.unpack("m*")[0].split(":", 2)
password ||= ""
if userid.empty?
error("user id was not given.")
challenge(req, res)
end
unless encpass = @userdb.get_passwd(@realm, userid, @reload_db)
error("%s: the user is not allowed.", userid)
challenge(req, res)
end
if password.crypt(encpass) != encpass
error("%s: password unmatch.", userid)
challenge(req, res)
end
info("%s: authentication succeeded.", userid)
req.user = userid
end

##
# Returns a challenge response which asks for for authentication
# information

def challenge(req, res)
res[@response_field] = "#{@auth_scheme} realm=\"#{@realm}\""
raise @auth_exception
end
end

##
# Basic authentication for proxy servers. See BasicAuth for details.

class ProxyBasicAuth < BasicAuth
include ProxyAuthenticator
end
end
end

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#
# httpauth/htdigest.rb -- Apache compatible htdigest file
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: htdigest.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $

require 'webrick/httpauth/userdb'
require 'webrick/httpauth/digestauth'
require 'tempfile'

module WEBrick
module HTTPAuth

##
# Htdigest accesses apache-compatible digest password files. Passwords are
# matched to a realm where they are valid. For security, the path for a
# digest password database should be stored outside of the paths available
# to the HTTP server.
#
# Htdigest is intended for use with WEBrick::HTTPAuth::DigestAuth and
# stores passwords using cryptographic hashes.
#
# htpasswd = WEBrick::HTTPAuth::Htdigest.new 'my_password_file'
# htpasswd.set_passwd 'my realm', 'username', 'password'
# htpasswd.flush

class Htdigest
include UserDB

##
# Open a digest password database at +path+

def initialize(path)
@path = path
@mtime = Time.at(0)
@digest = Hash.new
@mutex = Mutex::new
@auth_type = DigestAuth
open(@path,"a").close unless File::exist?(@path)
reload
end

##
# Reloads passwords from the database

def reload
mtime = File::mtime(@path)
if mtime > @mtime
@digest.clear
open(@path){|io|
while line = io.gets
line.chomp!
user, realm, pass = line.split(/:/, 3)
unless @digest[realm]
@digest[realm] = Hash.new
end
@digest[realm][user] = pass
end
}
@mtime = mtime
end
end

##
# Flush the password database. If +output+ is given the database will
# be written there instead of to the original path.

def flush(output=nil)
output ||= @path
tmp = Tempfile.new("htpasswd", File::dirname(output))
begin
each{|item| tmp.puts(item.join(":")) }
tmp.close
File::rename(tmp.path, output)
rescue
tmp.close(true)
end
end

##
# Retrieves a password from the database for +user+ in +realm+. If
# +reload_db+ is true the database will be reloaded first.

def get_passwd(realm, user, reload_db)
reload() if reload_db
if hash = @digest[realm]
hash[user]
end
end

##
# Sets a password in the database for +user+ in +realm+ to +pass+.

def set_passwd(realm, user, pass)
@mutex.synchronize{
unless @digest[realm]
@digest[realm] = Hash.new
end
@digest[realm][user] = make_passwd(realm, user, pass)
}
end

##
# Removes a password from the database for +user+ in +realm+.

def delete_passwd(realm, user)
if hash = @digest[realm]
hash.delete(user)
end
end

##
# Iterate passwords in the database.

def each # :yields: [user, realm, password_hash]
@digest.keys.sort.each{|realm|
hash = @digest[realm]
hash.keys.sort.each{|user|
yield([user, realm, hash[user]])
}
}
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#
# httpauth/htgroup.rb -- Apache compatible htgroup file
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: htgroup.rb,v 1.1 2003/02/16 22:22:56 gotoyuzo Exp $

require 'tempfile'

module WEBrick
module HTTPAuth

##
# Htgroup accesses apache-compatible group files. Htgroup can be used to
# provide group-based authentication for users. Currently Htgroup is not
# directly integrated with any authenticators in WEBrick. For security,
# the path for a digest password database should be stored outside of the
# paths available to the HTTP server.
#
# Example:
#
# htgroup = WEBrick::HTTPAuth::Htgroup.new 'my_group_file'
# htgroup.add 'superheroes', %w[spiderman batman]
#
# htgroup.members('superheroes').include? 'magneto' # => false

class Htgroup

##
# Open a group database at +path+

def initialize(path)
@path = path
@mtime = Time.at(0)
@group = Hash.new
open(@path,"a").close unless File::exist?(@path)
reload
end

##
# Reload groups from the database

def reload
if (mtime = File::mtime(@path)) > @mtime
@group.clear
open(@path){|io|
while line = io.gets
line.chomp!
group, members = line.split(/:\s*/)
@group[group] = members.split(/\s+/)
end
}
@mtime = mtime
end
end

##
# Flush the group database. If +output+ is given the database will be
# written there instead of to the original path.

def flush(output=nil)
output ||= @path
tmp = Tempfile.new("htgroup", File::dirname(output))
begin
@group.keys.sort.each{|group|
tmp.puts(format("%s: %s", group, self.members(group).join(" ")))
}
tmp.close
File::rename(tmp.path, output)
rescue
tmp.close(true)
end
end

##
# Retrieve the list of members from +group+

def members(group)
reload
@group[group] || []
end

##
# Add an Array of +members+ to +group+

def add(group, members)
@group[group] = members(group) | members
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#
# httpauth/htpasswd -- Apache compatible htpasswd file
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: htpasswd.rb,v 1.4 2003/07/22 19:20:45 gotoyuzo Exp $

require 'webrick/httpauth/userdb'
require 'webrick/httpauth/basicauth'
require 'tempfile'

module WEBrick
module HTTPAuth

##
# Htpasswd accesses apache-compatible password files. Passwords are
# matched to a realm where they are valid. For security, the path for a
# password database should be stored outside of the paths available to the
# HTTP server.
#
# Htpasswd is intended for use with WEBrick::HTTPAuth::BasicAuth.
#
# To create an Htpasswd database with a single user:
#
# htpasswd = WEBrick::HTTPAuth::Htpasswd.new 'my_password_file'
# htpasswd.set_passwd 'my realm', 'username', 'password'
# htpasswd.flush

class Htpasswd
include UserDB

##
# Open a password database at +path+

def initialize(path)
@path = path
@mtime = Time.at(0)
@passwd = Hash.new
@auth_type = BasicAuth
open(@path,"a").close unless File::exist?(@path)
reload
end

##
# Reload passwords from the database

def reload
mtime = File::mtime(@path)
if mtime > @mtime
@passwd.clear
open(@path){|io|
while line = io.gets
line.chomp!
case line
when %r!\A[^:]+:[a-zA-Z0-9./]{13}\z!
user, pass = line.split(":")
when /:\$/, /:{SHA}/
raise NotImplementedError,
'MD5, SHA1 .htpasswd file not supported'
else
raise StandardError, 'bad .htpasswd file'
end
@passwd[user] = pass
end
}
@mtime = mtime
end
end

##
# Flush the password database. If +output+ is given the database will
# be written there instead of to the original path.

def flush(output=nil)
output ||= @path
tmp = Tempfile.new("htpasswd", File::dirname(output))
begin
each{|item| tmp.puts(item.join(":")) }
tmp.close
File::rename(tmp.path, output)
rescue
tmp.close(true)
end
end

##
# Retrieves a password from the database for +user+ in +realm+. If
# +reload_db+ is true the database will be reloaded first.

def get_passwd(realm, user, reload_db)
reload() if reload_db
@passwd[user]
end

##
# Sets a password in the database for +user+ in +realm+ to +pass+.

def set_passwd(realm, user, pass)
@passwd[user] = make_passwd(realm, user, pass)
end

##
# Removes a password from the database for +user+ in +realm+.

def delete_passwd(realm, user)
@passwd.delete(user)
end

##
# Iterate passwords in the database.

def each # :yields: [user, password]
@passwd.keys.sort.each{|user|
yield([user, @passwd[user]])
}
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#--
# httpauth/userdb.rb -- UserDB mix-in module.
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2003 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: userdb.rb,v 1.2 2003/02/20 07:15:48 gotoyuzo Exp $

module WEBrick
module HTTPAuth

##
# User database mixin for HTTPAuth. This mixin dispatches user record
# access to the underlying auth_type for this database.

module UserDB

##
# The authentication type.
#
# WEBrick::HTTPAuth::BasicAuth or WEBrick::HTTPAuth::DigestAuth are
# built-in.

attr_accessor :auth_type

##
# Creates an obscured password in +realm+ with +user+ and +password+
# using the auth_type of this database.

def make_passwd(realm, user, pass)
@auth_type::make_passwd(realm, user, pass)
end

##
# Sets a password in +realm+ with +user+ and +password+ for the
# auth_type of this database.

def set_passwd(realm, user, pass)
self[user] = pass
end

##
# Retrieves a password in +realm+ for +user+ for the auth_type of this
# database. +reload_db+ is a dummy value.

def get_passwd(realm, user, reload_db=false)
make_passwd(realm, user, self[user])
end
end
end
end
339 changes: 339 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/httpproxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
#
# httpproxy.rb -- HTTPProxy Class
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2002 GOTO Kentaro
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: httpproxy.rb,v 1.18 2003/03/08 18:58:10 gotoyuzo Exp $
# $kNotwork: straw.rb,v 1.3 2002/02/12 15:13:07 gotoken Exp $

require "webrick/httpserver"
require "net/http"

Net::HTTP::version_1_2 if RUBY_VERSION < "1.7"

module WEBrick

NullReader = Object.new # :nodoc:
class << NullReader # :nodoc:
def read(*args)
nil
end
alias gets read
end

FakeProxyURI = Object.new # :nodoc:
class << FakeProxyURI # :nodoc:
def method_missing(meth, *args)
if %w(scheme host port path query userinfo).member?(meth.to_s)
return nil
end
super
end
end

# :startdoc:

##
# An HTTP Proxy server which proxies GET, HEAD and POST requests.
#
# To create a simple proxy server:
#
# require 'webrick'
# require 'webrick/httpproxy'
#
# proxy = WEBrick::HTTPProxyServer.new Port: 8000
#
# trap 'INT' do proxy.shutdown end
# trap 'TERM' do proxy.shutdown end
#
# proxy.start
#
# See ::new for proxy-specific configuration items.
#
# == Modifying proxied responses
#
# To modify content the proxy server returns use the +:ProxyContentHandler+
# option:
#
# handler = proc do |req, res|
# if res['content-type'] == 'text/plain' then
# res.body << "\nThis content was proxied!\n"
# end
# end
#
# proxy =
# WEBrick::HTTPProxyServer.new Port: 8000, ProxyContentHandler: handler

class HTTPProxyServer < HTTPServer

##
# Proxy server configurations. The proxy server handles the following
# configuration items in addition to those supported by HTTPServer:
#
# :ProxyAuthProc:: Called with a request and response to authorize a
# request
# :ProxyVia:: Appended to the via header
# :ProxyURI:: The proxy server's URI
# :ProxyContentHandler:: Called with a request and response and allows
# modification of the response
# :ProxyTimeout:: Sets the proxy timeouts to 30 seconds for open and 60
# seconds for read operations

def initialize(config={}, default=Config::HTTP)
super(config, default)
c = @config
@via = "#{c[:HTTPVersion]} #{c[:ServerName]}:#{c[:Port]}"
end

# :stopdoc:
def service(req, res)
if req.request_method == "CONNECT"
do_CONNECT(req, res)
elsif req.unparsed_uri =~ %r!^http://!
proxy_service(req, res)
else
super(req, res)
end
end

def proxy_auth(req, res)
if proc = @config[:ProxyAuthProc]
proc.call(req, res)
end
req.header.delete("proxy-authorization")
end

def proxy_uri(req, res)
# should return upstream proxy server's URI
return @config[:ProxyURI]
end

def proxy_service(req, res)
# Proxy Authentication
proxy_auth(req, res)

begin
self.send("do_#{req.request_method}", req, res)
rescue NoMethodError
raise HTTPStatus::MethodNotAllowed,
"unsupported method `#{req.request_method}'."
rescue => err
logger.debug("#{err.class}: #{err.message}")
raise HTTPStatus::ServiceUnavailable, err.message
end

# Process contents
if handler = @config[:ProxyContentHandler]
handler.call(req, res)
end
end

def do_CONNECT(req, res)
# Proxy Authentication
proxy_auth(req, res)

ua = Thread.current[:WEBrickSocket] # User-Agent
raise HTTPStatus::InternalServerError,
"[BUG] cannot get socket" unless ua

host, port = req.unparsed_uri.split(":", 2)
# Proxy authentication for upstream proxy server
if proxy = proxy_uri(req, res)
proxy_request_line = "CONNECT #{host}:#{port} HTTP/1.0"
if proxy.userinfo
credentials = "Basic " + [proxy.userinfo].pack("m").delete("\n")
end
host, port = proxy.host, proxy.port
end

begin
@logger.debug("CONNECT: upstream proxy is `#{host}:#{port}'.")
os = TCPSocket.new(host, port) # origin server

if proxy
@logger.debug("CONNECT: sending a Request-Line")
os << proxy_request_line << CRLF
@logger.debug("CONNECT: > #{proxy_request_line}")
if credentials
@logger.debug("CONNECT: sending a credentials")
os << "Proxy-Authorization: " << credentials << CRLF
end
os << CRLF
proxy_status_line = os.gets(LF)
@logger.debug("CONNECT: read a Status-Line form the upstream server")
@logger.debug("CONNECT: < #{proxy_status_line}")
if %r{^HTTP/\d+\.\d+\s+200\s*} =~ proxy_status_line
while line = os.gets(LF)
break if /\A(#{CRLF}|#{LF})\z/om =~ line
end
else
raise HTTPStatus::BadGateway
end
end
@logger.debug("CONNECT #{host}:#{port}: succeeded")
res.status = HTTPStatus::RC_OK
rescue => ex
@logger.debug("CONNECT #{host}:#{port}: failed `#{ex.message}'")
res.set_error(ex)
raise HTTPStatus::EOFError
ensure
if handler = @config[:ProxyContentHandler]
handler.call(req, res)
end
res.send_response(ua)
access_log(@config, req, res)

# Should clear request-line not to send the response twice.
# see: HTTPServer#run
req.parse(NullReader) rescue nil
end

begin
while fds = IO::select([ua, os])
if fds[0].member?(ua)
buf = ua.sysread(1024);
@logger.debug("CONNECT: #{buf.bytesize} byte from User-Agent")
os.syswrite(buf)
elsif fds[0].member?(os)
buf = os.sysread(1024);
@logger.debug("CONNECT: #{buf.bytesize} byte from #{host}:#{port}")
ua.syswrite(buf)
end
end
rescue => ex
os.close
@logger.debug("CONNECT #{host}:#{port}: closed")
end

raise HTTPStatus::EOFError
end

def do_GET(req, res)
perform_proxy_request(req, res) do |http, path, header|
http.get(path, header)
end
end

def do_HEAD(req, res)
perform_proxy_request(req, res) do |http, path, header|
http.head(path, header)
end
end

def do_POST(req, res)
perform_proxy_request(req, res) do |http, path, header|
http.post(path, req.body || "", header)
end
end

def do_OPTIONS(req, res)
res['allow'] = "GET,HEAD,POST,OPTIONS,CONNECT"
end

private

# Some header fields should not be transferred.
HopByHop = %w( connection keep-alive proxy-authenticate upgrade
proxy-authorization te trailers transfer-encoding )
ShouldNotTransfer = %w( set-cookie proxy-connection )
def split_field(f) f ? f.split(/,\s+/).collect{|i| i.downcase } : [] end

def choose_header(src, dst)
connections = split_field(src['connection'])
src.each{|key, value|
key = key.downcase
if HopByHop.member?(key) || # RFC2616: 13.5.1
connections.member?(key) || # RFC2616: 14.10
ShouldNotTransfer.member?(key) # pragmatics
@logger.debug("choose_header: `#{key}: #{value}'")
next
end
dst[key] = value
}
end

# Net::HTTP is stupid about the multiple header fields.
# Here is workaround:
def set_cookie(src, dst)
if str = src['set-cookie']
cookies = []
str.split(/,\s*/).each{|token|
if /^[^=]+;/o =~ token
cookies[-1] << ", " << token
elsif /=/o =~ token
cookies << token
else
cookies[-1] << ", " << token
end
}
dst.cookies.replace(cookies)
end
end

def set_via(h)
if @config[:ProxyVia]
if h['via']
h['via'] << ", " << @via
else
h['via'] = @via
end
end
end

def setup_proxy_header(req, res)
# Choose header fields to transfer
header = Hash.new
choose_header(req, header)
set_via(header)
return header
end

def setup_upstream_proxy_authentication(req, res, header)
if upstream = proxy_uri(req, res)
if upstream.userinfo
header['proxy-authorization'] =
"Basic " + [upstream.userinfo].pack("m").delete("\n")
end
return upstream
end
return FakeProxyURI
end

def perform_proxy_request(req, res)
uri = req.request_uri
path = uri.path.dup
path << "?" << uri.query if uri.query
header = setup_proxy_header(req, res)
upstream = setup_upstream_proxy_authentication(req, res, header)
response = nil

http = Net::HTTP.new(uri.host, uri.port, upstream.host, upstream.port)
http.start do
if @config[:ProxyTimeout]
################################## these issues are
http.open_timeout = 30 # secs # necessary (maybe bacause
http.read_timeout = 60 # secs # Ruby's bug, but why?)
##################################
end
response = yield(http, path, header)
end

# Persistent connection requirements are mysterious for me.
# So I will close the connection in every response.
res['proxy-connection'] = "close"
res['connection'] = "close"

# Convert Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
res.status = response.code.to_i
choose_header(response, res)
set_cookie(response, res)
set_via(res)
res.body = response.body
end

# :stopdoc:
end
end
583 changes: 583 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/httprequest.rb

Large diffs are not rendered by default.

464 changes: 464 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/httpresponse.rb

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/https.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#
# https.rb -- SSL/TLS enhancement for HTTPServer
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2001 GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $

require 'webrick/ssl'

module WEBrick
module Config
HTTP.update(SSL)
end

##
#--
# Adds SSL functionality to WEBrick::HTTPRequest

class HTTPRequest

##
# HTTP request SSL cipher

attr_reader :cipher

##
# HTTP request server certificate

attr_reader :server_cert

##
# HTTP request client certificate

attr_reader :client_cert

# :stopdoc:

alias orig_parse parse

def parse(socket=nil)
if socket.respond_to?(:cert)
@server_cert = socket.cert || @config[:SSLCertificate]
@client_cert = socket.peer_cert
@client_cert_chain = socket.peer_cert_chain
@cipher = socket.cipher
end
orig_parse(socket)
end

alias orig_parse_uri parse_uri

def parse_uri(str, scheme="https")
if server_cert
return orig_parse_uri(str, scheme)
end
return orig_parse_uri(str)
end
private :parse_uri

alias orig_meta_vars meta_vars

def meta_vars
meta = orig_meta_vars
if server_cert
meta["HTTPS"] = "on"
meta["SSL_SERVER_CERT"] = @server_cert.to_pem
meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
if @client_cert_chain
@client_cert_chain.each_with_index{|cert, i|
meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
}
end
meta["SSL_CIPHER"] = @cipher[0]
meta["SSL_PROTOCOL"] = @cipher[1]
meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s
meta["SSL_CIPHER_ALGKEYSIZE"] = @cipher[3].to_s
end
meta
end

# :startdoc:
end
end
278 changes: 278 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/httpserver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
#
# httpserver.rb -- HTTPServer Class
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $

require 'webrick/server'
require 'webrick/httputils'
require 'webrick/httpstatus'
require 'webrick/httprequest'
require 'webrick/httpresponse'
require 'webrick/httpservlet'
require 'webrick/accesslog'

module WEBrick
class HTTPServerError < ServerError; end

##
# An HTTP Server

class HTTPServer < ::WEBrick::GenericServer
##
# Creates a new HTTP server according to +config+
#
# An HTTP server uses the following attributes:
#
# :AccessLog:: An array of access logs. See WEBrick::AccessLog
# :BindAddress:: Local address for the server to bind to
# :DocumentRoot:: Root path to serve files from
# :DocumentRootOptions:: Options for the default HTTPServlet::FileHandler
# :HTTPVersion:: The HTTP version of this server
# :Port:: Port to listen on
# :RequestCallback:: Called with a request and response before each
# request is serviced.
# :RequestTimeout:: Maximum time to wait between requests
# :ServerAlias:: Array of alternate names for this server for virtual
# hosting
# :ServerName:: Name for this server for virtual hosting

def initialize(config={}, default=Config::HTTP)
super(config, default)
@http_version = HTTPVersion::convert(@config[:HTTPVersion])

@mount_tab = MountTable.new
if @config[:DocumentRoot]
mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot],
@config[:DocumentRootOptions])
end

unless @config[:AccessLog]
@config[:AccessLog] = [
[ $stderr, AccessLog::COMMON_LOG_FORMAT ],
[ $stderr, AccessLog::REFERER_LOG_FORMAT ]
]
end

@virtual_hosts = Array.new
end

##
# Processes requests on +sock+

def run(sock)
while true
res = HTTPResponse.new(@config)
req = HTTPRequest.new(@config)
server = self
begin
timeout = @config[:RequestTimeout]
while timeout > 0
break if IO.select([sock], nil, nil, 0.5)
timeout = 0 if @status != :Running
timeout -= 0.5
end
raise HTTPStatus::EOFError if timeout <= 0
raise HTTPStatus::EOFError if sock.eof?
req.parse(sock)
res.request_method = req.request_method
res.request_uri = req.request_uri
res.request_http_version = req.http_version
res.keep_alive = req.keep_alive?
server = lookup_server(req) || self
if callback = server[:RequestCallback]
callback.call(req, res)
elsif callback = server[:RequestHandler]
msg = ":RequestHandler is deprecated, please use :RequestCallback"
@logger.warn(msg)
callback.call(req, res)
end
server.service(req, res)
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
res.set_error(ex)
rescue HTTPStatus::Error => ex
@logger.error(ex.message)
res.set_error(ex)
rescue HTTPStatus::Status => ex
res.status = ex.code
rescue StandardError => ex
@logger.error(ex)
res.set_error(ex, true)
ensure
if req.request_line
if req.keep_alive? && res.keep_alive?
req.fixup()
end
res.send_response(sock)
server.access_log(@config, req, res)
end
end
break if @http_version < "1.1"
break unless req.keep_alive?
break unless res.keep_alive?
end
end

##
# Services +req+ and fills in +res+

def service(req, res)
if req.unparsed_uri == "*"
if req.request_method == "OPTIONS"
do_OPTIONS(req, res)
raise HTTPStatus::OK
end
raise HTTPStatus::NotFound, "`#{req.unparsed_uri}' not found."
end

servlet, options, script_name, path_info = search_servlet(req.path)
raise HTTPStatus::NotFound, "`#{req.path}' not found." unless servlet
req.script_name = script_name
req.path_info = path_info
si = servlet.get_instance(self, *options)
@logger.debug(format("%s is invoked.", si.class.name))
si.service(req, res)
end

##
# The default OPTIONS request handler says GET, HEAD, POST and OPTIONS
# requests are allowed.

def do_OPTIONS(req, res)
res["allow"] = "GET,HEAD,POST,OPTIONS"
end

##
# Mounts +servlet+ on +dir+ passing +options+ to the servlet at creation
# time

def mount(dir, servlet, *options)
@logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir))
@mount_tab[dir] = [ servlet, options ]
end

##
# Mounts +proc+ or +block+ on +dir+ and calls it with a
# WEBrick::HTTPRequest and WEBrick::HTTPResponse

def mount_proc(dir, proc=nil, &block)
proc ||= block
raise HTTPServerError, "must pass a proc or block" unless proc
mount(dir, HTTPServlet::ProcHandler.new(proc))
end

##
# Unmounts +dir+

def unmount(dir)
@logger.debug(sprintf("unmount %s.", dir))
@mount_tab.delete(dir)
end
alias umount unmount

##
# Finds a servlet for +path+

def search_servlet(path)
script_name, path_info = @mount_tab.scan(path)
servlet, options = @mount_tab[script_name]
if servlet
[ servlet, options, script_name, path_info ]
end
end

##
# Adds +server+ as a virtual host.

def virtual_host(server)
@virtual_hosts << server
@virtual_hosts = @virtual_hosts.sort_by{|s|
num = 0
num -= 4 if s[:BindAddress]
num -= 2 if s[:Port]
num -= 1 if s[:ServerName]
num
}
end

##
# Finds the appropriate virtual host to handle +req+

def lookup_server(req)
@virtual_hosts.find{|s|
(s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) &&
(s[:Port].nil? || req.port == s[:Port]) &&
((s[:ServerName].nil? || req.host == s[:ServerName]) ||
(!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host}))
}
end

##
# Logs +req+ and +res+ in the access logs. +config+ is used for the
# server name.

def access_log(config, req, res)
param = AccessLog::setup_params(config, req, res)
@config[:AccessLog].each{|logger, fmt|
logger << AccessLog::format(fmt+"\n", param)
}
end

##
# Mount table for the path a servlet is mounted on in the directory space
# of the server. Users of WEBrick can only access this indirectly via
# WEBrick::HTTPServer#mount, WEBrick::HTTPServer#unmount and
# WEBrick::HTTPServer#search_servlet

class MountTable # :nodoc:
def initialize
@tab = Hash.new
compile
end

def [](dir)
dir = normalize(dir)
@tab[dir]
end

def []=(dir, val)
dir = normalize(dir)
@tab[dir] = val
compile
val
end

def delete(dir)
dir = normalize(dir)
res = @tab.delete(dir)
compile
res
end

def scan(path)
@scanner =~ path
[ $&, $' ]
end

private

def compile
k = @tab.keys
k.sort!
k.reverse!
k.collect!{|path| Regexp.escape(path) }
@scanner = Regexp.new("^(" + k.join("|") +")(?=/|$)")
end

def normalize(dir)
ret = dir ? dir.dup : ""
ret.sub!(%r|/+$|, "")
ret
end
end
end
end
22 changes: 22 additions & 0 deletions lib/ruby/truffle/rubysl/rubysl-webrick/lib/webrick/httpservlet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# httpservlet.rb -- HTTPServlet Utility File
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: httpservlet.rb,v 1.21 2003/02/23 12:24:46 gotoyuzo Exp $

require 'webrick/httpservlet/abstract'
require 'webrick/httpservlet/filehandler'
require 'webrick/httpservlet/cgihandler'
require 'webrick/httpservlet/erbhandler'
require 'webrick/httpservlet/prochandler'

module WEBrick
module HTTPServlet
FileHandler.add_handler("cgi", CGIHandler)
FileHandler.add_handler("rhtml", ERBHandler)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#
# httpservlet.rb -- HTTPServlet Module
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $

require 'thread'

require 'webrick/htmlutils'
require 'webrick/httputils'
require 'webrick/httpstatus'

module WEBrick
module HTTPServlet
class HTTPServletError < StandardError; end

##
# AbstractServlet allows HTTP server modules to be reused across multiple
# servers and allows encapsulation of functionality.
#
# By default a servlet will respond to GET, HEAD (through an alias to GET)
# and OPTIONS requests.
#
# By default a new servlet is initialized for every request. A servlet
# instance can be reused by overriding ::get_instance in the
# AbstractServlet subclass.
#
# == A Simple Servlet
#
# class Simple < WEBrick::HTTPServlet::AbstractServlet
# def do_GET request, response
# status, content_type, body = do_stuff_with request
#
# response.status = status
# response['Content-Type'] = content_type
# response.body = body
# end
#
# def do_stuff_with request
# return 200, 'text/plain', 'you got a page'
# end
# end
#
# This servlet can be mounted on a server at a given path:
#
# server.mount '/simple', Simple
#
# == Servlet Configuration
#
# Servlets can be configured via initialize. The first argument is the
# HTTP server the servlet is being initialized for.
#
# class Configurable < Simple
# def initialize server, color, size
# super server
# @color = color
# @size = size
# end
#
# def do_stuff_with request
# content = "<p " \
# %q{style="color: #{@color}; font-size: #{@size}"} \
# ">Hello, World!"
#
# return 200, "text/html", content
# end
# end
#
# This servlet must be provided two arguments at mount time:
#
# server.mount '/configurable', Configurable, 'red', '2em'

class AbstractServlet

##
# Factory for servlet instances that will handle a request from +server+
# using +options+ from the mount point. By default a new servlet
# instance is created for every call.

def self.get_instance(server, *options)
self.new(server, *options)
end

##
# Initializes a new servlet for +server+ using +options+ which are
# stored as-is in +@options+. +@logger+ is also provided.

def initialize(server, *options)
@server = @config = server
@logger = @server[:Logger]
@options = options
end

##
# Dispatches to a +do_+ method based on +req+ if such a method is
# available. (+do_GET+ for a GET request). Raises a MethodNotAllowed
# exception if the method is not implemented.

def service(req, res)
method_name = "do_" + req.request_method.gsub(/-/, "_")
if respond_to?(method_name)
__send__(method_name, req, res)
else
raise HTTPStatus::MethodNotAllowed,
"unsupported method `#{req.request_method}'."
end
end

##
# Raises a NotFound exception

def do_GET(req, res)
raise HTTPStatus::NotFound, "not found."
end

##
# Dispatches to do_GET

def do_HEAD(req, res)
do_GET(req, res)
end

##
# Returns the allowed HTTP request methods

def do_OPTIONS(req, res)
m = self.methods.grep(/\Ado_([A-Z]+)\z/) {$1}
m.sort!
res["allow"] = m.join(",")
end

private

##
# Redirects to a path ending in /

def redirect_to_directory_uri(req, res)
if req.path[-1] != ?/
location = WEBrick::HTTPUtils.escape_path(req.path + "/")
if req.query_string && req.query_string.bytesize > 0
location << "?" << req.query_string
end
res.set_redirect(HTTPStatus::MovedPermanently, location)
end
end
end

end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# cgi_runner.rb -- CGI launcher.
#
# Author: IPR -- Internet Programming with Ruby -- writers
# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU YUUZOU
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
# reserved.
#
# $IPR: cgi_runner.rb,v 1.9 2002/09/25 11:33:15 gotoyuzo Exp $

def sysread(io, size)
buf = ""
while size > 0
tmp = io.sysread(size)
buf << tmp
size -= tmp.bytesize
end
return buf
end

STDIN.binmode

len = sysread(STDIN, 8).to_i
out = sysread(STDIN, len)
STDOUT.reopen(open(out, "w"))

len = sysread(STDIN, 8).to_i
err = sysread(STDIN, len)
STDERR.reopen(open(err, "w"))

len = sysread(STDIN, 8).to_i
dump = sysread(STDIN, len)
hash = Marshal.restore(dump)
ENV.keys.each{|name| ENV.delete(name) }
hash.each{|k, v| ENV[k] = v if v }

dir = File::dirname(ENV["SCRIPT_FILENAME"])
Dir::chdir dir

if ARGV[0]
argv = ARGV.dup
argv << ENV["SCRIPT_FILENAME"]
exec(*argv)
# NOTREACHED
end
exec ENV["SCRIPT_FILENAME"]
Loading

0 comments on commit 69d8085

Please sign in to comment.