Module: StreamlyFFI::Base

Included in:
PersistentRequest, Request
Defined in:
lib/streamly_ffi/base.rb

Constant Summary collapse

DEFAULT_CURL_ENCODING =
"identity, deflate, gzip"

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#default_header_handlerObject

Returns the value of attribute default_header_handler.



5
6
7
# File 'lib/streamly_ffi/base.rb', line 5

def default_header_handler
  @default_header_handler
end

#default_write_handlerObject

Returns the value of attribute default_write_handler.



5
6
7
# File 'lib/streamly_ffi/base.rb', line 5

def default_write_handler
  @default_write_handler
end

#methodObject Also known as: __method__

Returns the value of attribute method.



5
6
7
# File 'lib/streamly_ffi/base.rb', line 5

def method
  @method
end

#urlObject

Returns the value of attribute url.



5
6
7
# File 'lib/streamly_ffi/base.rb', line 5

def url
  @url
end

Instance Method Details

#connectionObject



114
115
116
# File 'lib/streamly_ffi/base.rb', line 114

def connection
  @connection ||= CurlFFI::Easy.new
end

#custom_header_callback(string_ptr, size, nmemb) ⇒ Object



171
172
173
174
175
176
177
# File 'lib/streamly_ffi/base.rb', line 171

def custom_header_callback(string_ptr, size, nmemb)
  length  = size * nmemb
  @_hcall = string_ptr.read_string(length)
  @custom_header_handler.call(string_ptr.read_string(length).dup)

  return length
end

#custom_write_callback(string_ptr, size, nmemb) ⇒ Object



163
164
165
166
167
168
169
# File 'lib/streamly_ffi/base.rb', line 163

def custom_write_callback(string_ptr, size, nmemb)
  length  = size * nmemb
  @_wcall = string_ptr.read_string(length)
  @custom_write_handler.call(string_ptr.read_string(length).dup)

  return length
end

#default_header_callback(string_ptr, size, nmemb) ⇒ Object



156
157
158
159
160
161
# File 'lib/streamly_ffi/base.rb', line 156

def default_header_callback(string_ptr, size, nmemb)
  length  = size * nmemb
  @response_header << string_ptr.read_string(length).dup

  return length
end

#default_write_callback(string_ptr, size, nmemb) ⇒ Object



149
150
151
152
153
154
# File 'lib/streamly_ffi/base.rb', line 149

def default_write_callback(string_ptr, size, nmemb)
  length  = size * nmemb
  @response_body << string_ptr.read_string(length).dup

  return length
end

#error_bufferObject Also known as: error



118
119
120
# File 'lib/streamly_ffi/base.rb', line 118

def error_buffer
  @error_buffer ||= FFI::MemoryPointer.new(:char, CurlFFI::ERROR_SIZE, :clear)
end

#execute(options = {}) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/streamly_ffi/base.rb', line 9

def execute(options={})
  connection.reset
  set_options(options).perform

  CurlFFI.slist_free_all(@request_headers) if @request_headers

  resp  = if(options.has_key?(:response_header_handler) or options.has_key?(:response_body_handler))
            nil
          elsif(options[:method] == :head && response_header.respond_to?(:to_str))
            response_header
          elsif(response_body.is_a?(String))
            response_body
          else
            nil
          end

  return resp
end

#performObject



28
29
30
# File 'lib/streamly_ffi/base.rb', line 28

def perform
  connection.perform
end

#request_headersObject



123
124
125
# File 'lib/streamly_ffi/base.rb', line 123

def request_headers
  @request_headers ||= FFI::MemoryPointer.new(:pointer)
end

#response_bodyObject Also known as: response, body



127
128
129
# File 'lib/streamly_ffi/base.rb', line 127

def response_body
  @response_body ||= ""
end

#response_headerObject Also known as: headers



133
134
135
# File 'lib/streamly_ffi/base.rb', line 133

def response_header
  @response_header ||= ""
end

#set_header_handler(_callback = :default_header_callback) ⇒ Object



144
145
146
147
# File 'lib/streamly_ffi/base.rb', line 144

def set_header_handler(_callback=:default_header_callback)
  @_header_handler = FFI::Function.new(:size_t, [:pointer, :size_t, :size_t], &self.__method__(_callback))
  connection.setopt(:HEADERFUNCTION, @_header_handler)
end

#set_headers(headers) ⇒ Object

Set/add request headers in Curl’s slist

@param [Hash, Array<Hash>, Set<Hash>] headers Any number of headers to be added to curl's slist. Ultimate form
  must be a Hash; multiple Hashes with the same key (and different value) can be placed in an Array, if desired.


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/streamly_ffi/base.rb', line 35

def set_headers(headers)
  case headers
  when Hash
    headers.each_pair do |k_v|
      self.request_headers = CurlFFI.slist_append(self.request_headers, k_v.join(": "))
    end
  when Array, Set
    headers.each do |header|
      header.each_pair do |k_v|
        self.request_headers = CurlFFI.slist_append(self.request_headers, k_v.join(": "))
      end
    end
  end
  return self.request_headers
end

#set_options(options = {}) ⇒ Object

def set_headers



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/streamly_ffi/base.rb', line 51

def set_options(options={})
  @url      = options[:url].dup     if options.has_key?(:url)     # Make sure @url is set, if not
  @method   = options[:method]      if options.has_key?(:method)  # Make sure @method is set, if not
  @payload  = options[:payload].dup if options.has_key?(:payload)

  @response_body          = nil
  @response_header        = nil
  @custom_header_handler  = nil
  @custom_write_handler   = nil

  # url should be a string that doesn't suck
  # method should be :post, :get, :put, :delete, :head
  # options should contain any of the following keys:
  #   :headers, :response_header_handler, :response_body_handler, :payload (required if method = :post / :put)

  case @method
  when :get     then  connection.setopt :HTTPGET,        1
  when :head    then  connection.setopt :NOBODY,         1
  when :post    then  connection.setopt :POST,           1
                      connection.setopt :POSTFIELDS,     @payload
                      connection.setopt :POSTFIELDSIZE,  @payload.size
  when :put     then  connection.setopt :CUSTOMREQUEST,  "PUT"
                      connection.setopt :POSTFIELDS,     @payload
                      connection.setopt :POSTFIELDSIZE,  @payload.size
  when :delete  then  connection.setopt :CUSTOMREQUEST,  "DELETE"
  # else I WILL CUT YOU
  end

  if options.has_key?(:headers)
    connection.setopt(:HTTPHEADER, set_headers(options[:headers])) unless options[:headers].nil?
  end

  if options.has_key?(:response_header_handler)
    @custom_header_handler = options[:response_header_handler]
    set_header_handler(:custom_header_callback)
  else
    @response_header = ""
    set_header_handler
  end

  if options.has_key?(:response_body_handler)
    @custom_write_handler = options[:response_body_handler]
    set_write_handler(:custom_write_callback)
  else
    @response_body = ""
    set_write_handler
  end

  connection.setopt :ENCODING,        DEFAULT_CURL_ENCODING unless @method == :head
  connection.setopt :URL,             @url

  # Other common options (blame streamly guy)
  connection.setopt :FOLLOWLOCATION,  1
  connection.setopt :MAXREDIRS,       3
  # @TODO: This should be an option
  connection.setopt :SSL_VERIFYPEER,  0
  connection.setopt :SSL_VERIFYHOST,  0

  connection.setopt :ERRORBUFFER,     self.error_buffer

  return self
end

#set_write_handler(_callback = :default_write_callback) ⇒ Object



138
139
140
141
142
# File 'lib/streamly_ffi/base.rb', line 138

def set_write_handler(_callback=:default_write_callback)
  @_write_handler = FFI::Function.new(:size_t, [:pointer, :size_t, :size_t,], &self.__method__(_callback))

  connection.setopt(:WRITEFUNCTION, @_write_handler)
end