motion/http.rb in bubble-wrap-1.1.2 vs motion/http.rb in bubble-wrap-1.1.3

- old
+ new

@@ -17,44 +17,43 @@ # BubbleWrap::HTTP.get("https://api.github.com/users/mattetti", {credentials: {username: 'matt', password: 'aimonetti'}}) do |response| # p response.body.to_str # prints the response's body # end # def self.get(url, options={}, &block) - options[:action] = block if block_given? - HTTP::Query.new(url, :get, options) + create_query(url, :get, options, block) end # Make a POST request def self.post(url, options={}, &block) - options[:action] = block if block_given? - HTTP::Query.new(url, :post, options) + create_query(url, :post, options, block) end # Make a PUT request def self.put(url, options={}, &block) - options[:action] = block if block_given? - HTTP::Query.new(url, :put, options) + create_query(url, :put, options, block) end # Make a DELETE request def self.delete(url, options={}, &block) - options[:action] = block if block_given? - HTTP::Query.new(url, :delete, options) + create_query(url, :delete, options, block) end # Make a HEAD request def self.head(url, options={}, &block) - options[:action] = block if block_given? - HTTP::Query.new(url, :head, options) + create_query(url, :head, options, block) end # Make a PATCH request def self.patch(url, options={}, &block) - options[:action] = block if block_given? - HTTP::Query.new(url, :patch, options) + create_query(url, :patch, options, block) end + def self.create_query(url, method, options, block) + options[:action] = block if block + HTTP::Query.new(url, method, options) + end + # Response class wrapping the results of a Query's response class Response attr_reader :body attr_reader :headers attr_accessor :status_code, :error_message @@ -93,11 +92,11 @@ attr_reader :response attr_reader :status_code attr_reader :response_headers attr_reader :response_size attr_reader :options - + CLRF = "\r\n" # ==== Parameters # url<String>:: url of the resource to download # http_method<Symbol>:: Value representing the HTTP method to use # options<Hash>:: optional options used for the query # @@ -125,11 +124,11 @@ @response = HTTP::Response.new @url = create_url(url_string) @body = create_request_body @request = create_request - set_content_type + @connection = create_connection(request, self) @connection.start UIApplication.sharedApplication.networkActivityIndicatorVisible = true end @@ -155,19 +154,22 @@ download_progress.call(@received_data.length.to_f, response_size) end end def connection(connection, willSendRequest:request, redirectResponse:redirect_response) - @redirection ||= 0 - @redirection += 1 - log "##{@redirection} HTTP redirection: #{request} - #{self.description}" - new_request = request.mutableCopy - # new_request.setValue(@credentials.inspect, forHTTPHeaderField:'Authorization') # disabled while we figure this one out - new_request.setAllHTTPHeaderFields(@headers) if @headers - @connection.cancel - @connection = create_connection(new_request, self) - new_request + @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" + @request.done_loading! + call_delegator_with_response + nil + else + request + end end def connection(connection, didFailWithError: error) log "HTTP Connection failed #{error.localizedDescription}" UIApplication.sharedApplication.networkActivityIndicatorVisible = false @@ -210,106 +212,118 @@ request = NSMutableURLRequest.requestWithURL(@url, cachePolicy:@cache_policy, timeoutInterval:@timeout) request.setHTTPMethod(@method) + set_content_type request.setAllHTTPHeaderFields(@headers) request.setHTTPBody(@body) patch_nsurl_request(request) request end + def set_content_type + return if headers_provided? + return if (@method == "GET" || @method == "HEAD") + @headers ||= {} + @headers["Content-Type"] = case @format + when :json + "application/json" + when :xml + "application/xml" + when :text + "text/plain" + else + if @format == :form_data || @payload_or_files_were_appended + "multipart/form-data; boundary=#{@boundary}" + else + "application/x-www-form-urlencoded" + end + end + end + + def headers_provided? + @headers && @headers.keys.find {|k| k.downcase == 'content-type'} + end + def create_request_body return nil if (@method == "GET" || @method == "HEAD") return nil unless (@payload || @files) body = NSMutableData.data append_payload(body) if @payload append_files(body) if @files - append_body_boundary(body) if @set_body_to_close_boundary + append_body_boundary(body) if @payload_or_files_were_appended log "Built HTTP body: \n #{body.to_str}" body end - def set_content_type - # if no headers provided, set content-type automatically - if @headers.nil? || !@headers.keys.find {|k| k.downcase == 'content-type'} - @headers ||= {} - @headers["Content-Type"] = case @format - when :json - "application/json" - when :xml - "application/xml" - when :text - "text/plain" - else - if @format == :form_data || @set_body_to_close_boundary - "multipart/form-data; boundary=#{@boundary}" - else - "application/x-www-form-urlencoded" - end - end - end - end - def append_payload(body) if @payload.is_a?(NSData) body.appendData(@payload) + elsif @payload.is_a?(String) + body.appendData(@payload.dataUsingEncoding NSUTF8StringEncoding) else append_form_params(body) end body end def append_form_params(body) - # puts "*** append_form #{@payload}" - if @payload.is_a?(String) - body.appendData(@payload.dataUsingEncoding NSUTF8StringEncoding) - else - list = process_payload_hash(@payload) - list.each do |key, value| - form_data = NSMutableData.new - s = "\r\n--#{@boundary}\r\n" - s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n" - s += value.to_s - form_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding) - body.appendData(form_data) - end - @set_body_to_close_boundary = true + list = process_payload_hash(@payload) + list.each do |key, value| + form_data = NSMutableData.new + s = "--#{@boundary}\r\n" + s += "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n" + s += value.to_s + s += "\r\n" + form_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding) + body.appendData(form_data) end + @payload_or_files_were_appended = true body end def append_files(body) @files.each do |key, value| file_data = NSMutableData.new - s = "\r\n--#{@boundary}\r\n" + s = "--#{@boundary}\r\n" s += "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{key}\"\r\n" s += "Content-Type: application/octet-stream\r\n\r\n" file_data.appendData(s.dataUsingEncoding NSUTF8StringEncoding) file_data.appendData(value) + file_data.appendData("\r\n".dataUsingEncoding NSUTF8StringEncoding) body.appendData(file_data) end - @set_body_to_close_boundary = true + @payload_or_files_were_appended = true body end def append_body_boundary(body) - body.appendData("\r\n--#{@boundary}--\r\n".dataUsingEncoding NSUTF8StringEncoding) + body.appendData("--#{@boundary}--\r\n".dataUsingEncoding NSUTF8StringEncoding) end def create_url(url_string) if (@method == "GET" || @method == "HEAD") && @payload convert_payload_to_url if @payload.is_a?(Hash) url_string += "?#{@payload}" end - NSURL.URLWithString(url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding) + url = NSURL.URLWithString(url_string.stringByAddingPercentEscapesUsingEncoding NSUTF8StringEncoding) + + validate_url(url) + url end + def validate_url(url) + if !NSURLConnection.canHandleRequest(NSURLRequest.requestWithURL(url)) + raise InvalidURLError, "Invalid URL provided (Make sure you include a valid URL scheme, e.g. http:// or similar)." + end + end + def convert_payload_to_url params_array = process_payload_hash(@payload) params_array.map! { |key, value| "#{key}=#{value}" } @payload = params_array.join("&") end @@ -340,18 +354,18 @@ def escape_line_feeds(hash) return nil if hash.nil? escaped_hash = {} - hash.each{|k,v| escaped_hash[k] = v.gsub("\n", '\\n') } + hash.each{|k,v| escaped_hash[k] = v.gsub("\n", CLRF) } escaped_hash end def patch_nsurl_request(request) request.instance_variable_set("@done_loading", false) - def request.done_loading; @done_loading; end + def request.done_loading?; @done_loading; end def request.done_loading!; @done_loading = true; end end def call_delegator_with_response if @delegator.respond_to?(:call) @@ -365,5 +379,7 @@ end end end end + +class InvalidURLError < StandardError; end