jschementi / iron

[Jimmy Schementi's development fork] Implementations of Python and Ruby programming languages for .NET Framework that are built on top of the Dynamic Language Runtime.
http://ironruby.net
17 stars 2 forks source link

Camping and IronRuby #24

Closed jschementi closed 14 years ago

jschementi commented 15 years ago

Reported by Philippe Monnet:

As I continued get my Camping app to work in IronRuby Rack, I noticed that I kept getting the following error when a form was POST-ed to the server: [InvalidOperationException: can't convert System::String into String] Microsoft.Scripting.Interpreter.ThrowInstruction.Run(InterpretedFrame frame) +58 Microsoft.Scripting.Interpreter.Interpreter.RunInstructions(InterpretedFrame frame) +90 Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame) +278 Microsoft.Scripting.Interpreter.LightLambda.Run2(T0 arg0, T1 arg1) +341 IronRuby.Runtime.RubyScriptCode.Run(Scope scope, Boolean bindGlobals) +293 IronRuby.Runtime.RubyScriptCode.Run(Scope scope) +39 Microsoft.Scripting.SourceUnit.Execute(Scope scope, ErrorSink errorSink) +138 Microsoft.Scripting.SourceUnit.Execute(Scope scope) +43 Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope) +75 IronCamping.RubyEngine.Execute(String code, ScriptScope aScope) in E:\DEV\POC\IronCamping\IronCamping\RubyEngine.cs:56 IronCamping.IIS.Handle(Request request, Response response) in E:\DEV\POC\IronCamping\IronCamping\IIS.cs:177 IronCamping.HttpHandler.ProcessRequest(HttpContext context) in E:\DEV\POC\IronCamping\IronCamping\HttpHandler.cs:41 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

As a work-around I found that if I explictly passed the request.Body as a string using the following code to set the rack.input environment variable in the Handle mthod of IIS class, the issue went away:

if (request.Body != null)
{
                // Explicitly pass the request body as a string
                string myInput = request.Body.ToString(); 
                handle_scope.SetVariable("__myinput", myInput);
                env["rack.input"] = RubyEngine.Execute("StringIO.new(__myinput.to_s)", handle_scope);
}
else
{
                // Original code
                env["rack.input"] = RubyEngine.Execute("StringIO.new(__request.body || '')", handle_scope);
}

(Original code in GitHub: http://github.com/ironruby/ironruby/blob/adb33b18780e5f2a7e050fd38ebc58750ec1cf5b/Merlin/Main/Hosts/IronRuby.Rack/IIS.cs)

Is this the right way to go?

jschementi commented 15 years ago

It the whole point is to make sure __request.body is a string, then we can just change the Ruby code to be the following:

StringIO.new(__request.body ? __request.body.to_s : '')
jschementi commented 15 years ago

Fixed here: http://github.com/jschementi/ironruby/commit/e2bd2313c63d9917dbe54e62afe51ea9248da884

techarch commented 15 years ago

Hi Jimmy, actually the reason I converted the request body to a string from C# is that the Ruby code would otherwise blow up when accessing Body. I tried to figure out why but could not. So with the fix you made I still would experience the same issue.

jschementi commented 15 years ago

Yep, you're right. Actually, request.Body should never be null, as the rack spec requires it to respond to a set of methods, which do not exist on NilClass: http://rack.rubyforge.org/doc/SPEC.html. Your actual exception was "can't convert System::String into String", so just making sure that request.Body is a MutableString should be good enough:

SetEnv(env, "rack.input", new StringIO(MutableString.CreateMutable(request.Body, RubyEncoding.Default), IOMode.ReadOnly));

jschementi commented 15 years ago

Change is checked in here: http://github.com/jschementi/ironruby/tree/dev/rackupdate

jschementi commented 14 years ago

However, when MutableString.Create is passed null, the StringIO reading will blow up. This change (cc5bd360e4c55eba96b9d2fed5b605c041632651) makes sure request.Body is always a string.