Welcome to the "trac"-ing site of soap4r!
[soap4r] [httpclient] [openpgp4u] [pkcs1] [logger] [csv] [vtr]

root/branches/1_5/lib/soap/rpc/soaplet.rb

Revision 1829, 4.8 kB (checked in by nahi, 2 years ago)
  • SOAPlet generated a wrong cookie. fixed.
  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1 # SOAP4R - SOAP handler servlet for WEBrick
2 # Copyright (C) 2000-2007  NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
4 # This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
5 # redistribute it and/or modify it under the same terms of Ruby's license;
6 # either the dual license version in 2003, or any later version.
7
8
9 require 'webrick/httpservlet/abstract'
10 require 'webrick/httpstatus'
11 require 'soap/rpc/router'
12 require 'soap/streamHandler'
13 begin
14   require 'stringio'
15   require 'zlib'
16 rescue LoadError
17   warn("Loading stringio or zlib failed.  No gzipped response supported.") if $DEBUG
18 end
19
20
21 warn("Overriding WEBrick::Log#debug") if $DEBUG
22 require 'webrick/log'
23 module WEBrick
24   class Log < BasicLog
25     alias __debug debug
26     def debug(msg = nil)
27       if block_given? and msg.nil?
28         __debug(yield)
29       else
30         __debug(msg)
31       end
32     end
33   end
34 end
35
36
37 module SOAP
38 module RPC
39
40
41 class SOAPlet < WEBrick::HTTPServlet::AbstractServlet
42 public
43   attr_reader :options
44   attr_accessor :authenticator
45
46   def initialize(router = nil)
47     @router = router || ::SOAP::RPC::Router.new(self.class.name)
48     @options = {}
49     @authenticator = nil
50     @config = {}
51   end
52
53   # for backward compatibility
54   def app_scope_router
55     @router
56   end
57
58   # for backward compatibility
59   def add_servant(obj, namespace)
60     @router.add_rpc_servant(obj, namespace)
61   end
62
63   def allow_content_encoding_gzip=(allow)
64     @options[:allow_content_encoding_gzip] = allow
65   end
66
67   ###
68   ## Servlet interfaces for WEBrick.
69   #
70   def get_instance(config, *options)
71     @config = config
72     self
73   end
74
75   def require_path_info?
76     false
77   end
78
79   def do_GET(req, res)
80     res.header['Allow'] = 'POST'
81     raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed"
82   end
83
84   def do_POST(req, res)
85     logger.debug { "SOAP request: " + req.body } if logger
86     if @authenticator
87       @authenticator.authenticate(req, res)
88       # you can check authenticated user with SOAP::RPC::SOAPlet.user
89     end
90     begin
91       conn_data = ::SOAP::StreamHandler::ConnectionData.new
92       setup_req(conn_data, req)
93       @router.external_ces = @options[:external_ces]
94       Mapping.protect_threadvars(:SOAPlet) do
95         SOAPlet.user = req.user
96         SOAPlet.cookies = req.cookies
97         conn_data = @router.route(conn_data)
98         setup_res(conn_data, req, res)
99       end
100     rescue Exception => e
101       conn_data = @router.create_fault_response(e)
102       res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
103       res.body = conn_data.send_string
104       res['content-type'] = conn_data.send_contenttype || "text/xml"
105     end
106     if res.body.is_a?(IO)
107       res.chunked = true
108       logger.debug { "SOAP response: (chunked response not logged)" } if logger
109     else
110       logger.debug { "SOAP response: " + res.body } if logger
111     end
112   end
113
114   def self.cookies
115     get_variable(:Cookies)
116   end
117
118   def self.cookies=(cookies)
119     set_variable(:Cookies, cookies)
120   end
121
122   def self.user
123     get_variable(:User)
124   end
125
126   def self.user=(user)
127     set_variable(:User, user)
128   end
129
130 private
131
132   def self.get_variable(name)
133     if var = Thread.current[:SOAPlet]
134       var[name]
135     else
136       nil
137     end
138   end
139
140   def self.set_variable(name, value)
141     var = Thread.current[:SOAPlet] ||= {}
142     var[name] = value
143   end
144
145   def logger
146     @config[:Logger]
147   end
148
149   def setup_req(conn_data, req)
150     conn_data.receive_string = req.body
151     conn_data.receive_contenttype = req['content-type']
152     conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION'])
153   end
154
155   def setup_res(conn_data, req, res)
156     res['content-type'] = conn_data.send_contenttype
157     cookies = SOAPlet.cookies
158     unless cookies.empty?
159       res['set-cookie'] = cookies.collect { |cookie| cookie.to_s }
160     end
161     if conn_data.is_nocontent
162       res.status = WEBrick::HTTPStatus::RC_ACCEPTED
163       res.body = ''
164       return
165     end
166     if conn_data.is_fault
167       res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
168     end
169     if outstring = encode_gzip(req, conn_data.send_string)
170       res['content-encoding'] = 'gzip'
171       res['content-length'] = outstring.size
172       res.body = outstring
173     else
174       res.body = conn_data.send_string
175     end
176   end
177
178   def parse_soapaction(soapaction)
179     if !soapaction.nil? and !soapaction.empty?
180       if /^"(.+)"$/ =~ soapaction
181         return $1
182       end
183     end
184     nil
185   end
186
187   def encode_gzip(req, outstring)
188     unless encode_gzip?(req)
189       return nil
190     end
191     begin
192       ostream = StringIO.new
193       gz = Zlib::GzipWriter.new(ostream)
194       gz.write(outstring)
195       ostream.string
196     ensure
197       gz.close
198     end
199   end
200
201   def encode_gzip?(req)
202     @options[:allow_content_encoding_gzip] and defined?(::Zlib) and
203       req['accept-encoding'] and
204       req['accept-encoding'].split(/,\s*/).include?('gzip')
205   end
206 end
207
208
209 end
210 end
Note: See TracBrowser for help on using the browser.