1# 2# httpservlet.rb -- HTTPServlet Module 3# 4# Author: IPR -- Internet Programming with Ruby -- writers 5# Copyright (c) 2000 TAKAHASHI Masayoshi, GOTOU Yuuzou 6# Copyright (c) 2002 Internet Programming with Ruby writers. All rights 7# reserved. 8# 9# $IPR: abstract.rb,v 1.24 2003/07/11 11:16:46 gotoyuzo Exp $ 10 11require 'thread' 12 13require 'webrick/htmlutils' 14require 'webrick/httputils' 15require 'webrick/httpstatus' 16 17module WEBrick 18 module HTTPServlet 19 class HTTPServletError < StandardError; end 20 21 ## 22 # AbstractServlet allows HTTP server modules to be reused across multiple 23 # servers and allows encapsulation of functionality. 24 # 25 # By default a servlet will respond to GET, HEAD (through an alias to GET) 26 # and OPTIONS requests. 27 # 28 # By default a new servlet is initialized for every request. A servlet 29 # instance can be reused by overriding ::get_instance in the 30 # AbstractServlet subclass. 31 # 32 # == A Simple Servlet 33 # 34 # class Simple < WEBrick::HTTPServlet::AbstractServlet 35 # def do_GET request, response 36 # status, content_type, body = do_stuff_with request 37 # 38 # response.status = status 39 # response['Content-Type'] = content_type 40 # response.body = body 41 # end 42 # 43 # def do_stuff_with request 44 # return 200, 'text/plain', 'you got a page' 45 # end 46 # end 47 # 48 # This servlet can be mounted on a server at a given path: 49 # 50 # server.mount '/simple', Simple 51 # 52 # == Servlet Configuration 53 # 54 # Servlets can be configured via initialize. The first argument is the 55 # HTTP server the servlet is being initialized for. 56 # 57 # class Configurable < Simple 58 # def initialize server, color, size 59 # super server 60 # @color = color 61 # @size = size 62 # end 63 # 64 # def do_stuff_with request 65 # content = "<p " \ 66 # %q{style="color: #{@color}; font-size: #{@size}"} \ 67 # ">Hello, World!" 68 # 69 # return 200, "text/html", content 70 # end 71 # end 72 # 73 # This servlet must be provided two arguments at mount time: 74 # 75 # server.mount '/configurable', Configurable, 'red', '2em' 76 77 class AbstractServlet 78 79 ## 80 # Factory for servlet instances that will handle a request from +server+ 81 # using +options+ from the mount point. By default a new servlet 82 # instance is created for every call. 83 84 def self.get_instance(server, *options) 85 self.new(server, *options) 86 end 87 88 ## 89 # Initializes a new servlet for +server+ using +options+ which are 90 # stored as-is in +@options+. +@logger+ is also provided. 91 92 def initialize(server, *options) 93 @server = @config = server 94 @logger = @server[:Logger] 95 @options = options 96 end 97 98 ## 99 # Dispatches to a +do_+ method based on +req+ if such a method is 100 # available. (+do_GET+ for a GET request). Raises a MethodNotAllowed 101 # exception if the method is not implemented. 102 103 def service(req, res) 104 method_name = "do_" + req.request_method.gsub(/-/, "_") 105 if respond_to?(method_name) 106 __send__(method_name, req, res) 107 else 108 raise HTTPStatus::MethodNotAllowed, 109 "unsupported method `#{req.request_method}'." 110 end 111 end 112 113 ## 114 # Raises a NotFound exception 115 116 def do_GET(req, res) 117 raise HTTPStatus::NotFound, "not found." 118 end 119 120 ## 121 # Dispatches to do_GET 122 123 def do_HEAD(req, res) 124 do_GET(req, res) 125 end 126 127 ## 128 # Returns the allowed HTTP request methods 129 130 def do_OPTIONS(req, res) 131 m = self.methods.grep(/\Ado_([A-Z]+)\z/) {$1} 132 m.sort! 133 res["allow"] = m.join(",") 134 end 135 136 private 137 138 ## 139 # Redirects to a path ending in / 140 141 def redirect_to_directory_uri(req, res) 142 if req.path[-1] != ?/ 143 location = WEBrick::HTTPUtils.escape_path(req.path + "/") 144 if req.query_string && req.query_string.bytesize > 0 145 location << "?" << req.query_string 146 end 147 res.set_redirect(HTTPStatus::MovedPermanently, location) 148 end 149 end 150 end 151 152 end 153end 154