2013-04-02 20 views
10

我們的Ruby on Rails站點有一個URI,表示我們的合作伙伴將XML數據發佈到的URI。Rails/Rack:針對POST數據的「ArgumentError:invalid%-encoding」

由於我們不想處理XML,所以我們只是將原始數據填充到數據庫列中,不要進一步處理它。

然而,我們收到的職位之一給了我們這個錯誤在減速板:

ArgumentError: invalid %-encoding ("http://ns.hr-xml.org/2004-08-02" 
userId="" password=""><BackgroundReportPackage type="report"> 
<ProviderReferenceId>.... 

隨着回溯:

vendor/ruby-1.9.3/lib/ruby/1.9.1/uri/common.rb:898:in `decode_www_form_component' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:41:in `unescape' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:94:in `block (2 levels) in parse_nested_query' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:94:in `map' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:94:in `block in parse_nested_query' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:93:in `each' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/utils.rb:93:in `parse_nested_query' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/request.rb:332:in `parse_query' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/request.rb:209:in `POST' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/methodoverride.rb:26:in `method_override' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/methodoverride.rb:14:in `call' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/runtime.rb:17:in `call' 
vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/cache/strategy/local_cache.rb:72:in `call' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/lock.rb:15:in `call' 
vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.13/lib/action_dispatch/middleware/static.rb:63:in `call' 
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:136:in `forward' 
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:143:in `pass' 
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:155:in `invalidate' 
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:71:in `call!' 
vendor/bundle/ruby/1.9.1/gems/rack-cache-1.2/lib/rack/cache/context.rb:51:in `call' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/engine.rb:479:in `call' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/application.rb:223:in `call' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/railtie/configurable.rb:30:in `method_missing' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/deflater.rb:13:in `call' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/content_length.rb:14:in `call' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/rack/log_tailer.rb:17:in `call' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:80:in `block in pre_process' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:78:in `catch' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:78:in `pre_process' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:53:in `process' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/connection.rb:38:in `receive_data' 
vendor/bundle/ruby/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine' 
vendor/bundle/ruby/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/backends/base.rb:63:in `start' 
vendor/bundle/ruby/1.9.1/gems/thin-1.4.1/lib/thin/server.rb:159:in `start' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/handler/thin.rb:13:in `run' 
vendor/bundle/ruby/1.9.1/gems/rack-1.4.5/lib/rack/server.rb:268:in `start' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/server.rb:70:in `start' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:55:in `block in <top (required)>' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:50:in `tap' 
vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:50:in `<top (required)>' 
script/rails:6:in `require' 
script/rails:6:in `<main>' 

的問題是,POST包含數據:

<ChargeOrComplaint>DRIVE WHILE BLOOD ALCOHOL LEVEL IS 0.08% OR MORE</ChargeOrComplaint> 

推測這是有效的XML,但在年底裸正在導致錯誤,因爲它是通過HTTP傳遞的,我猜機架期望它被URL編碼。

回溯表明這種情況發生之前,它甚至到達我們的代碼,所以我不認爲它與我們如何處理它有任何關係。我的問題,然後:

1)問題在哪裏? Ruby 1.9.3的實現decode_www_form_component(位於堆棧跟蹤的頂部)?架?我們的合作伙伴的POST數據或標題?我們如何處理POST?

2)通過HTTP發佈的XML數據是否需要進行URL編碼?

3)有沒有這個POST需要讓Rack正確解釋它的頭文件? (即:它是XML二進制數據,而不是URL編碼)。

4)如果我無法讓我們的合作伙伴更改他們發佈給我們的內容,我們該如何解決它?一些Rack中間件?

+2

我遇到了這個確切的問題。你最終找到了解決方案嗎? –

回答

7

我猜你的伴侶可能是以「x-www-form-urlencoded」的形式發佈數據給你,使Rack試圖以這種方式解析它。如果他們可以改變他們發送的內容,我懷疑他們的內容類型「text/xml」會解決這個問題。

如果你不能讓他們改變他們發送的內容,那麼是的,我認爲你必須使用Rack中間件(或monkeypatching)。雖然你可以圍繞Rack源碼進行探索,但也許有一種設置可以避免進行任何分析。

+4

我認爲如果Rack是一個POST並且沒有Content-Type頭部,我認爲這個請求是'x-www-form-urlencoded',所以這是你看到的行爲,如果合作伙伴沒有指定任何內容請鍵入:https://github.com/rack/rack/blob/1.4.5/lib/rack/request.rb#L171 – matt

0

在我的情況下,原因是標題之後和請求正文之前的額外換行符。我猜測存在Content-Length不一致的問題,它會拋出解析器。如果您以編程方式設置標題,請確保它們沒有尾隨換行符。

1

在各種論壇上,關於在請求主體內容中捕獲無效編碼錯誤的責任在哪裏存在一些爭議,但機架和導軌都無法處理它,都將它留給應用程序處理。若要在POST數據無效左右-encoding%在我的應用程序,我用了一個類似的解決方案來此相關的問題:Rails ArgumentError: invalid %-encoding

app/middleware/invalid_post_data_interceptor.rb加入這個中間件攔截無效後數據:

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

    def call(env) 
    request_content = Rack::Request.new(env).POST rescue :bad_form_data 

    headers = {'Content-Type' => 'text/plain'} 

    if request_content == :bad_form_data 
     [400, headers, ['Bad Request']] 
    else 
     @app.call(env) 
    end 
    end 
end 

然後加入它通過加入到中間件堆棧application.rb

config.middleware.insert_before Rack::Runtime, "InvalidPostDataInterceptor"