PageRenderTime 141ms CodeModel.GetById 41ms app.highlight 28ms RepoModel.GetById 70ms app.codeStats 0ms

/tools/Ruby/lib/ruby/1.8/soap/streamHandler.rb

http://github.com/agross/netopenspace
Ruby | 229 lines | 189 code | 34 blank | 6 comment | 21 complexity | 0af91e9db62d09e951e0dd1efb2c8a68 MD5 | raw file
  1# SOAP4R - Stream handler.
  2# Copyright (C) 2000, 2001, 2003  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
  9require 'soap/soap'
 10require 'soap/httpconfigloader'
 11begin
 12  require 'stringio'
 13  require 'zlib'
 14rescue LoadError
 15  warn("Loading stringio or zlib failed.  No gzipped response support.") if $DEBUG
 16end
 17
 18
 19module SOAP
 20
 21
 22class StreamHandler
 23  RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]"
 24
 25  class ConnectionData
 26    attr_accessor :send_string
 27    attr_accessor :send_contenttype
 28    attr_accessor :receive_string
 29    attr_accessor :receive_contenttype
 30    attr_accessor :is_fault
 31    attr_accessor :soapaction
 32
 33    def initialize(send_string = nil)
 34      @send_string = send_string
 35      @send_contenttype = nil
 36      @receive_string = nil
 37      @receive_contenttype = nil
 38      @is_fault = false
 39      @soapaction = nil
 40    end
 41  end
 42
 43  def self.parse_media_type(str)
 44    if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str
 45      return nil
 46    end
 47    charset = $1
 48    charset.gsub!(/"/, '') if charset
 49    charset || 'us-ascii'
 50  end
 51
 52  def self.create_media_type(charset)
 53    "#{ MediaType }; charset=#{ charset }"
 54  end
 55end
 56
 57
 58class HTTPStreamHandler < StreamHandler
 59  include SOAP
 60
 61  begin
 62    require 'http-access2'
 63    if HTTPAccess2::VERSION < "2.0"
 64      raise LoadError.new("http-access/2.0 or later is required.")
 65    end
 66    Client = HTTPAccess2::Client
 67    RETRYABLE = true
 68  rescue LoadError
 69    warn("Loading http-access2 failed.  Net/http is used.") if $DEBUG
 70    require 'soap/netHttpClient'
 71    Client = SOAP::NetHttpClient
 72    RETRYABLE = false
 73  end
 74
 75
 76public
 77  
 78  attr_reader :client
 79  attr_accessor :wiredump_file_base
 80  
 81  MAX_RETRY_COUNT = 10       	# [times]
 82
 83  def initialize(options)
 84    super()
 85    @client = Client.new(nil, "SOAP4R/#{ Version }")
 86    @wiredump_file_base = nil
 87    @charset = @wiredump_dev = nil
 88    @options = options
 89    set_options
 90    @client.debug_dev = @wiredump_dev
 91    @cookie_store = nil
 92    @accept_encoding_gzip = false
 93  end
 94
 95  def test_loopback_response
 96    @client.test_loopback_response
 97  end
 98
 99  def accept_encoding_gzip=(allow)
100    @accept_encoding_gzip = allow
101  end
102
103  def inspect
104    "#<#{self.class}>"
105  end
106
107  def send(endpoint_url, conn_data, soapaction = nil, charset = @charset)
108    conn_data.soapaction ||= soapaction # for backward conpatibility
109    send_post(endpoint_url, conn_data, charset)
110  end
111
112  def reset(endpoint_url = nil)
113    if endpoint_url.nil?
114      @client.reset_all
115    else
116      @client.reset(endpoint_url)
117    end
118    @client.save_cookie_store if @cookie_store
119  end
120
121private
122
123  def set_options
124    HTTPConfigLoader.set_options(@client, @options)
125    @charset = @options["charset"] || XSD::Charset.xml_encoding_label
126    @options.add_hook("charset") do |key, value|
127      @charset = value
128    end
129    @wiredump_dev = @options["wiredump_dev"]
130    @options.add_hook("wiredump_dev") do |key, value|
131      @wiredump_dev = value
132      @client.debug_dev = @wiredump_dev
133    end
134    set_cookie_store_file(@options["cookie_store_file"])
135    @options.add_hook("cookie_store_file") do |key, value|
136      set_cookie_store_file(value)
137    end
138    ssl_config = @options["ssl_config"]
139    basic_auth = @options["basic_auth"]
140    @options.lock(true)
141    ssl_config.unlock
142    basic_auth.unlock
143  end
144
145  def set_cookie_store_file(value)
146    value = nil if value and value.empty?
147    @cookie_store = value
148    @client.set_cookie_store(@cookie_store) if @cookie_store
149  end
150
151  def send_post(endpoint_url, conn_data, charset)
152    conn_data.send_contenttype ||= StreamHandler.create_media_type(charset)
153
154    if @wiredump_file_base
155      filename = @wiredump_file_base + '_request.xml'
156      f = File.open(filename, "w")
157      f << conn_data.send_string
158      f.close
159    end
160
161    extra = {}
162    extra['Content-Type'] = conn_data.send_contenttype
163    extra['SOAPAction'] = "\"#{ conn_data.soapaction }\""
164    extra['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip?
165    send_string = conn_data.send_string
166    @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev
167    begin
168      retry_count = 0
169      while true
170        res = @client.post(endpoint_url, send_string, extra)
171        if RETRYABLE and HTTP::Status.redirect?(res.status)
172          retry_count += 1
173          if retry_count >= MAX_RETRY_COUNT
174            raise HTTPStreamError.new("redirect count exceeded")
175          end
176          endpoint_url = res.header["location"][0]
177          puts "redirected to #{endpoint_url}" if $DEBUG
178        else
179          break
180        end
181      end
182    rescue
183      @client.reset(endpoint_url)
184      raise
185    end
186    @wiredump_dev << "\n\n" if @wiredump_dev
187    receive_string = res.content
188    if @wiredump_file_base
189      filename = @wiredump_file_base + '_response.xml'
190      f = File.open(filename, "w")
191      f << receive_string
192      f.close
193    end
194    case res.status
195    when 405
196      raise PostUnavailableError.new("#{ res.status }: #{ res.reason }")
197    when 200, 500
198      # Nothing to do.
199    else
200      raise HTTPStreamError.new("#{ res.status }: #{ res.reason }")
201    end
202    if res.respond_to?(:header) and !res.header['content-encoding'].empty? and
203        res.header['content-encoding'][0].downcase == 'gzip'
204      receive_string = decode_gzip(receive_string)
205    end
206    conn_data.receive_string = receive_string
207    conn_data.receive_contenttype = res.contenttype
208    conn_data
209  end
210
211  def send_accept_encoding_gzip?
212    @accept_encoding_gzip and defined?(::Zlib)
213  end
214
215  def decode_gzip(instring)
216    unless send_accept_encoding_gzip?
217      raise HTTPStreamError.new("Gzipped response content.")
218    end
219    begin
220      gz = Zlib::GzipReader.new(StringIO.new(instring))
221      gz.read
222    ensure
223      gz.close
224    end
225  end
226end
227
228
229end