motion/http/query.rb in bubble-wrap-1.3.0 vs motion/http/query.rb in bubble-wrap-1.4.0
- old
+ new
@@ -1,7 +1,7 @@
# Class wrapping NSConnection and often used indirectly by the BubbleWrap::HTTP module methods.
-class BubbleWrap::HTTP::Query
+module BubbleWrap; module HTTP; class Query
attr_accessor :request
attr_accessor :connection
attr_accessor :credentials # username & password has a hash
attr_accessor :proxy_credential # credential supplied to proxy servers
attr_accessor :post_data
@@ -18,21 +18,22 @@
# http_method<Symbol>:: Value representing the HTTP method to use
# options<Hash>:: optional options used for the query
#
# ==== Options
# :payload<String> - data to pass to a POST, PUT, DELETE query.
- # :delegator - Proc, class or object to call when the file is downloaded.
+ # :action - Proc, class or object to call when the file is downloaded.
# a proc will receive a Response object while the passed object
# will receive the handle_query_response method
# :headers<Hash> - headers send with the request
# :cookies<Boolean> - Set whether cookies should be sent with request or not (Default: true)
# Anything else will be available via the options attribute reader.
#
def initialize(url_string, http_method = :get, options={})
@method = http_method.upcase.to_s
@delegator = options.delete(:action) || self
@payload = options.delete(:payload)
+ @encoding = options.delete(:encoding) || NSUTF8StringEncoding
@files = options.delete(:files)
@boundary = options.delete(:boundary) || BW.create_uuid
@credentials = options.delete(:credentials) || {}
@credentials = {:username => nil, :password => nil}.merge(@credentials)
@timeout = options.delete(:timeout) || 30.0
@@ -68,13 +69,11 @@
# NSURLConnection, even if the connection has not yet started. The `response`
# object will be a NSURLResponse, *not* an `NSHTTPURLResponse`, and so will start to crash.
if App.osx? && !response.is_a?(NSHTTPURLResponse)
return
end
- @status_code = response.statusCode
- @response_headers = response.allHeaderFields
- @response_size = response.expectedContentLength.to_f
+ did_receive_response(response)
end
# This delegate method get called every time a chunk of data is being received
def connection(connection, didReceiveData:received_data)
@received_data ||= NSMutableData.new
@@ -93,11 +92,15 @@
@redirect_count ||= 0
@redirect_count += 1
log "##{@redirect_count} HTTP redirect_count: #{request.inspect} - #{self.description}"
if @redirect_count >= 30
- @response.error_message = "Too many redirections"
+ @response.error = NSError.errorWithDomain('BubbleWrap::HTTP', code:NSURLErrorHTTPTooManyRedirects,
+ userInfo:NSDictionary.dictionaryWithObject("Too many redirections",
+ forKey: NSLocalizedDescriptionKey))
+ @response.error_message = @response.error.localizedDescription
+ show_status_indicator false
@request.done_loading!
call_delegator_with_response
nil
else
@url = request.URL if @follow_urls
@@ -107,10 +110,11 @@
def connection(connection, didFailWithError: error)
log "HTTP Connection to #{@url.absoluteString} failed #{error.localizedDescription}"
show_status_indicator false
@request.done_loading!
+ @response.error = error
@response.error_message = error.localizedDescription
call_delegator_with_response
end
def connection(connection, didSendBodyData:sending, totalBytesWritten:written, totalBytesExpectedToWrite:expected)
@@ -137,19 +141,31 @@
new_credential = NSURLCredential.credentialWithUser(credentials[:username], password:credentials[:password], persistence:@credential_persistence)
challenge.sender.useCredential(new_credential, forAuthenticationChallenge:challenge)
log "auth challenged, answered with credentials: #{credentials.inspect}"
end
else
+ did_receive_response(challenge.failureResponse)
+ @response.update(status_code: status_code, headers: response_headers, url: @url, original_url: @original_url)
challenge.sender.cancelAuthenticationChallenge(challenge)
log 'Auth Failed :('
end
end
+ def cancel
+ @connection.cancel
+ show_status_indicator false
+ @request.done_loading!
+ end
private
- private
+ def did_receive_response(response)
+ @status_code = response.statusCode
+ @response_headers = response.allHeaderFields
+ @response_size = response.expectedContentLength.to_f
+ end
+
def show_status_indicator(show)
if App.ios?
UIApplication.sharedApplication.networkActivityIndicatorVisible = show
end
end
@@ -171,11 +187,11 @@
request
end
def set_content_type
return if headers_provided?
- return if (@method == "GET" || @method == "HEAD")
+ return if (@method == "GET" || @method == "HEAD" || @method == "OPTIONS")
@headers ||= {}
@headers["Content-Type"] = case @format
when :json
"application/json"
when :xml
@@ -198,11 +214,11 @@
def credentials_provided?
@credentials[:username] && @credentials[:password]
end
def create_request_body
- return nil if (@method == "GET" || @method == "HEAD")
+ return nil if (@method == "GET" || @method == "HEAD" || @method == "OPTIONS")
return nil unless (@payload || @files)
body = NSMutableData.data
append_payload(body) if @payload
@@ -215,11 +231,14 @@
def append_payload(body)
if @payload.is_a?(NSData)
body.appendData(@payload)
elsif @payload.is_a?(String)
- body.appendData(@payload.dataUsingEncoding NSUTF8StringEncoding)
+ body.appendData(@payload.to_encoded_data @encoding)
+ elsif @format == :json
+ json_string = BW::JSON.generate(@payload)
+ body.appendData(json_string.to_encoded_data @encoding)
else
append_form_params(body)
end
body
end
@@ -229,11 +248,11 @@
list.each do |key, value|
s = "--#{@boundary}\r\n"
s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
s += value.to_s
s += "\r\n"
- body.appendData(s.dataUsingEncoding NSUTF8StringEncoding)
+ body.appendData(s.to_encoded_data @encoding)
end
@payload_or_files_were_appended = true
body
end
@@ -249,11 +268,11 @@
end
end
def parse_file(key, value)
if value.is_a?(Hash)
- raise InvalidFileError if value[:data].nil?
+ raise(InvalidFileError, "You need to supply a `:data` entry in #{value} for file '#{key}' in your HTTP `:files`") if value[:data].nil?
{data: value[:data], filename: value[:filename] || key}
else
{data: value, filename: key}
end
end
@@ -263,26 +282,26 @@
file = parse_file(key, value)
s = "--#{@boundary}\r\n"
s += "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{file[:filename]}\"\r\n"
s += "Content-Type: application/octet-stream\r\n\r\n"
file_data = NSMutableData.new
- file_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding)
+ file_data.appendData(s.to_encoded_data @encoding)
file_data.appendData(file[:data])
- file_data.appendData("\r\n".dataUsingEncoding NSUTF8StringEncoding)
+ file_data.appendData("\r\n".to_encoded_data @encoding)
body.appendData(file_data)
end
@payload_or_files_were_appended = true
body
end
def append_body_boundary(body)
- body.appendData("--#{@boundary}--\r\n".dataUsingEncoding NSUTF8StringEncoding)
+ body.appendData("--#{@boundary}--\r\n".to_encoded_data @encoding)
end
def create_url(url_string)
url_string = url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding
- if (@method == "GET" || @method == "HEAD") && @payload
+ if (@method == "GET" || @method == "HEAD" || @method == "OPTIONS") && @payload
unless @payload.empty?
convert_payload_to_url if @payload.is_a?(Hash)
url_string += "?#{@payload}"
end
end
@@ -297,12 +316,13 @@
raise InvalidURLError, "Invalid URL provided (Make sure you include a valid URL scheme, e.g. http:// or similar)."
end
end
def escape(string)
- if string
- CFURLCreateStringByAddingPercentEscapes nil, string.to_s, nil, "!*'();:@&=+$,/?%#[]", KCFStringEncodingUTF8
+ string_to_escape = string.to_s
+ if string_to_escape
+ CFURLCreateStringByAddingPercentEscapes nil, string_to_escape, nil, "!*'();:@&=+$,/?%#[]", KCFStringEncodingUTF8
end
end
def convert_payload_to_url
params_array = process_payload_hash(@payload)
@@ -362,6 +382,6 @@
# This is a temporary method used for mocking.
def create_connection(request, delegate)
NSURLConnection.connectionWithRequest(request, delegate:delegate)
end
-end
\ No newline at end of file
+end; end; end