bubble-wrap-http 1.6.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: aefaa21254b706e9bfc9fae4fb19435f0ef526bd
4
+ data.tar.gz: 662e834e0a96c3b04e919beed10f108898a7a49f
5
+ SHA512:
6
+ metadata.gz: d3d5ae993ee8cd50cbcd539eb501ca53dd82ea0d135500488380ba1f101ee40091de9c3855633c386fb0772e551be237ba8ee6f4e755bddcdf9f031ce8061293
7
+ data.tar.gz: e133ca52ac112ef4c12ea92d732b663c73066c9910999b798f8cbabab6bfb823d13417bc1fc985a064d183a175dfbcdb336c76b16b5f5ddfd9fcd84955fc3567
data/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # BubbleWrap::HTTP
2
+
3
+ [![Build Status](https://travis-ci.org/rubymotion/BubbleWrap-HTTP.svg?branch=master)](https://travis-ci.org/rubymotion/BubbleWrap-HTTP)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```
10
+ gem 'bubble-wrap-http'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ gem install bubble-wrap-http
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ `BubbleWrap::HTTP` wraps `NSURLRequest`, `NSURLConnection` and friends to provide Ruby developers with a more familiar and easier to use API.
28
+ The API uses async calls and blocks to stay as simple as possible.
29
+
30
+ To enable it add the following require line to your `Rakefile`:
31
+ ```ruby
32
+ require 'bubble-wrap-http'
33
+ ```
34
+
35
+ Usage example:
36
+
37
+ ```ruby
38
+ BubbleWrap::HTTP.get("https://api.github.com/users/mattetti") do |response|
39
+ p response.body.to_str
40
+ end
41
+ ```
42
+
43
+ ```ruby
44
+ BubbleWrap::HTTP.get("https://api.github.com/users/mattetti", {credentials: {username: 'matt', password: 'aimonetti'}}) do |response|
45
+ p response.body.to_str # prints the response's body
46
+ end
47
+ ```
48
+
49
+ ```ruby
50
+ data = {first_name: 'Matt', last_name: 'Aimonetti'}
51
+ BubbleWrap::HTTP.post("http://foo.bar.com/", {payload: data}) do |response|
52
+ if response.ok?
53
+ json = BW::JSON.parse(response.body.to_str)
54
+ p json['id']
55
+ elsif response.status_code.to_s =~ /40\d/
56
+ App.alert("Login failed")
57
+ else
58
+ App.alert(response.error_message)
59
+ end
60
+ end
61
+ ```
62
+
63
+ To upload files to a server, provide a `files:` hash:
64
+
65
+ ```ruby
66
+ data = {token: "some-api-token"}
67
+ avatar_data = UIImagePNGRepresentation(UIImage.imageNamed("some-image"))
68
+ avatar = { data: avatar_data, filename: "some-image.png", content_type: "image/png" }
69
+
70
+ BubbleWrap::HTTP.post("http://foo.bar.com/", {payload: data}, files: { avatar: avatar }) do |response|
71
+ if response.ok?
72
+ # files are uploaded
73
+ end
74
+ end
75
+ ```
76
+
77
+ A `:download_progress` option can also be passed. The expected object
78
+ would be a Proc that takes two arguments: a float representing the
79
+ amount of data currently received and another float representing the
80
+ total amount of data expected.
81
+
82
+ Connections can also be cancelled. Just keep a refrence,
83
+
84
+ ```ruby
85
+ @conn = BubbleWrap::HTTP.get("https://api.github.com/users/mattetti") do |response|
86
+ p response.body.to_str
87
+ end
88
+ ```
89
+
90
+ and send the `cancel` method to it asynchronously as desired. The block will not be executed.
91
+
92
+ ```ruby
93
+ @conn.cancel
94
+ ```
95
+
96
+ ### Gotchas
97
+
98
+ Because of how RubyMotion currently works, you sometimes need to assign objects as `@instance_variables` in order to retain their callbacks.
99
+
100
+ For example:
101
+
102
+ ```ruby
103
+ class HttpClient
104
+ def get_user(user_id, &callback)
105
+ BubbleWrap::HTTP.get(user_url(user_id)) do |response|
106
+ # ..
107
+ end
108
+ end
109
+ end
110
+ ```
111
+
112
+ This class should be invoked in your code as:
113
+
114
+ ```ruby
115
+ @http_client = HttpClient.new
116
+ @http_client.get_user(user_id) do |user|
117
+ # ..
118
+ end
119
+ ```
120
+
121
+ (instead of doing an instance-variable-less `HttpClient.new.get_user`)
122
+
123
+ ## Contributing
124
+
125
+ 1. Fork it
126
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
127
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
128
+ 4. Push to the branch (`git push origin my-new-feature`)
129
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ lib_dir_path = File.expand_path(File.join(File.dirname(File.expand_path(__FILE__)), '..'))
8
+ Motion::Project::App.setup do |app|
9
+ app.files.unshift(Dir.glob(File.join(lib_dir_path, "motion/**/*.rb")))
10
+ end
data/motion/http.rb ADDED
@@ -0,0 +1,101 @@
1
+ module BubbleWrap
2
+
3
+ # The HTTP module provides a simple interface to make HTTP requests.
4
+ #
5
+ # TODO: preflight support, easier/better cookie support, better error handling
6
+ module HTTP
7
+
8
+ # Make a GET request and process the response asynchronously via a block.
9
+ #
10
+ # @examples
11
+ # # Simple GET request printing the body
12
+ # BubbleWrap::HTTP.get("https://api.github.com/users/mattetti") do |response|
13
+ # p response.body.to_str
14
+ # end
15
+ #
16
+ # # GET request with basic auth credentials
17
+ # BubbleWrap::HTTP.get("https://api.github.com/users/mattetti", {credentials: {username: 'matt', password: 'aimonetti'}}) do |response|
18
+ # p response.body.to_str # prints the response's body
19
+ # end
20
+ #
21
+
22
+ [:get, :post, :put, :delete, :head, :options, :patch].each do |http_verb|
23
+
24
+ define_singleton_method(http_verb) do |url, options = {}, &block|
25
+ options[:action] = block if block
26
+ HTTP::Query.new(url, http_verb, options)
27
+ end
28
+
29
+ end
30
+
31
+ module Patch
32
+ module_function
33
+ def use_weak_callbacks?
34
+ if BubbleWrap.respond_to?("use_weak_callbacks?")
35
+ return BubbleWrap.use_weak_callbacks?
36
+ end
37
+ true
38
+ end
39
+
40
+ def ios?
41
+ Kernel.const_defined?(:UIApplication)
42
+ end
43
+
44
+ def osx?
45
+ Kernel.const_defined?(:NSApplication)
46
+ end
47
+
48
+ def debug?
49
+ if BubbleWrap.respond_to?("debug?")
50
+ return BubbleWrap.debug?
51
+ end
52
+ false
53
+ end
54
+
55
+ def create_uuid
56
+ uuid = CFUUIDCreate(nil)
57
+ CFUUIDCreateString(nil, uuid)
58
+ end
59
+
60
+ module JSON
61
+ module_function
62
+ def generate(obj)
63
+ NSJSONSerialization.dataWithJSONObject(obj, options:0, error:nil).to_str
64
+ end
65
+
66
+ def parse(str_data, &block)
67
+ return nil unless str_data
68
+ data = str_data.respond_to?(:to_data) ? str_data.to_data : str_data
69
+ opts = NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves | NSJSONReadingAllowFragments
70
+ error = Pointer.new(:id)
71
+ obj = NSJSONSerialization.JSONObjectWithData(data, options:opts, error:error)
72
+ raise ParserError, error[0].description if error[0]
73
+ if block_given?
74
+ yield obj
75
+ else
76
+ obj
77
+ end
78
+ end
79
+ end
80
+
81
+ module NetworkIndicator
82
+ module_function
83
+ def show
84
+ if BubbleWrap.const_defined?("NetworkIndicator")
85
+ BubbleWrap::NetworkIndicator.show
86
+ end
87
+ end
88
+
89
+ def hide
90
+ if BubbleWrap.const_defined?("NetworkIndicator")
91
+ BubbleWrap::NetworkIndicator.hide
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+ end
99
+
100
+ class InvalidURLError < StandardError; end
101
+ class InvalidFileError < StandardError; end
@@ -0,0 +1,412 @@
1
+ # Class wrapping NSConnection and often used indirectly by the BubbleWrap::HTTP module methods.
2
+ module BubbleWrap; module HTTP; class Query
3
+ attr_accessor :request
4
+ attr_accessor :connection
5
+ attr_accessor :credentials # username & password has a hash
6
+ attr_accessor :proxy_credential # credential supplied to proxy servers
7
+ attr_accessor :post_data
8
+ attr_reader :method
9
+
10
+ attr_reader :response
11
+ attr_reader :status_code
12
+ attr_reader :response_headers
13
+ attr_reader :response_size
14
+ attr_reader :options
15
+ CLRF = "\r\n"
16
+ # ==== Parameters
17
+ # url<String>:: url of the resource to download
18
+ # http_method<Symbol>:: Value representing the HTTP method to use
19
+ # options<Hash>:: optional options used for the query
20
+ #
21
+ # ==== Options
22
+ # :payload<String> - data to pass to a POST, PUT, DELETE query.
23
+ # :action - Proc, class or object to call when the file is downloaded.
24
+ # a proc will receive a Response object while the passed object
25
+ # will receive the handle_query_response method
26
+ # :headers<Hash> - headers send with the request
27
+ # :cookies<Boolean> - Set whether cookies should be sent with request or not (Default: true)
28
+ # Anything else will be available via the options attribute reader.
29
+ #
30
+ def initialize(url_string, http_method = :get, options={})
31
+ @method = http_method.upcase.to_s
32
+ @delegator = options.delete(:action) || self
33
+ if @delegator.respond_to?("weak!")
34
+ @delegator.weak! if BubbleWrap::HTTP::Patch.use_weak_callbacks?
35
+ end
36
+
37
+ @payload = options.delete(:payload)
38
+ @encoding = options.delete(:encoding) || NSUTF8StringEncoding
39
+ @files = options.delete(:files)
40
+ @boundary = options.delete(:boundary) || BubbleWrap::HTTP::Patch.create_uuid
41
+ @credentials = options.delete(:credentials) || {}
42
+ @credentials = {:username => nil, :password => nil}.merge(@credentials)
43
+ @timeout = options.delete(:timeout) || 30.0
44
+ @headers = escape_line_feeds(options.delete :headers)
45
+ @format = options.delete(:format)
46
+ @cache_policy = options.delete(:cache_policy) || NSURLRequestUseProtocolCachePolicy
47
+ @credential_persistence = options.delete(:credential_persistence) || NSURLCredentialPersistenceForSession
48
+ @cookies = options.key?(:cookies) ? options.delete(:cookies) : true
49
+ @options = options
50
+ @response = BubbleWrap::HTTP::Response.new
51
+ @follow_urls = options[:follow_urls] || true
52
+ @present_credentials = options[:present_credentials] == nil ? true : options.delete(:present_credentials)
53
+
54
+ @url = create_url(url_string)
55
+ @body = create_request_body
56
+ @request = create_request
57
+ @original_url = @url.copy
58
+
59
+ @connection = create_connection(request, self)
60
+ @connection.scheduleInRunLoop(NSRunLoop.currentRunLoop, forMode:NSRunLoopCommonModes)
61
+ @connection.start
62
+
63
+ show_status_indicator true
64
+ end
65
+
66
+ def to_s
67
+ "#<#{self.class}:#{self.object_id} - Method: #{@method}, url: #{@url.description}, body: #{@body.description}, Payload: #{@payload}, Headers: #{@headers} Credentials: #{@credentials}, Timeout: #{@timeout}, \
68
+ Cache policy: #{@cache_policy}, response: #{@response.inspect} >"
69
+ end
70
+ alias description to_s
71
+
72
+ def done?
73
+ @did_fail_error || @did_finish_loading || @canceled
74
+ end
75
+
76
+ def connection(connection, didReceiveResponse:response)
77
+ # On OSX, if using an FTP connection, this method will fire *immediately* after creating an
78
+ # NSURLConnection, even if the connection has not yet started. The `response`
79
+ # object will be a NSURLResponse, *not* an `NSHTTPURLResponse`, and so will start to crash.
80
+ if BubbleWrap::HTTP::Patch.osx? && !response.is_a?(NSHTTPURLResponse)
81
+ return
82
+ end
83
+ did_receive_response(response)
84
+ end
85
+
86
+ # This delegate method get called every time a chunk of data is being received
87
+ def connection(connection, didReceiveData:received_data)
88
+ @received_data ||= NSMutableData.new
89
+ @received_data.appendData(received_data)
90
+
91
+ if download_progress = options[:download_progress]
92
+ download_progress.call(@received_data.length.to_f, response_size)
93
+ end
94
+ end
95
+
96
+ def connection(connection, willSendRequest:request, redirectResponse:redirect_response)
97
+ # abort early if the user has explicitly disabled redirects
98
+ if @options[:no_redirect] and redirect_response then
99
+ return nil
100
+ end
101
+ @redirect_count ||= 0
102
+ @redirect_count += 1
103
+ log "##{@redirect_count} HTTP redirect_count: #{request.inspect} - #{self.description}"
104
+
105
+ if @redirect_count >= 30
106
+ error = NSError.errorWithDomain('BubbleWrap::HTTP', code:NSURLErrorHTTPTooManyRedirects,
107
+ userInfo:NSDictionary.dictionaryWithObject("Too many redirections",
108
+ forKey: NSLocalizedDescriptionKey))
109
+ self.connection(connection, didFailWithError: error)
110
+ nil
111
+ else
112
+ @url = request.URL if @follow_urls
113
+ request
114
+ end
115
+ end
116
+
117
+ def connection(connection, didFailWithError: error)
118
+ return if done?
119
+
120
+ @did_fail_error = error
121
+ log "HTTP Connection to #{@url.absoluteString} failed #{error.localizedDescription}"
122
+ show_status_indicator false
123
+ @request.done_loading!
124
+ @response.error = error
125
+ @response.error_message = error.localizedDescription
126
+ call_delegator_with_response
127
+ end
128
+
129
+ def connection(connection, didSendBodyData:sending, totalBytesWritten:written, totalBytesExpectedToWrite:expected)
130
+ if upload_progress = options[:upload_progress]
131
+ upload_progress.call(sending, written, expected)
132
+ end
133
+ end
134
+
135
+ def connectionDidFinishLoading(connection)
136
+ return if done?
137
+ @did_finish_loading = true
138
+
139
+ show_status_indicator false
140
+ @request.done_loading!
141
+ response_body = NSData.dataWithData(@received_data) if @received_data
142
+ @response.update(status_code: status_code, body: response_body, headers: response_headers, url: @url, original_url: @original_url)
143
+
144
+ call_delegator_with_response
145
+ end
146
+
147
+ def connection(connection, didReceiveAuthenticationChallenge:challenge)
148
+ if (challenge.previousFailureCount == 0)
149
+ if credentials[:username].to_s.empty? && credentials[:password].to_s.empty?
150
+ challenge.sender.continueWithoutCredentialForAuthenticationChallenge(challenge)
151
+ log 'Continue without credentials to get 401 status in response'
152
+ else
153
+ new_credential = NSURLCredential.credentialWithUser(credentials[:username], password:credentials[:password], persistence:@credential_persistence)
154
+ challenge.sender.useCredential(new_credential, forAuthenticationChallenge:challenge)
155
+ log "auth challenged, answered with credentials: #{credentials.inspect}"
156
+ end
157
+ else
158
+ did_receive_response(challenge.failureResponse)
159
+ @response.update(status_code: status_code, headers: response_headers, url: @url, original_url: @original_url)
160
+ challenge.sender.cancelAuthenticationChallenge(challenge)
161
+ log 'Auth Failed :('
162
+ end
163
+ end
164
+
165
+ def cancel
166
+ return if done?
167
+ @canceled = true
168
+
169
+ @connection.cancel
170
+ show_status_indicator false
171
+ @request.done_loading!
172
+ end
173
+
174
+ private
175
+
176
+ def did_receive_response(response)
177
+ @status_code = response.statusCode
178
+ @response_headers = response.allHeaderFields
179
+ @response_size = response.expectedContentLength.to_f
180
+ end
181
+
182
+ def show_status_indicator(show)
183
+ if BubbleWrap::HTTP::Patch.ios? && (@status.nil? || @status != !!show)
184
+ @status = !!show
185
+ if show
186
+ BubbleWrap::HTTP::Patch::NetworkIndicator.show
187
+ else
188
+ BubbleWrap::HTTP::Patch::NetworkIndicator.hide
189
+ end
190
+ end
191
+ end
192
+
193
+ def create_request
194
+ log "BubbleWrap::HTTP building a NSRequest for #{@url.description}"
195
+
196
+ request = NSMutableURLRequest.requestWithURL(@url,
197
+ cachePolicy:@cache_policy,
198
+ timeoutInterval:@timeout)
199
+ request.setHTTPMethod(@method)
200
+ set_content_type
201
+ append_auth_header
202
+ request.setAllHTTPHeaderFields(@headers)
203
+ request.setHTTPBody(@body)
204
+ request.setHTTPShouldHandleCookies(@cookies)
205
+ patch_nsurl_request(request)
206
+
207
+ request
208
+ end
209
+
210
+ def set_content_type
211
+ return if headers_provided?
212
+ return if (@method == "GET" || @method == "HEAD" || @method == "OPTIONS")
213
+ @headers ||= {}
214
+ @headers["Content-Type"] = case @format
215
+ when :json
216
+ "application/json"
217
+ when :xml
218
+ "application/xml"
219
+ when :text
220
+ "text/plain"
221
+ else
222
+ if @format == :form_data || @payload_or_files_were_appended
223
+ "multipart/form-data; boundary=#{@boundary}"
224
+ else
225
+ "application/x-www-form-urlencoded"
226
+ end
227
+ end
228
+ end
229
+
230
+ def headers_provided?
231
+ @headers && @headers.keys.find {|k| k.downcase == 'content-type'}
232
+ end
233
+
234
+ def credentials_provided?
235
+ @credentials[:username] && @credentials[:password]
236
+ end
237
+
238
+ def create_request_body
239
+ return nil if (@method == "GET" || @method == "HEAD" || @method == "OPTIONS")
240
+ return nil unless (@payload || @files)
241
+
242
+ body = NSMutableData.data
243
+
244
+ append_payload(body) if @payload
245
+ append_files(body) if @files
246
+ append_body_boundary(body) if @payload_or_files_were_appended
247
+
248
+ log "Built HTTP body: \n #{body.to_str}"
249
+ body
250
+ end
251
+
252
+ def append_payload(body)
253
+ if @payload.is_a?(NSData)
254
+ body.appendData(@payload)
255
+ elsif @payload.is_a?(String)
256
+ body.appendData encode_to_data(@payload, @encoding)
257
+ elsif @format == :json
258
+ json_string = BubbleWrap::HTTP::Patch::JSON.generate(@payload)
259
+ body.appendData encode_to_data(json_string, @encoding)
260
+ else
261
+ append_form_params(body)
262
+ end
263
+ body
264
+ end
265
+
266
+ def append_form_params(body)
267
+ list = process_payload_hash(@payload)
268
+ list.each do |key, value|
269
+ s = "--#{@boundary}\r\n"
270
+ s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
271
+ s += value.to_s
272
+ s += "\r\n"
273
+ body.appendData encode_to_data(s, @encoding)
274
+ end
275
+ @payload_or_files_were_appended = true
276
+ body
277
+ end
278
+
279
+ def append_auth_header
280
+ return if @headers && @headers["Authorization"]
281
+
282
+ if credentials_provided? && @present_credentials
283
+ mock_request = CFHTTPMessageCreateRequest(nil, nil, nil, nil)
284
+ CFHTTPMessageAddAuthentication(mock_request, nil, @credentials[:username], @credentials[:password], KCFHTTPAuthenticationSchemeBasic, false)
285
+
286
+ @headers ||= {}
287
+ @headers["Authorization"] = CFHTTPMessageCopyHeaderFieldValue(mock_request, "Authorization")
288
+ end
289
+ end
290
+
291
+ def parse_file(key, value)
292
+ value = {data: value} unless value.is_a?(Hash)
293
+ raise(InvalidFileError, "You need to supply a `:data` entry in #{value} for file '#{key}' in your HTTP `:files`") if value[:data].nil?
294
+ {
295
+ data: value[:data],
296
+ filename: value.fetch(:filename, key),
297
+ content_type: value.fetch(:content_type, "application/octet-stream")
298
+ }
299
+ end
300
+
301
+ def append_files(body)
302
+ @files.each do |key, value|
303
+ file = parse_file(key, value)
304
+ s = "--#{@boundary}\r\n"
305
+ s += "Content-Disposition: attachment; name=\"#{key}\"; filename=\"#{file[:filename]}\"\r\n"
306
+ s += "Content-Type: #{file[:content_type]}\r\n\r\n"
307
+ file_data = NSMutableData.new
308
+ file_data.appendData encode_to_data(s, @encoding)
309
+ file_data.appendData(file[:data])
310
+ file_data.appendData encode_to_data("\r\n", @encoding)
311
+ body.appendData(file_data)
312
+ end
313
+ @payload_or_files_were_appended = true
314
+ body
315
+ end
316
+
317
+ def append_body_boundary(body)
318
+ body.appendData encode_to_data("--#{@boundary}--\r\n", @encoding)
319
+ end
320
+
321
+ def create_url(url_string)
322
+ url_string = url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding
323
+ if (@method == "GET" || @method == "HEAD" || @method == "OPTIONS") && @payload
324
+ unless @payload.empty?
325
+ convert_payload_to_url if @payload.is_a?(Hash)
326
+ url_string += "?#{@payload}"
327
+ end
328
+ end
329
+ url = NSURL.URLWithString(url_string)
330
+
331
+ validate_url(url)
332
+ url
333
+ end
334
+
335
+ def validate_url(url)
336
+ if !NSURLConnection.canHandleRequest(NSURLRequest.requestWithURL(url))
337
+ raise InvalidURLError, "Invalid URL provided (Make sure you include a valid URL scheme, e.g. http:// or similar)."
338
+ end
339
+ end
340
+
341
+ def escape(string)
342
+ string_to_escape = string.to_s
343
+ if string_to_escape
344
+ CFURLCreateStringByAddingPercentEscapes nil, string_to_escape, nil, "!*'();:@&=+$,/?%#[]", KCFStringEncodingUTF8
345
+ end
346
+ end
347
+
348
+ def convert_payload_to_url
349
+ params_array = process_payload_hash(@payload)
350
+ params_array.map! { |key, value| "#{escape key}=#{escape value}" }
351
+ @payload = params_array.join("&")
352
+ end
353
+
354
+ def process_payload_hash(payload, prefix=nil)
355
+ list = []
356
+ payload.each do |k,v|
357
+ if v.is_a?(Hash)
358
+ new_prefix = prefix ? "#{prefix}[#{k.to_s}]" : k.to_s
359
+ param = process_payload_hash(v, new_prefix)
360
+ list += param
361
+ elsif v.is_a?(Array)
362
+ v.each do |val|
363
+ param = prefix ? "#{prefix}[#{k.to_s}][]" : "#{k.to_s}[]"
364
+ if val.is_a?(Hash)
365
+ list += process_payload_hash(val, param)
366
+ else
367
+ list << [param, val]
368
+ end
369
+ end
370
+ else
371
+ param = prefix ? "#{prefix}[#{k.to_s}]" : k.to_s
372
+ list << [param, v]
373
+ end
374
+ end
375
+ list
376
+ end
377
+
378
+ def log(message)
379
+ NSLog message if BubbleWrap::HTTP::Patch.debug?
380
+ end
381
+
382
+ def escape_line_feeds(hash)
383
+ return nil if hash.nil?
384
+ escaped_hash = {}
385
+
386
+ hash.each{|k,v| escaped_hash[k] = v.gsub("\n", CLRF) if v }
387
+ escaped_hash
388
+ end
389
+
390
+ def patch_nsurl_request(request)
391
+ request.instance_variable_set("@done_loading", false)
392
+
393
+ def request.done_loading?; @done_loading; end
394
+ def request.done_loading!; @done_loading = true; end
395
+ end
396
+
397
+ def call_delegator_with_response
398
+ if @delegator.respond_to?(:call)
399
+ @delegator.call( @response, self )
400
+ end
401
+ end
402
+
403
+ # This is a temporary method used for mocking.
404
+ def create_connection(request, delegate)
405
+ NSURLConnection.alloc.initWithRequest(request, delegate:delegate, startImmediately:false)
406
+ end
407
+
408
+ def encode_to_data(string, encoding)
409
+ string.dataUsingEncoding encoding
410
+ end
411
+
412
+ end; end; end
@@ -0,0 +1,32 @@
1
+ # Response class wrapping the results of a Query's response
2
+ module BubbleWrap; module HTTP; class Response
3
+ attr_reader :body
4
+ attr_reader :headers
5
+ attr_accessor :status_code, :status_description, :error_message, :error
6
+ attr_reader :url
7
+ attr_reader :original_url
8
+
9
+ def initialize(values={})
10
+ self.update(values)
11
+ end
12
+
13
+ def update(values)
14
+ values.each do |k,v|
15
+ self.instance_variable_set("@#{k}", v)
16
+ end
17
+ update_status_description
18
+ end
19
+
20
+ def ok?
21
+ status_code.to_s =~ /2\d\d/ ? true : false
22
+ end
23
+
24
+ def to_s
25
+ "#<#{self.class}:#{self.object_id} - url: #{self.url}, body: #{self.body}, headers: #{self.headers}, status code: #{self.status_code}, error message: #{self.error_message} >"
26
+ end
27
+ alias description to_s
28
+
29
+ def update_status_description
30
+ @status_description = status_code.nil? ? nil : NSHTTPURLResponse.localizedStringForStatusCode(status_code)
31
+ end
32
+ end; end; end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bubble-wrap-http
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.6.0.rc1
5
+ platform: ruby
6
+ authors:
7
+ - Matt Aimonetti
8
+ - Francis Chong
9
+ - James Harton
10
+ - Clay Allsopp
11
+ - Dylan Markow
12
+ - Jan Weinkauff
13
+ - Marin Usalj
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+ date: 2014-04-16 00:00:00.000000000 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: rake
21
+ requirement: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - '>='
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ type: :development
27
+ prerelease: false
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ description: BubbleWrap's deprecated HTTP library
34
+ email:
35
+ - mattaimonetti@gmail.com
36
+ - francis@ignition.hk
37
+ - james@sociable.co.nz
38
+ - clay.allsopp@gmail.com
39
+ - dylan@dylanmarkow.com
40
+ - jan@dreimannzelt.de
41
+ - mneorr@gmail.com
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - README.md
47
+ - lib/bubble-wrap-http.rb
48
+ - motion/http/query.rb
49
+ - motion/http/response.rb
50
+ - motion/http.rb
51
+ homepage: https://github.com/rubymotion/BubbleWrap-HTTP
52
+ licenses:
53
+ - MIT
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>'
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.1
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 2.0.3
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: BubbleWrap's deprecated HTTP library
75
+ test_files: []