2010-10-18 9 views
7

मैंने संकुचित अनुरोध निकायों को स्वचालित रूप से अनजिप करने के लिए रैक मिडलवेयर का एक टुकड़ा लिखा था। कोड ठीक काम कर रहा है, लेकिन जब मैं इसे अपने रेल ऐप में प्लग करता हूं, तो मुझे एक्शनकंट्रोलर :: पैराम्स पार्सर से "अमान्य JSON" विफलता मिलती है।रैक rack.input चर truncated हो रही है?

एक डिबगिंग तंत्र के रूप में, मैं ज़िपित सामग्री दोनों, और अनजिप सामग्री को एक फ़ाइल में लिख रहा हूं (यह सुनिश्चित करने के लिए कि कोड ठीक से काम कर रहा है) और मुझे अपना मूल JSON दस्तावेज़ प्राप्त होता है (क्लाइंट इसे ज़िप करने से पहले)।

मैं जो डेटा पोस्ट कर रहा हूं JSON डेटा है, और अनजिप सामग्री को http://jsonlint.com से वैध JSON के रूप में पहचाना जाता है।

कोई विचार क्या मैं गलत कर रहा हूं?

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

    def call(env) 
    input = env['rack.input'].read 

    #output the zipped data we received 
    File.open('/Users/ben/Desktop/data.gz', 'w+') do |f| 
     f.write input 
    end 

    if env['REQUEST_METHOD'] =~ /(POST|PUT)/ 
     if env.keys.include? 'HTTP_CONTENT_ENCODING' 
     new_input = decode(input, env['HTTP_CONTENT_ENCODING']) 
     env['rack.input'] = StringIO.new(new_input) 

     #output our decoded data (for debugging) 
     File.open('/Users/ben/Desktop/data.txt', 'w+') do |f| 
      f.write env['rack.input'].read 
     end 

     env.delete('HTTP_CONTENT_ENCODING') 
     end 
    end 

    env['rack.input'].rewind 
    status, headers, response = @app.call(env) 
    return [status, headers, response] 
    end 

    def decode(input, content_encoding) 
    if content_encoding == 'gzip' 
     Zlib::GzipReader.new(input).read 
    elsif content_encoding == 'deflate' 
     Zlib::Inflate.new.inflate new input 
    else 
     input 
    end 
    end 
end 

यहाँ त्रुटि है कि मैं कंसोल से हो रही है है सूचना का

Contents::"2010-05-17T12:46:30Z","background":false},{"longitude":-95.38620785000001,"latitude":29.62815358333334,"estimated_speed":14.04305,"timestamp":"2010-05-17T12:46:36Z","background":false},{"longitude":-95.3862767,"latitude":29.62926725,"estimated_speed":39.87791,"timestamp":"2010-05-17T12:46:42Z","background":false},{"longitude":-95.38655023333334,"latitude":29.63051011666666,"estimated_speed":46.09239,"timestamp":"2010-05-17T12:46:49Z","background":false},{"longitude":-95.38676226666666,"latitude":29.63158775,"estimated_speed":47.34936,"timestamp":"2010-05-17T12:46:55Z","background":false},{"longitude":-95.38675346666666,"latitude":29.63219841666666,"estimated_speed":22.54016,"timestamp":"2010-05-17T12:47:03Z","background":false},{"longitude":-95.38675491666666,"latitude":29.63265714999999,"estimated_speed":14.03642,"timestamp":"2010-05-17T12:47:10Z","background":false},{"longitude":-95.38677551666666,"latitude":29.63358661666667,"estimated_speed":29.29489,"timestamp":"2010-05-17T12:47:17Z","background":false},{"longitude":-95.38679026666662,"latitude":29.63466445,"estimated_speed":38.34926,"timestamp":"2010-05-17T12:47:24Z","background":false},{"longitude":-95.38681656666668,"latitude":29.63590941666666,"estimated_speed":44.82093,"timestamp":"2010-05-17T12:47:31Z","background":false},{"longitude":-95.38683366666667,"latitude":29.63679638333334,"estimated_speed":40.21729,"timestamp":"2010-05-17T12:47:37Z","background":false},{"longitude":-95.38685133333333,"latitude":29.63815714999999,"estimated_speed":44.86543,"timestamp":"2010-05-17T12:47:44Z","background":false},{"longitude":-95.3868655 
/!\ FAILSAFE /!\ Mon Oct 18 18:18:43 -0500 2010 
    Status: 500 Internal Server Error 
    Invalid JSON string 
    /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/json/backends/yaml.rb:14:in `decode' 
    /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/json/decoding.rb:11:in `__send__' 
    /Library/Ruby/Gems/1.8/gems/activesupport-2.3.5/lib/active_support/json/decoding.rb:11:in `decode' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:42:in `parse_formatted_parameters' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/params_parser.rb:11:in `call' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/session/cookie_store.rb:93:in `call' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/failsafe.rb:26:in `call' 
    /Users/ben/projects/safecell/safecellweb/lib/compressed_requests.rb:36:in `call' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `synchronize' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/lock.rb:11:in `call' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:114:in `call' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/reloader.rb:34:in `run' 
    /Library/Ruby/Gems/1.8/gems/actionpack-2.3.5/lib/action_controller/dispatcher.rb:108:in `call' 
    /Library/Ruby/Gems/1.8/gems/rails-2.3.5/lib/rails/rack/static.rb:31:in `call' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:46:in `call' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `each' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/urlmap.rb:40:in `call' 
    /Library/Ruby/Gems/1.8/gems/rails-2.3.5/lib/rails/rack/log_tailer.rb:17:in `call' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/content_length.rb:13:in `call' 
    /Library/Ruby/Gems/1.8/gems/rack-1.0.1/lib/rack/handler/webrick.rb:50:in `service' 

एक आखिरी टुकड़ा, मैं ActionController :: फेलसेफ के बाद इस मिडलवेयर डालने कर रहा हूँ।

संपादित करें: प्रतीत होता है कि यह सब के बाद एक काट-छांट समस्या नहीं है की तरह लग रहा है, यह एक काट-छांट समस्या

अधिक खुदाई के बाद नहीं है की तरह। लॉग बस आउटपुट को क्लिप कर रहे हैं ताकि एक छंटनी समस्या की तरह दिखता है।

इस बिंदु पर मुझे यकीन नहीं है कि JSON क्यों अमान्य में आ रहा है। क्या मुझे कोई मैन्युअल भागने की ज़रूरत है?

उत्तर

15

मैं किसी भी खिंचाव से रूबी विशेषज्ञ नहीं हूं। मैंने अपने परिणामों को सत्यापित करने के लिए इस समस्या को दोबारा करने की कोशिश भी नहीं की है। लेकिन रैक और एक्शनपैक कोड के माध्यम से खोदने के बाद, मेरे पास कुछ हो सकता है।

"rack.input" के लिए दस्तावेज़ कहता है: "इनपुट स्ट्रीम एक आईओ-जैसी वस्तु है जिसमें कच्चे HTTP पोस्ट डेटा होते हैं।"

तो आप इसे सही तरीके से उपयोग कर रहे हैं, ऐसा प्रतीत होता है।

हालांकि, actionpack शरीर से बाहर JSON पार्स करने के लिए (यदि सामग्री प्रकार JSON के रूप में निर्दिष्ट किया जाता है) की कोशिश करता है और इस तरह शरीर को पुन: प्राप्त:

when :json 
    body = request.raw_post 

जहां "अनुरोध" actionpack के अपने अनुरोध वर्ग है, और "raw_post" इस तरह परिभाषित किया गया है:

def raw_post 
    unless @env.include? 'RAW_POST_DATA' 
    @env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i) 
    body.rewind if body.respond_to?(:rewind) 
    end 
    @env['RAW_POST_DATA'] 
end 

और "Request.body" है:

def body 
    if raw_post = @env['RAW_POST_DATA'] 
    raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding) 
    StringIO.new(raw_post) 
    else 
    @env['rack.input'] 
    end 
end 

यह सब ठीक दिखता है और अच्छा लगता है (हालांकि यह समझने में भ्रमित है कि पहले मूल्य कैश करता है :))। यह समस्या की तरह लग रहा है कि कैसे पोस्ट डेटा को पढ़ने में है:

@env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i) 

तो मैं समस्या अनुमान लगा रहा हूँ जब से तुम "rack.input" को बदल कर "CONTENT_LENGTH" अद्यतन नहीं करते हैं, actionpack है स्पष्ट रूप से ज़िप्ड सामग्री अनजिप सामग्री से कम हो गई है, इसलिए डेटा को छोटा कर रहा है।

अपने मिडलवेयर कोड में "CONTENT_LENGTH" को अपडेट करने का प्रयास करें और देखें कि यह ठीक करता है या नहीं।

+1

दोस्त आप रॉक करते हैं। वह यह था! यहां अपडेट किया गया कामकाजी कोड है: http://gist.github.com/635471 –

+1

कूल कहानी ब्रो: डी – noodl

+0

एक्सेलेंट स्पष्टीकरण, कि प्रत्येक व्यक्ति कैसे होना चाहिए :) – Pablo