Skip to content

When providing parameters to execute(), + is replaced by space #56

@GoogleCodeExporter

Description

@GoogleCodeExporter
Call execute() using google-api-ruby-client version 0.4.5:

result = @client.execute(
   api_method: @calendar.events.list,
   parameters: {
      calendarId: calendar_id,
      timeMax: "2012-08-29T00:00:00+02:00",
      timeMin: "2012-08-28T00:00:00+02:00"
   })

timeMax & timeMin parameters are replaced internally by:
2012-08-29T00:00:00 02:00

which then is encoded to 2012-07-29T00%3A00%3A00+02%3A00

The end result is a bad request because Google Calendar API wants 
2012-07-29T00%3A00%3A00%2B02%3A00



After some debugging, it appears that Faraday 0.8.4 does this :

    # File faraday/utils.rb 

    # Adapted from Rack
    def parse_query(qs)
      params = {}

      (qs || '').split(DEFAULT_SEP).each do |p|
        k, v = p.split('=', 2).map { |x| unescape(x) }        <---------

        if cur = params[k]
          if cur.class == Array then params[k] << v
          else params[k] = [cur, v]
          end
        else
          params[k] = v
        end
      end
      params
    end


unescape() method is from file cgi/util.rb from Ruby stdlib:

  # File cgi/util.rb

  # URL-decode a string with encoding(optional).
  #   string = CGI::unescape("%27Stop%21%27+said+Fred")
  #      # => "'Stop!' said Fred"
  def CGI::unescape(string,encoding=@@accept_charset)
    str=string.tr('+', ' ').force_encoding(Encoding::ASCII_8BIT).gsub(/((?:%[0-9a-fA-F]{2})+)/) do
      [$1.delete('%')].pack('H*')
    end.force_encoding(encoding)
    str.valid_encoding? ? str : str.force_encoding(string.encoding)
  end


As you see unescape replaces '+' by ' ' (space) and this causes the issue.

parse_query() from Faraday is being called by api_client/discovery/method.rb 
generate_request()

      # File api_client/discovery/method.rb
      def generate_request(parameters={}, body='', headers=[], options={})
        options[:connection] ||= Faraday.default_connection
        if body.respond_to?(:string)
          body = body.string
        elsif body.respond_to?(:to_str)
          body = body.to_str
        else
          raise TypeError, "Expected String or StringIO, got #{body.class}."
        end
        if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
          raise TypeError, "Expected Hash or Array, got #{headers.class}."
        end
        method = self.http_method
        uri = self.generate_uri(parameters)
        headers = headers.to_a if headers.kind_of?(Hash)
        return options[:connection].build_request(
          method.to_s.downcase.to_sym
        ) do |req|
          req.url(Addressable::URI.parse(uri).normalize.to_s)
          req.url(uri.to_s)        <---------
          req.headers = Faraday::Utils::Headers.new(headers)
          req.body = body
        end
      end


Original issue reported on code.google.com by tkrotoff on 30 Aug 2012 at 7:36

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions