1#-- 2# accesslog.rb -- Access log handling utilities 3# 4# Author: IPR -- Internet Programming with Ruby -- writers 5# Copyright (c) 2002 keita yamaguchi 6# Copyright (c) 2002 Internet Programming with Ruby writers 7# 8# $IPR: accesslog.rb,v 1.1 2002/10/01 17:16:32 gotoyuzo Exp $ 9 10module WEBrick 11 12 ## 13 # AccessLog provides logging to various files in various formats. 14 # 15 # Multiple logs may be written to at the same time: 16 # 17 # access_log = [ 18 # [$stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT], 19 # [$stderr, WEBrick::AccessLog::REFERER_LOG_FORMAT], 20 # ] 21 # 22 # server = WEBrick::HTTPServer.new :AccessLog => access_log 23 # 24 # Custom log formats may be defined. WEBrick::AccessLog provides a subset 25 # of the formatting from Apache's mod_log_config 26 # http://httpd.apache.org/docs/mod/mod_log_config.html#formats. See 27 # AccessLog::setup_params for a list of supported options 28 29 module AccessLog 30 31 ## 32 # Raised if a parameter such as %e, %i, %o or %n is used without fetching 33 # a specific field. 34 35 class AccessLogError < StandardError; end 36 37 ## 38 # The Common Log Format's time format 39 40 CLF_TIME_FORMAT = "[%d/%b/%Y:%H:%M:%S %Z]" 41 42 ## 43 # Common Log Format 44 45 COMMON_LOG_FORMAT = "%h %l %u %t \"%r\" %s %b" 46 47 ## 48 # Short alias for Common Log Format 49 50 CLF = COMMON_LOG_FORMAT 51 52 ## 53 # Referer Log Format 54 55 REFERER_LOG_FORMAT = "%{Referer}i -> %U" 56 57 ## 58 # User-Agent Log Format 59 60 AGENT_LOG_FORMAT = "%{User-Agent}i" 61 62 ## 63 # Combined Log Format 64 65 COMBINED_LOG_FORMAT = "#{CLF} \"%{Referer}i\" \"%{User-agent}i\"" 66 67 module_function 68 69 # This format specification is a subset of mod_log_config of Apache: 70 # 71 # %a:: Remote IP address 72 # %b:: Total response size 73 # %e{variable}:: Given variable in ENV 74 # %f:: Response filename 75 # %h:: Remote host name 76 # %{header}i:: Given request header 77 # %l:: Remote logname, always "-" 78 # %m:: Request method 79 # %{attr}n:: Given request attribute from <tt>req.attributes</tt> 80 # %{header}o:: Given response header 81 # %p:: Server's request port 82 # %{format}p:: The canonical port of the server serving the request or the 83 # actual port or the client's actual port. Valid formats are 84 # canonical, local or remote. 85 # %q:: Request query string 86 # %r:: First line of the request 87 # %s:: Request status 88 # %t:: Time the request was recieved 89 # %T:: Time taken to process the request 90 # %u:: Remote user from auth 91 # %U:: Unparsed URI 92 # %%:: Literal % 93 94 def setup_params(config, req, res) 95 params = Hash.new("") 96 params["a"] = req.peeraddr[3] 97 params["b"] = res.sent_size 98 params["e"] = ENV 99 params["f"] = res.filename || "" 100 params["h"] = req.peeraddr[2] 101 params["i"] = req 102 params["l"] = "-" 103 params["m"] = req.request_method 104 params["n"] = req.attributes 105 params["o"] = res 106 params["p"] = req.port 107 params["q"] = req.query_string 108 params["r"] = req.request_line.sub(/\x0d?\x0a\z/o, '') 109 params["s"] = res.status # won't support "%>s" 110 params["t"] = req.request_time 111 params["T"] = Time.now - req.request_time 112 params["u"] = req.user || "-" 113 params["U"] = req.unparsed_uri 114 params["v"] = config[:ServerName] 115 params 116 end 117 118 ## 119 # Formats +params+ according to +format_string+ which is described in 120 # setup_params. 121 122 def format(format_string, params) 123 format_string.gsub(/\%(?:\{(.*?)\})?>?([a-zA-Z%])/){ 124 param, spec = $1, $2 125 case spec[0] 126 when ?e, ?i, ?n, ?o 127 raise AccessLogError, 128 "parameter is required for \"#{spec}\"" unless param 129 (param = params[spec][param]) ? escape(param) : "-" 130 when ?t 131 params[spec].strftime(param || CLF_TIME_FORMAT) 132 when ?p 133 case param 134 when 'remote' 135 escape(params["i"].peeraddr[1].to_s) 136 else 137 escape(params["p"].to_s) 138 end 139 when ?% 140 "%" 141 else 142 escape(params[spec].to_s) 143 end 144 } 145 end 146 147 ## 148 # Escapes control characters in +data+ 149 150 def escape(data) 151 if data.tainted? 152 data.gsub(/[[:cntrl:]\\]+/) {$&.dump[1...-1]}.untaint 153 else 154 data 155 end 156 end 157 end 158end 159