2013-04-29 4 views
34

Im letzten Monat hatten wir einen Bot, der regelmäßig unsere Site scraped, was zu einer Reihe von ArgumentError: invalid %-encoding Fehlern führte, weil die URLs falsch formatiert waren. Ich habe eine Reihe von Problemen im Rack here und here und Schienen here betrachtet, und schaute auf this SO thread, aber es scheint keine endgültige Lösung zu sein. Gibt es eine richtige Lösung für GET-Fehler? Muss ich Rack monkeypatch?Rails ArgumentError: ungültig% -encoding

edit: Und hier ist ein Backtrace:

/usr/local/lib/ruby/1.9.1/uri/common.rb:898:in `decode_www_form_component' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/utils.rb:41:in `unescape' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/utils.rb:94:in `block (2 levels) in parse_nested_query' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/utils.rb:94:in `map' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/utils.rb:94:in `block in parse_nested_query' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/utils.rb:93:in `each' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/utils.rb:93:in `parse_nested_query' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/request.rb:332:in `parse_query' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/http/request.rb:269:in `parse_query' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/request.rb:186:in `GET' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/http/request.rb:225:in `GET' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/http/parameters.rb:10:in `parameters' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/http/filter_parameters.rb:33:in `filtered_parameters' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_controller/metal/instrumentation.rb:21:in `process_action' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_controller/metal/params_wrapper.rb:207:in `process_action' 
[GEM_ROOT]/gems/activerecord-3.2.12/lib/active_record/railties/controller_runtime.rb:18:in `process_action' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/abstract_controller/base.rb:121:in `process' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/abstract_controller/rendering.rb:45:in `process' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_controller/metal.rb:203:in `dispatch' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_controller/metal/rack_delegation.rb:14:in `dispatch' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_controller/metal.rb:246:in `block in action' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/routing/route_set.rb:73:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/routing/route_set.rb:73:in `dispatch' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/routing/route_set.rb:36:in `call' 
[GEM_ROOT]/gems/journey-1.0.4/lib/journey/router.rb:68:in `block in call' 
[GEM_ROOT]/gems/journey-1.0.4/lib/journey/router.rb:56:in `each' 
[GEM_ROOT]/gems/journey-1.0.4/lib/journey/router.rb:56:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/routing/route_set.rb:601:in `call' 
[GEM_ROOT]/gems/omniauth-1.1.1/lib/omniauth/strategy.rb:177:in `call!' 
[GEM_ROOT]/gems/omniauth-1.1.1/lib/omniauth/strategy.rb:157:in `call' 
[GEM_ROOT]/gems/sass-3.2.7/lib/sass/plugin/rack.rb:54:in `call' 
[GEM_ROOT]/gems/warden-1.2.1/lib/warden/manager.rb:35:in `block in call' 
[GEM_ROOT]/gems/warden-1.2.1/lib/warden/manager.rb:34:in `catch' 
[GEM_ROOT]/gems/warden-1.2.1/lib/warden/manager.rb:34:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/best_standards_support.rb:17:in `call' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/etag.rb:23:in `call' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/conditionalget.rb:25:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/head.rb:14:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/params_parser.rb:21:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/flash.rb:242:in `call' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/session/abstract/id.rb:210:in `context' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/session/abstract/id.rb:205:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/cookies.rb:341:in `call' 
[GEM_ROOT]/gems/activerecord-3.2.12/lib/active_record/query_cache.rb:64:in `call' 
[GEM_ROOT]/gems/activerecord-3.2.12/lib/active_record/connection_adapters/abstract/connection_pool.rb:479:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call' 
[GEM_ROOT]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:405:in `_run__497203393471184793__call__4495106819278994598__callbacks' 
[GEM_ROOT]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:405:in `__run_callback' 
[GEM_ROOT]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:385:in `_run_call_callbacks' 
[GEM_ROOT]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:81:in `run_callbacks' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/callbacks.rb:27:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/remote_ip.rb:31:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' 
[GEM_ROOT]/gems/railties-3.2.12/lib/rails/rack/logger.rb:32:in `call_app' 
[GEM_ROOT]/gems/railties-3.2.12/lib/rails/rack/logger.rb:16:in `block in call' 
[GEM_ROOT]/gems/activesupport-3.2.12/lib/active_support/tagged_logging.rb:22:in `tagged' 
[GEM_ROOT]/gems/railties-3.2.12/lib/rails/rack/logger.rb:16:in `call' 
[GEM_ROOT]/gems/actionpack-3.2.12/lib/action_dispatch/middleware/request_id.rb:22:in `call' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/methodoverride.rb:21:in `call' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/runtime.rb:17:in `call' 
[GEM_ROOT]/gems/activesupport-3.2.12/lib/active_support/cache/strategy/local_cache.rb:72:in `call' 
[GEM_ROOT]/gems/rack-1.4.5/lib/rack/lock.rb:15:in `call' 
[GEM_ROOT]/gems/rack-cache-1.2/lib/rack/cache/context.rb:136:in `forward' 
[GEM_ROOT]/gems/rack-cache-1.2/lib/rack/cache/context.rb:143:in `pass' 
[GEM_ROOT]/gems/rack-cache-1.2/lib/rack/cache/context.rb:172:in `rescue in lookup' 
[GEM_ROOT]/gems/rack-cache-1.2/lib/rack/cache/context.rb:168:in `lookup' 
[GEM_ROOT]/gems/rack-cache-1.2/lib/rack/cache/context.rb:66:in `call!' 
[GEM_ROOT]/gems/rack-cache-1.2/lib/rack/cache/context.rb:51:in `call' 
[GEM_ROOT]/gems/railties-3.2.12/lib/rails/engine.rb:479:in `call' 
[GEM_ROOT]/gems/railties-3.2.12/lib/rails/application.rb:223:in `call' 
[GEM_ROOT]/gems/railties-3.2.12/lib/rails/railtie/configurable.rb:30:in `method_missing' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/rack/request_handler.rb:96:in `process_request' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_request_handler.rb:516:in `accept_and_process_next_request' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_request_handler.rb:274:in `main_loop' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/rack/application_spawner.rb:206:in `start_request_handler' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/rack/application_spawner.rb:171:in `block in handle_spawn_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/utils.rb:479:in `safe_fork' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/rack/application_spawner.rb:166:in `handle_spawn_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server.rb:357:in `server_main_loop' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server.rb:206:in `start_synchronously' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server.rb:180:in `start' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/rack/application_spawner.rb:129:in `start' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/spawn_manager.rb:253:in `block (2 levels) in spawn_rack_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server_collection.rb:132:in `lookup_or_add' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/spawn_manager.rb:246:in `block in spawn_rack_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server_collection.rb:82:in `block in synchronize' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server_collection.rb:79:in `synchronize' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/spawn_manager.rb:244:in `spawn_rack_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/spawn_manager.rb:137:in `spawn_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/spawn_manager.rb:275:in `handle_spawn_application' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server.rb:357:in `server_main_loop' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/lib/phusion_passenger/abstract_server.rb:206:in `start_synchronously' 
/usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.13/helper-scripts/passenger-spawn-server:99:in `<main>' 
+0

Kann in der neuesten Rack-Version behoben werden. Scheint ein paar der Fehler, [einschließlich einer, den ich kommentierte] (https://github.com/rack/rack/issues/225#issuecomment-2594611), als ich dieses Problem vor 2 Jahren hatte, wurden geschlossen. Blockiert der Bot eine Option? –

+0

Leider habe ich versucht, auf das neueste Rack upzugraden und sah immer noch das Problem (dann wieder heruntergestuft, weil ich einige andere Edelsteine ​​ausschalten musste). Es kommt von mehreren IP-Adressen herein, so dass es sich zu einem Spiel von Whack-a-Mole entwickelt, und ich hoffe, dass es einen besseren Weg geben muss. :) –

+0

Können Sie ein Backtrace teilen? –

Antwort

5

Sie könnten eine Middleware injizieren entworfen anmutig diese und nicht zu erkennen. Die Grundidee besteht darin, einfach zu versuchen, die Abfragezeichenfolge zu analysieren, und wenn es fehlschlägt, bail out mit einem HTTP 400. Ansonsten erlauben Sie einfach die Anfrage durch.

class RefuseInvalidRequest 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    query = Rack::Utils.parse_nested_query(env['QUERY_STRING'].to_s) rescue :bad_query 
    if query == :bad_query 
     [400, {'Content-Type' => 'text/plain'}, "Bad Request"] 
    else 
     @app.call(env) 
    end 
    end 
end 

Ich habe dies nicht getestet, aber das Konzept sollte funktionieren.

+1

Es funktioniert nicht auf meiner Entwicklungsumgebung. Ich weiß nicht warum, aber es zeigt nur '!! Ungültige Anforderung im Protokoll. Und habe versucht, 'puts 'namens' '' '' def initialize' hinzuzufügen, es wird nicht 'logarithmiert' ausgegeben. nur '!! Ungültige Anfrage. Ja, ich habe 'config.middleware.use (" RefuseInvalidRequest ") zu meiner application.rb hinzugefügt. Haben Sie eine Idee, warum das passiert? – Yana

+0

Vielleicht haben Sie die Middleware nicht hoch genug in Ihren Middleware-Stack injiziert. –

+0

'config.middleware.insert_before Rack :: Runtime," RefuseInvalidRequest "'. Die höchste, die ich einfügen kann. Eigentlich ist es 'Rack :: MiniProfiler' und' Honeybadger'. Aber ich kann nicht davor einfügen. Immer noch die gleiche Ausgabe. Checkout meine alte Frage mit Logs http://StackOverflow.com/Questions/21229499/Custom-Message-oder-Redirection-for-400-Bad-Request-because-of-unexcaped-on-par – Yana

5

wenn Sie nicht gegen monkeypatching Gestell nichts dagegen dann mit diesem Inhalt in config/initializers-Datei (zum Beispiel rack.rb) erstellen:

module Rack 
    module Utils 
    if defined?(::Encoding) 
     def unescape(s, encoding = Encoding::UTF_8) 
     begin 
      URI.decode_www_form_component(s, encoding) 
     rescue ArgumentError 
      URI.decode_www_form_component(URI.encode(s), encoding) 
     end 
     end 
    else 
     def unescape(s, encoding = nil) 
     begin 
      URI.decode_www_form_component(s, encoding) 
     rescue ArgumentError 
      URI.decode_www_form_component(URI.encode(s), encoding) 
     end 
     end 
    end 
    module_function :unescape 
    end 
end 

P. S. Es funktioniert mit Passagier, aber mit Webrick und Thin ist es nicht. Es sieht so aus, als würde sowohl webrick als auch Thin eine Anfrage analysieren, also tritt der Fehler auf, bevor der Initializer geladen wird. Zum Beispiel mit Thin-Fehler passiert in thin-1.6.2/lib/thin/request.rb:84.

Verwandte Themen