1 # -*- encoding: binary -*-
16 # support nginx variables that are less customizable than our own
18 '$request_time' => '$request_time{3}',
19 '$time_local' => '$time_local{%d/%b/%Y:%H:%M:%S %z}',
20 '$msec' => '$time{3}',
21 '$usec' => '$time{6}',
25 :body_bytes_sent => 0,
27 :request => 2, # REQUEST_METHOD PATH_INFO?QUERY_STRING HTTP_VERSION
28 :request_length => 3, # env['rack.input'].size
29 :response_length => 4, # like body_bytes_sent, except "-" instead of "0"
30 :ip => 5, # HTTP_X_FORWARDED_FOR || REMOTE_ADDR || -
36 CGI_ENV = Regexp.new('\A\$(' <<
37 %w(remote_addr remote_ident remote_user
38 path_info query_string script_name
39 server_name server_port).join('|') << ')\z').freeze
41 SCAN = /([^$]*)(\$+(?:env\{\w+(?:\.[\w\.]+)?\}|
43 (?:request_)?time\{\d+\}|
44 time_(?:utc|local)\{[^\}]+\}|
47 def compile_format(str)
49 str.scan(SCAN).each do |pre,tok,post|
50 rv << [ OP_LITERAL, pre ] if pre && pre != ""
53 if tok.sub!(/\A(\$+)\$/, '$')
54 rv << [ OP_LITERAL, $1.dup ]
57 compat = ALIASES[tok] and tok = compat
61 rv << [ OP_LITERAL, $1.dup ]
62 when /\A\$env\{(\w+(?:\.[\w\.]+))\}\z/
63 rv << [ OP_REQUEST, $1.freeze ]
64 when /\A\$e\{([^\}]+)\}\z/
65 rv << [ OP_EVAL, $1.dup ]
66 when /\A\$cookie_(\w+)\z/
67 rv << [ OP_COOKIE, $1.dup.freeze ]
68 when CGI_ENV, /\A\$(http_\w+)\z/
69 rv << [ OP_REQUEST, $1.upcase.freeze ]
70 when /\A\$sent_http_(\w+)\z/
71 rv << [ OP_RESPONSE, $1.downcase.tr('_','-').freeze ]
72 when /\A\$time_local\{([^\}]+)\}\z/
73 rv << [ OP_TIME_LOCAL, $1.dup ]
74 when /\A\$time_utc\{([^\}]+)\}\z/
75 rv << [ OP_TIME_UTC, $1.dup ]
76 when /\A\$time\{(\d+)\}\z/
77 rv << [ OP_TIME, *usec_conv_pair(tok, $1.to_i) ]
78 when /\A\$request_time\{(\d+)\}\z/
79 rv << [ OP_REQUEST_TIME, *usec_conv_pair(tok, $1.to_i) ]
81 tok_sym = tok[1..-1].to_sym
82 if special_code = SPECIAL_VARS[tok_sym]
83 rv << [ OP_SPECIAL, special_code ]
85 raise ArgumentError, "unable to make sense of token: #{tok}"
90 rv << [ OP_LITERAL, post ] if post && post != ""
93 # auto-append a newline
94 last = rv.last or return rv
96 if (op == OP_LITERAL && /\n\z/ !~ last.last) || op != OP_LITERAL
97 rv << [ OP_LITERAL, "\n" ]
103 def usec_conv_pair(tok, prec)
105 [ "%d", 1 ] # stupid...
107 raise ArgumentError, "#{tok}: too high precision: #{prec} (max=6)"
109 [ "%d.%0#{prec}d", 10 ** (6 - prec) ]
113 def need_response_headers?(fmt_ops)
114 fmt_ops.any? { |op| OP_RESPONSE == op[0] }
117 def need_wrap_body?(fmt_ops)
119 (OP_REQUEST_TIME == op[0]) || (OP_SPECIAL == op[0] &&
120 (SPECIAL_VARS[:body_bytes_sent] == op[1] ||
121 SPECIAL_VARS[:response_length] == op[1]))
127 require 'clogger/format'
130 require 'clogger_ext'
132 require 'clogger/pure'