bubble-wrap-http 1.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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: []