module Ethon module Curls # This module contains logic for setting options on # easy or multi interface. module Options OPTION_STRINGS = { :easy => 'easy_options', :multi => 'multi_options' }.freeze FOPTION_STRINGS = { :easy => 'EASY_OPTIONS', :multi => 'MULTI_OPTIONS' }.freeze FTYPES = [:long, :string, :ffipointer, :callback, :debug_callback, :progress_callback, :off_t] FUNCS = Hash[*[:easy, :multi].zip([:easy, :multi].map { |t| Hash[*FTYPES.zip(FTYPES.map { |ft| "#{t}_setopt_#{ft}" }).flatten] }).flatten] # Sets appropriate option for easy, depending on value type. def set_option(option, value, handle, type = :easy) type = type.to_sym unless type.is_a?(Symbol) raise NameError, "Ethon::Curls::Options unknown type #{type}." unless respond_to?(OPTION_STRINGS[type]) opthash=send(OPTION_STRINGS[type], nil) raise Errors::InvalidOption.new(option) unless opthash.include?(option) case opthash[option][:type] when :none return if value.nil? value=1 func=:long when :int return if value.nil? func=:long value=value.to_i when :bool return if value.nil? func=:long value=(value&&value!=0) ? 1 : 0 when :time return if value.nil? func=:long value=value.to_i when :enum return if value.nil? func=:long value = case value when Symbol opthash[option][:opts][value] when String opthash[option][:opts][value.to_sym] else value end.to_i when :bitmask return if value.nil? func=:long value = case value when Symbol opthash[option][:opts][value] when Array value.inject(0) { |res,v| res|opthash[option][:opts][v] } else value end.to_i when :string func=:string value=value.to_s unless value.nil? when :string_as_pointer func = :ffipointer s = '' s = value.to_s unless value.nil? value = FFI::MemoryPointer.new(:char, s.bytesize) value.put_bytes(0, s) when :string_escape_null func=:string value=Util.escape_zero_byte(value) unless value.nil? when :ffipointer func=:ffipointer raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? FFI::Pointer when :curl_slist func=:ffipointer raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? FFI::Pointer when :buffer raise NotImplementedError, "Ethon::Curls::Options option #{option} buffer type not implemented." when :dontuse_object raise NotImplementedError, "Ethon::Curls::Options option #{option} type not implemented." when :cbdata raise NotImplementedError, "Ethon::Curls::Options option #{option} callback data type not implemented. Use Ruby closures." when :callback func=:callback raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc when :debug_callback func=:debug_callback raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc when :progress_callback func=:progress_callback raise Errors::InvalidValue.new(option,value) unless value.nil? or value.is_a? Proc when :off_t return if value.nil? func=:off_t value=value.to_i end if func==:long or func==:off_t then bits=FFI.type_size(:long)*8 if func==:long bits=FFI.type_size(:int64)*8 if func==:off_t tv=((value<0) ? value.abs-1 : value) raise Errors::InvalidValue.new(option,value) unless tv<(1< 0, :objectpoint => 10000, :functionpoint => 20000, :off_t => 30000 } OPTION_TYPE_MAP = { :none => :long, :int => :long, :bool => :long, :time => :long, :enum => :long, # Two ways to specify values (as opts parameter): # * Array of symbols, these will number sequentially # starting at 0. Skip elements with nil. (see :netrc) # * Hash of :symbol => enum_value (See :proxytype) :bitmask => :long, # Three ways to specify values (as opts parameter): # * Hash of :symbol => bitmask_value or Array. # An Array can be an array of already defined # Symbols, which represents a bitwise or of those # symbols. (See :httpauth) # * Array of symbols, these will number the bits # sequentially (i.e. 0, 1, 2, 4, etc.). Skip # elements with nil. The last element can be a # Hash, which will be interpreted as above. # (See :protocols) # :all defaults to all bits set :string => :objectpoint, :string_escape_null => :objectpoint, :string_as_pointer => :objectpoint, :ffipointer => :objectpoint, # FFI::Pointer :curl_slist => :objectpoint, :buffer => :objectpoint, # A memory buffer of size defined in the options :dontuse_object => :objectpoint, # An object we don't support (e.g. FILE*) :cbdata => :objectpoint, :callback => :functionpoint, :debug_callback => :functionpoint, :progress_callback => :functionpoint, :off_t => :off_t, } def self.option(ftype,name,type,num,opts=nil) case type when :enum if opts.is_a? Array then opts=Hash[opts.each_with_index.to_a] elsif not opts.is_a? Hash then raise TypeError, "Ethon::Curls::Options #{ftype} #{name} Expected opts to be an Array or a Hash." end when :bitmask if opts.is_a? Array then if opts.last.is_a? Hash then hopts=opts.pop else hopts={} end opts.each_with_index do |v,i| next if v.nil? if i==0 then hopts[v]=0 else hopts[v]=1<<(i-1) end end opts=hopts elsif not opts.is_a? Hash then raise TypeError, "Ethon::Curls::Options #{ftype} #{name} Expected opts to be an Array or a Hash." end opts[:all]=-1 unless opts.include? :all opts.each do |k,v| if v.is_a? Array then opts[k]=v.map { |b| opts[b] }.inject :| end end when :buffer raise TypeError, "Ethon::Curls::Options #{ftype} #{name} Expected opts to be an Array or a Hash." unless opts.is_a? Integer else raise ArgumentError, "Ethon::Curls::Options #{ftype} #{name} Expected no opts." unless opts.nil? end opthash=const_get(FOPTION_STRINGS[ftype]) opthash[name] = { :type => type, :opt => OPTION_TYPE_BASE[OPTION_TYPE_MAP[type]] + num, :opts => opts } end def self.option_alias(ftype,name,*aliases) opthash=const_get(FOPTION_STRINGS[ftype]) aliases.each { |a| opthash[a]=opthash[name] } end def self.option_type(type) cname = FOPTION_STRINGS[type] const_set(cname, {}) define_method(OPTION_STRINGS[type]) do |rt| return Ethon::Curls::Options.const_get(cname).map { |k, v| [k, v[:opt]] } if rt == :enum Ethon::Curls::Options.const_get(cname) end end # Curl multi options, refer # Defined @ https://github.com/bagder/curl/blob/master/include/curl/multi.h # Documentation @ http://curl.haxx.se/libcurl/c/curl_multi_setopt.html option_type :multi option :multi, :socketfunction, :callback, 1 option :multi, :socketdata, :cbdata, 2 option :multi, :pipelining, :int, 3 option :multi, :timerfunction, :callback, 4 option :multi, :timerdata, :cbdata, 5 option :multi, :maxconnects, :int, 6 option :multi, :max_host_connections, :int, 7 option :multi, :max_pipeline_length, :int, 8 option :multi, :content_length_penalty_size, :off_t, 9 option :multi, :chunk_length_penalty_size, :off_t, 10 option :multi, :pipelining_site_bl, :dontuse_object, 11 option :multi, :pipelining_server_bl, :dontuse_object, 12 option :multi, :max_total_connections, :int, 3 # Curl easy options # Defined @ https://github.com/bagder/curl/blob/master/include/curl/curl.h # Documentation @ http://curl.haxx.se/libcurl/c/curl_easy_setopt.html ## BEHAVIOR OPTIONS option_type :easy option :easy, :verbose, :bool, 41 option :easy, :header, :bool, 42 option :easy, :noprogress, :bool, 43 option :easy, :nosignal, :bool, 99 option :easy, :wildcardmatch, :bool, 197 ## CALLBACK OPTIONS option :easy, :writefunction, :callback, 11 option :easy, :file, :cbdata, 1 option_alias :easy, :file, :writedata option :easy, :readfunction, :callback, 12 option :easy, :infile, :cbdata, 9 option_alias :easy, :infile, :readdata option :easy, :ioctlfunction, :callback, 130 option :easy, :ioctldata, :cbdata, 131 option :easy, :seekfunction, :callback, 167 option :easy, :seekdata, :cbdata, 168 option :easy, :sockoptfunction, :callback, 148 option :easy, :sockoptdata, :cbdata, 149 option :easy, :opensocketfunction, :callback, 163 option :easy, :opensocketdata, :cbdata, 164 option :easy, :closesocketfunction, :callback, 208 option :easy, :closesocketdata, :cbdata, 209 option :easy, :progressfunction, :progress_callback, 56 option :easy, :progressdata, :cbdata, 57 option :easy, :headerfunction, :callback, 79 option :easy, :writeheader, :cbdata, 29 option_alias :easy, :writeheader, :headerdata option :easy, :debugfunction, :debug_callback, 94 option :easy, :debugdata, :cbdata, 95 option :easy, :ssl_ctx_function, :callback, 108 option :easy, :ssl_ctx_data, :cbdata, 109 option :easy, :conv_to_network_function, :callback, 143 option :easy, :conv_from_network_function, :callback, 142 option :easy, :conv_from_utf8_function, :callback, 144 option :easy, :interleavefunction, :callback, 196 option :easy, :interleavedata, :cbdata, 195 option :easy, :chunk_bgn_function, :callback, 198 option :easy, :chunk_end_function, :callback, 199 option :easy, :chunk_data, :cbdata, 201 option :easy, :fnmatch_function, :callback, 200 option :easy, :fnmatch_data, :cbdata, 202 option :easy, :xferinfofunction, :progress_callback, 219 option :easy, :xferinfodata, :cbdata, 57 ## ERROR OPTIONS option :easy, :errorbuffer, :buffer, 10, 256 option :easy, :stderr, :dontuse_object, 37 option :easy, :failonerror, :bool, 45 ## NETWORK OPTIONS option :easy, :url, :string, 2 option :easy, :protocols, :bitmask, 181, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher] option :easy, :redir_protocols, :bitmask, 182, [nil, :http, :https, :ftp, :ftps, :scp, :sftp, :telnet, :ldap, :ldaps, :dict, :file, :tftp, :imap, :imaps, :pop3, :pop3s, :smtp, :smtps, :rtsp, :rtmp, :rtmpt, :rtmpe, :rtmpte, :rtmps, :rtmpts, :gopher] option :easy, :proxy, :string, 4 option :easy, :proxyport, :int, 59 option :easy, :proxytype, :enum, 101, [:http, :http_1_0, nil, nil, :socks4, :socks5, :socks4a, :socks5_hostname] option :easy, :noproxy, :string, 177 option :easy, :httpproxytunnel, :bool, 61 option :easy, :socks5_gssapi_service, :string, 179 option :easy, :socks5_gssapi_nec, :bool, 180 option :easy, :interface, :string, 62 option :easy, :localport, :int, 139 option :easy, :localportrange, :int, 140 option :easy, :dns_cache_timeout, :int, 92 option :easy, :dns_use_global_cache, :bool, 91 # Obsolete option :easy, :dns_interface, :string, 221 option :easy, :dns_local_ip4, :string, 222 option :easy, :buffersize, :int, 98 option :easy, :port, :int, 3 option :easy, :tcp_nodelay, :bool, 121 option :easy, :address_scope, :int, 171 option :easy, :tcp_keepalive, :bool, 213 option :easy, :tcp_keepidle, :int, 214 option :easy, :tcp_keepintvl, :int, 215 ## NAMES and PASSWORDS OPTIONS (Authentication) option :easy, :netrc, :enum, 51, [:ignored, :optional, :required] option :easy, :netrc_file, :string, 118 option :easy, :userpwd, :string, 5 option :easy, :proxyuserpwd, :string, 6 option :easy, :username, :string, 173 option :easy, :password, :string, 174 option :easy, :proxyusername, :string, 175 option :easy, :proxypassword, :string, 176 option :easy, :httpauth, :bitmask, 107, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x10, :anysafe => ~0x11, :auto => 0x1f}] option :easy, :tlsauth_type, :enum, 206, [:none, :srp] option :easy, :tlsauth_username, :string, 204 option :easy, :tlsauth_password, :string, 205 option :easy, :proxyauth, :bitmask, 111, [:none, :basic, :digest, :gssnegotiate, :ntlm, :digest_ie, :ntlm_wb, {:only => 1<<31, :any => ~0x10, :anysafe => ~0x11, :auto => 0x1f}] option :easy, :sasl_ir, :bool, 218 ## HTTP OPTIONS option :easy, :autoreferer, :bool, 58 option :easy, :accept_encoding, :string, 102 option_alias :easy, :accept_encoding, :encoding option :easy, :transfer_encoding, :bool, 207 option :easy, :followlocation, :bool, 52 option :easy, :unrestricted_auth, :bool, 105 option :easy, :maxredirs, :int, 68 option :easy, :postredir, :bitmask, 161, [:get_all, :post_301, :post_302, :post_303, {:post_all => [:post_301, :post_302, :post_303]}] option_alias :easy, :postredir, :post301 option :easy, :put, :bool, 54 option :easy, :post, :bool, 47 option :easy, :postfields, :string, 15 option :easy, :postfieldsize, :int, 60 option :easy, :postfieldsize_large, :off_t, 120 option :easy, :copypostfields, :string_as_pointer, 165 option :easy, :httppost, :ffipointer, 24 option :easy, :referer, :string, 16 option :easy, :useragent, :string, 18 option :easy, :httpheader, :curl_slist, 23 option :easy, :http200aliases, :curl_slist, 104 option :easy, :cookie, :string, 22 option :easy, :cookiefile, :string, 31 option :easy, :cookiejar, :string, 82 option :easy, :cookiesession, :bool, 96 option :easy, :cookielist, :string, 135 option :easy, :httpget, :bool, 80 option :easy, :http_version, :enum, 84, [:none, :httpv1_0, :httpv1_1, :httpv2_0] option :easy, :ignore_content_length, :bool, 136 option :easy, :http_content_decoding, :bool, 158 option :easy, :http_transfer_decoding, :bool, 157 ## SMTP OPTIONS option :easy, :mail_from, :string, 186 option :easy, :mail_rcpt, :curl_slist, 187 option :easy, :mail_auth, :string, 217 ## TFTP OPTIONS option :easy, :tftp_blksize, :int, 178 ## FTP OPTIONS option :easy, :ftpport, :string, 17 option :easy, :quote, :curl_slist, 28 option :easy, :postquote, :curl_slist, 39 option :easy, :prequote, :curl_slist, 93 option :easy, :dirlistonly, :bool, 48 option_alias :easy, :dirlistonly, :ftplistonly option :easy, :append, :bool, 50 option_alias :easy, :append, :ftpappend option :easy, :ftp_use_eprt, :bool, 106 option :easy, :ftp_use_epsv, :bool, 85 option :easy, :ftp_use_pret, :bool, 188 option :easy, :ftp_create_missing_dirs, :bool, 110 option :easy, :ftp_response_timeout, :int, 112 option_alias :easy, :ftp_response_timeout, :server_response_timeout option :easy, :ftp_alternative_to_user, :string, 147 option :easy, :ftp_skip_pasv_ip, :bool, 137 option :easy, :ftpsslauth, :enum, 129, [:default, :ssl, :tls] option :easy, :ftp_ssl_ccc, :enum, 154, [:none, :passive, :active] option :easy, :ftp_account, :string, 134 option :easy, :ftp_filemethod, :enum, 138, [:default, :multicwd, :nocwd, :singlecwd] ## RTSP OPTIONS option :easy, :rtsp_request, :enum, 189, [:none, :options, :describe, :announce, :setup, :play, :pause, :teardown, :get_parameter, :set_parameter, :record, :receive] option :easy, :rtsp_session_id, :string, 190 option :easy, :rtsp_stream_uri, :string, 191 option :easy, :rtsp_transport, :string, 192 option_alias :easy, :httpheader, :rtspheader option :easy, :rtsp_client_cseq, :int, 193 option :easy, :rtsp_server_cseq, :int, 194 ## PROTOCOL OPTIONS option :easy, :transfertext, :bool, 53 option :easy, :proxy_transfer_mode, :bool, 166 option :easy, :crlf, :bool, 27 option :easy, :range, :string, 7 option :easy, :resume_from, :int, 21 option :easy, :resume_from_large, :off_t, 116 option :easy, :customrequest, :string, 36 option :easy, :filetime, :bool, 69 option :easy, :nobody, :bool, 44 option :easy, :infilesize, :int, 14 option :easy, :infilesize_large, :off_t, 115 option :easy, :upload, :bool, 46 option :easy, :maxfilesize, :int, 114 option :easy, :maxfilesize_large, :off_t, 117 option :easy, :timecondition, :enum, 33, [:none, :ifmodsince, :ifunmodsince, :lastmod] option :easy, :timevalue, :time, 34 ## CONNECTION OPTIONS option :easy, :timeout, :int, 13 option :easy, :timeout_ms, :int, 155 option :easy, :low_speed_limit, :int, 19 option :easy, :low_speed_time, :int, 20 option :easy, :max_send_speed_large, :off_t, 145 option :easy, :max_recv_speed_large, :off_t, 146 option :easy, :maxconnects, :int, 71 option :easy, :fresh_connect, :bool, 74 option :easy, :forbid_reuse, :bool, 75 option :easy, :connecttimeout, :int, 78 option :easy, :connecttimeout_ms, :int, 156 option :easy, :ipresolve, :enum, 113, [:whatever, :v4, :v6] option :easy, :connect_only, :bool, 141 option :easy, :use_ssl, :enum, 119, [:none, :try, :control, :all] option_alias :easy, :use_ssl, :ftp_ssl option :easy, :resolve, :curl_slist, 203 option :easy, :dns_servers, :string, 211 option :easy, :accepttimeout_ms, :int, 212 option :easy, :unix_socket_path, :string, 231 option :easy, :pipewait, :bool, 237 option_alias :easy, :unix_socket_path, :unix_socket ## SSL and SECURITY OPTIONS option :easy, :sslcert, :string, 25 option :easy, :sslcerttype, :string, 86 option :easy, :sslkey, :string, 87 option :easy, :sslkeytype, :string, 88 option :easy, :keypasswd, :string, 26 option_alias :easy, :keypasswd, :sslcertpasswd option_alias :easy, :keypasswd, :sslkeypasswd option :easy, :sslengine, :string, 89 option :easy, :sslengine_default, :none, 90 option :easy, :sslversion, :enum, 32, [:default, :tlsv1, :sslv2, :sslv3, :tlsv1_0, :tlsv1_1, :tlsv1_2] option :easy, :ssl_verifypeer, :bool, 64 option :easy, :cainfo, :string, 65 option :easy, :issuercert, :string, 170 option :easy, :capath, :string, 97 option :easy, :crlfile, :string, 169 option :easy, :ssl_verifyhost, :int, 81 option :easy, :certinfo, :bool, 172 option :easy, :random_file, :string, 76 option :easy, :egdsocket, :string, 77 option :easy, :ssl_cipher_list, :string, 83 option :easy, :ssl_sessionid_cache, :bool, 150 option :easy, :ssl_options, :bitmask, 216, [nil, :allow_beast] option :easy, :krblevel, :string, 63 option_alias :easy, :krblevel, :krb4level option :easy, :gssapi_delegation, :bitmask, 210, [:none, :policy_flag, :flag] ## SSH OPTIONS option :easy, :ssh_auth_types, :bitmask, 151, [:none, :publickey, :password, :host, :keyboard, :agent, {:any => [:all], :default => [:any]}] option :easy, :ssh_host_public_key_md5, :string, 162 option :easy, :ssh_public_keyfile, :string, 152 option :easy, :ssh_private_keyfile, :string, 153 option :easy, :ssh_knownhosts, :string, 183 option :easy, :ssh_keyfunction, :callback, 184 option :easy, :khstat, :enum, -1, [:fine_add_to_file, :fine, :reject, :defer] # Kludge to make this enum available... Access via CurL::EASY_OPTIONS[:khstat][:opt] option :easy, :ssh_keydata, :cbdata, 185 ## OTHER OPTIONS option :easy, :private, :cbdata, 103 option :easy, :share, :dontuse_object, 100 option :easy, :new_file_perms, :int, 159 option :easy, :new_directory_perms, :int, 160 ## TELNET OPTIONS option :easy, :telnetoptions, :curl_slist, 70 end end end