Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
GoogleCodeExporter opened this issue May 2, 2015 · 6 comments

Comments

@GoogleCodeExporter
Copy link

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

@GoogleCodeExporter
Copy link
Author

Oupsss

Inside generate_request(), you should ignore req.url(uri.to_s), it's me trying 
to understand what was going on :)
The line that calls Faraday and then unescape() is
req.url(Addressable::URI.parse(uri).normalize.to_s)

Original comment by tkrotoff on 30 Aug 2012 at 10:46

@GoogleCodeExporter
Copy link
Author

I don't think it is a bug. + sign should probably not be inside an url.
The solution here is not to pass the local time (+02:00) but the UTC time 
instead:

      result = @client.execute(
        api_method: @calendar.events.list,
        parameters: {
          calendarId: calendar_id,
          timeMin: time_min.utc.iso8601,
          timeMax: time_max.utc.iso8601
        })

timeMin and timeMax are now:
"2012-07-28T22:00:00Z"
so no more + sign.

Original comment by tkrotoff on 31 Aug 2012 at 12:32

@GoogleCodeExporter
Copy link
Author

I'm in complete agreement that avoiding the '+' character is a best practice. 
However, I still consider this a bug. Unfortunately, it's not one that's likely 
to be fixed soon. Way too many dependencies involved in this issue. That said, 
Faraday may end up exposing a mechanism by which handling parameters could be 
delegated to something else.

https://github.com/technoweenie/faraday/issues/182

Original comment by bobaman@google.com on 31 Aug 2012 at 9:03

  • Changed state: Accepted
  • Added labels: Component-Dependencies, Milestone-Release-1.0

@GoogleCodeExporter
Copy link
Author

I'm having a similar issue, but haven't been able to resolve it by using 
.utc.iso6801.

I'm calling:
    @result = client.execute({
                api_method: service.freebusy.query,
                parameters: { 
                  timeMin: Time.now.utc.iso8601,
                  timeMax: 3.days.from_now.utc.iso8601,
                  items: [{id: "#{@calendar.calendar_id}"}]
                },
                headers: {'Content-Type' => 'application/json'}
    })

I'm getting back a 400, "Missing timeMin parameter" error. Am I missing 
something else with how I need to submit these params?

Original comment by forr...@skedipity.com on 12 Dec 2012 at 4:20

@GoogleCodeExporter
Copy link
Author

Finally got this working and the fix was non-intuitive for me:
@result = client.execute({
    api_method: service.freebusy.query,
    body: JSON.dump({
        timeMin: Time.now.utc.iso8601,
        timeMax: 3.days.from_now.utc.iso8601,
        items: [{id: "#{@calendar.calendar_id}"}]
    },
    headers: {'Content-Type' => 'application/json'}
})

Basically, when timeMin was sent in the parameters field, it wasn't interpreted 
correctly, but when sent in the body, it was.

Original comment by forr...@skedipity.com on 12 Dec 2012 at 4:48

@GoogleCodeExporter
Copy link
Author

See https://github.com/google/google-api-ruby-client/issues/38 for further 
updates.

Original comment by sba...@google.com on 8 Apr 2013 at 8:48

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant