Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

[Patch] XML Mini Parser NoMethodError :getc when application running through Phusion Passenger

#4437

Rails Version: 3.0.0 beta 3
Scenario: ActiveResource from Rails App #1 Migrations will not run on a fresh database calling to a controller on Rails App #2 rake rails:freeze:edge on windows with #create action. Rails App #2 rake rails:freeze:edge on windows was running through Phusion Passenger, and was returning this:

NoMethodError (private method getc' called for<br/>

<PhusionPassenger::Utils::RewindableInput:0x1044e22d0>):

Asked Hongli (thread: http://groups.google.com/group/phusion-passenger/browse_thread/thre...) about this, and apparently the data input stream fed into the Rack app doesn't need to be able to respond to getc.

This error does not occur if App is running through script/server.

Problem: http://github.com/rails/rails/commit/69bc2043f93890048e415dd7c5f1fe...

Here is the patch for your consideration.

Sorry if it's a bit of a hack as this is my first contrib. Thanks - Simon

Reported by Simon Chiu · April 19th, 2010 @ 05:17 AM

State: committed
Milestone: none
Assigned to: Jeremy Kemper Jeremy Kemper
Importance: none

Activity

  1. Hongli Lai
    Hongli Lai

    Instead of referring to Phusion Passenger specifically, you should refer to Rack, because Phusion Passenger is just implementing the Rack specification and the restriction is in Rack.

    April 19th, 2010 @ 09:39 AM

  2. Simon Chiu
    Simon Chiu

    Agreed, it should be referred to the rack.input rather than Passenger specifically. Updated the patch to reflect that in the tests. Libxml and Nokogiri parsers have also been updated.

    April 19th, 2010 @ 12:50 PM

  3. Simon Chiu
    Simon Chiu
    • Title changed from XML Mini Parser NoMethodError :getc when application running through Phusion Passenger to [Patch] XML Mini Parser NoMethodError :getc when application running through Phusion Passenger

    April 21st, 2010 @ 02:26 PM

  4. ieuser
    ieuser

    applied the patch to rails3 beta3 but still get

    PhusionPassenger::Utils::RewindableInput is not a valid input stream. It must walk like either a String, an IO, or a Source.

    April 26th, 2010 @ 06:00 PM

  5. Simon Chiu
    Simon Chiu

    ieuser, Which XML parser backend are you using with your Rails 3 app?

    April 27th, 2010 @ 12:51 PM

  6. Si
    Si

    Hi Simon, I just tried the patch and get the same error:

    PhusionPassenger::Utils::RewindableInput is not a valid input stream.  It must walk like either a String, an IO, or a Source.
    

    I'm using rexml and here's the backtrace:

    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/source.rb:22:in `create_from'
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/parsers/baseparser.rb:146:in `stream='
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/parsers/baseparser.rb:123:in `initialize'
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:9:in `new'
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:9:in `initialize'
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/document.rb:230:in `new'
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/document.rb:230:in `build'
    /Users/Si/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize'
    vendor/rails/activesupport/lib/active_support/xml_mini/rexml.rb:38:in `new'
    vendor/rails/activesupport/lib/active_support/xml_mini/rexml.rb:38:in `parse'
    vendor/rails/activesupport/lib/active_support/xml_mini.rb:13:in `parse'
    

    April 27th, 2010 @ 04:27 PM

  7. Jan Kubr
    Jan Kubr

    You'll need to call .read on the received data before passing it to REXML::Document.new. Something like this seems to work:

    def parse(data)
      if !data.respond_to?(:read)
        data = StringIO.new(data || '')
      end
    
      str = data.gets
      if str.nil?
        {}
      else
        data.rewind
        silence_warnings { require 'rexml/document' } unless defined?(REXML::Document)
        doc = REXML::Document.new(data.read)
    
        if doc.root
          merge_element!({}, doc.root)
        else
          raise REXML::ParseException,
            "The document #{doc.to_s.inspect} does not have a valid root"
        end
      end
    end
    

    April 28th, 2010 @ 10:54 AM

  8. Simon Chiu
    Simon Chiu

    I wonder if this is one of those incompatibilities with Ruby 1.8 vs 1.9. I was using 1.8.7 when I came across this error, but the patch seemed to have fixed it. I will try and use 1.9-head tonight and see if I can duplicate the problem.

    Just in case, can someone post an example XML which caused the error for them?

    April 28th, 2010 @ 12:25 PM

  9. Si
    Si

    Even something minimal like will do it.

    If I use NokogiriSAX as my XmlMini backend, your patch works as hoped however.

    April 28th, 2010 @ 01:12 PM

  10. Si
    Si

    Ha! I should have used preview :)

    Even something minimal like

    <oops/>
    

    will do it.

    April 28th, 2010 @ 01:14 PM

  11. Gaël Deest
    Gaël Deest

    Any update on this ? I'm seeing this bug too and it is pretty annoying.

    May 4th, 2010 @ 11:11 PM

  12. Simon Chiu
    Simon Chiu

    Gael, are you also using Ruby 1.9.2-head?

    May 5th, 2010 @ 04:46 AM

  13. Gaël Deest
    Gaël Deest

    Nope, I'm using Ruby Enterprise Edition 1.8.7 with rack 1.1.0 on the remote (ActiveResource) server, behind SSL and HTTP basic authentication. Switching the XmlMini backend from REXML to Nokogiri did not help.

    If I'm understanding the issue correctly, the XML sent by the client can not be parsed because the XML parser expects the rack object to respond to unknown 'getc' and 'ungetc' methods. So this probably affects any XML controller and I would expect more people to complain. Perhaps there is something special in our setup (such as SSL) that triggers the problem ?

    May 5th, 2010 @ 09:00 AM

  14. Simon Chiu
    Simon Chiu

    Gael,

    I'm just curious what is preventing your set up from working.

    Try putting this Gist in your initializer directory and see if it works: http://gist.github.com/373797

    Simon

    May 5th, 2010 @ 11:03 AM

  15. Gaël Deest
    Gaël Deest

    Your monkey patch seems to work. Thanks !

    May 5th, 2010 @ 06:06 PM

  16. Simon Chiu
    Simon Chiu

    Okay, I will look at the patch and see if I messed up somewhere. Thanks Gael.

    May 5th, 2010 @ 06:37 PM

  17. Gaël Deest
    Gaël Deest

    Oh, I had not applied your patch yet so it may be perfectly fine. Thanks to your for taking some time to address this issue !

    May 6th, 2010 @ 08:01 AM

  18. Lawrence Pit
    Lawrence Pit
    • Tag changed from active_resource, passenger, rack, xml_mini to actiondispatch, active_resource, passenger, rack, rails3, xml_mini
    • Assigned user set to Jeremy Kemper

    This shouldn't be solved by patching the xmlmini classes.

    The issue only occurs in development mode. This is because Rack adds the middleware Rack::Lint when in development mode, which results in all input to Rails being wrapped into a Rack::Lint::InputWrapper. This is not an IO class, and therefor fails as input into all the XML parsers.

    Attached is a patch to solve this issue.

    Note: at this moment it's not possible to add a proper test for this, as rack's Rack::MockRequest always returns a StringIO stream for env['rack.input']. I'm currently working on a patch for Rack to remedy this, as I think tests should work with Rack::Lint::InputWrapper instances instead (which would then show the current xml tests failing without the attached patch): StringIO basically doesn't comply with the Rack specification.

    May 6th, 2010 @ 12:46 PM

  19. Mat Schaffer
    Mat Schaffer

    Just thought I'd mention that we've hit this running in production mode as well. Thanks for your work on this, looking forward to a fix.

    May 6th, 2010 @ 02:40 PM

  20. Gaël Deest
    Gaël Deest

    I too met this bug in production.

    May 6th, 2010 @ 04:12 PM

  21. Jeremy Kemper
    Jeremy Kemper
    • State changed from new to open

    Sounds like our only option for streaming parsing is to provide an IO wrapper than treats getc as read. Nasty.

    Patch + test welcome to read the full IO to a string first instead, reverting the streaming behavior.

    May 6th, 2010 @ 06:45 PM

  22. Lawrence Pit
    Lawrence Pit

    Mat and Gael, it /is/ possible that you get this issue in production as well, because any rack middleware that adds itself and wraps the input which strictly conforms to the Rack protocol will cause this issue.

    May 7th, 2010 @ 01:48 AM

  23. Lawrence Pit
    Lawrence Pit

    Jeremy, attached patch with test.

    May 7th, 2010 @ 01:49 AM

  24. Lawrence Pit
  25. Mat Schaffer
    Mat Schaffer

    Thanks for the clarification, Lawrence. If it helps, the app in question is using Rack::URLMap in config.ru (for switching between the main app and Resque::Server) as well as HoptoadNotifier::Rack in production.rb as middleware.

    I'll try out some of these patches and let you know if I find anything. Thanks!

    May 7th, 2010 @ 02:43 AM

  26. Mat Schaffer
    Mat Schaffer

    That rackinput.diff patch seems to do the trick for my app. Good find, Lawrence!

    I also did a test app without any middleware and was able to produce this under Passenger (development and production envs). Seems that the Rack environment in Passenger is a little more strict than others.

    Thanks again.

    May 7th, 2010 @ 03:34 AM

  27. Repository