Idea: Webshare

I am using the eval function excessively in one of my programs. Is there any real performance drains from using it? Thanks,

Zach

Hello,

···

On Saturday, August 21, 2004, at 07:50 PM, Andreas Schwarz wrote:

I strongly disagree. Request and response are two completely different things; that their implementations _might_ have shared code (though I can't see where) doesn't mean that they have shared data.

The common resource is the connection to the client.

Cheers,

Patrick

Hello,

There are in fact good reasons in favor of the request / response split.
First of all request and response are in fact two different things, so from
that point of view it's not a bad idea to separate them. The interface of a
combined request response instance is likely to get too bloated.

I don't really think that request / response are all that different. They share the connection to the client.

An object with many methods is one kind of bloat. Managing two objects that share the same resource and lifecycle causes another kind of bloat. The latter bloat is the kind that leads to bugs in my code.

For example, the library should delete the Tempfiles containing file uploads (request state) when the final output is written and the connection is closed (response state). A single object with a single lifecycle makes this sort of thing easier to support.

There are
use cases where you only need the response (say, a page that displays the
current time) and there might be others where you don't need the response
(can't think of any at the moment though, some kind of upload maybe :-)).

I don't think the object will mind if you don't call all of its methods. Just ask aString :slight_smile:

Another reason why I liked the separation (in Java) is that you can easily
wrap only one of them (common with filters in Java, but similar things can
be done with Ruby, too); examples are filtering of whitespace from the
response and adding default values for request parameters. If request and
response are encapsulated in a single instance this becomes much more
difficult to do - and the fun goes away. :slight_smile:

You should be able to do this in Narf:

    Web["param"] ||= "a value"

Note that the single object I recommend that you use is the Web module. That way, you don't have to pass anything around! The output filter isn't something I've thought about, but I think it is a good idea.

I don't want to be entirely negative. These are use cases I want to support. I tried designing a Request / Response style interface. I found that the separation made things more difficult for me. I apologize for the earlier <rant />.

Cheers,

Patrick

···

On Saturday, August 21, 2004, at 06:25 PM, Robert Klemme wrote:

Hello,

You know, this is one thing I definitely agree with. In Iowa, I have an
Iowa::Request that encapsulates the request. However, it actually also
encapsulates the response, and I've found it to be a very natural thing that
the same object that brings the request into the app also carries the
response back out of it.

The Iowa::Request is modeled very closely on the mod_ruby Apache::Request,
mostly because it seems like a good, effective, familiar model, and doing so
helped me avoid reimplementing the wheel.

I was checking out Iowa. It looks like you've done alot of work to make Iowa run across multiple servers. It looked pretty nice :slight_smile:

I am working on a model for supporting multiple web servers that is similar to DBI (in my head, at least).

The CGI object would provide the useful methods that make building web apps easier. Each server would have a "CGD" that actually provided the necessary common functionality. Different environments may also have different ways of embedding the application, just like you have iowa_fcgi.rb, iowa_webrick.rb, and mod_iowa.rb.

I'm planning on writing a cgi script and a set of webunit tests, so that I can start writing CGDs for different servers and test that things are working.

Since you've had experience with solving this problem, I'm curious about your opinion. Does this sound like a productive way of attacking this problem?

Cheers,

Patrick

···

On Saturday, August 21, 2004, at 06:17 PM, Kirk Haines wrote:

Hello,

···

On Tuesday, August 24, 2004, at 12:01 AM, T. Onoma wrote:

Time to make it make sense.

Thought's this was intersting. On Matz's blog there was this snippet:

require 'cgi'
require 'fcgi.so'
class CGI
  class Fast < CGI
    CONTINUATION =
    def Fast::new(*args)
      at_exit do
        if CONTINUATION[0]
          CONTINUATION[0].call
        end
      end
      callcc do |c|
        CONTINUATION[0] = c
      end
      fcgi = FCGI::accept
      unless fcgi CONTINUATION[0] = nil
        exit
      end
      $defout = fcgi.out super(*args)
    end
  end
end

Does that make sense? Here's what matz says about it:

<quote>
About how to make correction of the existing CGI program minimum and make it
FastCGI correspondence

Before, such a trick has been written.

  [ above code here ]

I change "require'cgi'" into "require'fcgi'" and think that remarkable CGI
will operate as it is only by rewriting "CGI.new" to "CGI::Fast.new."
</quote>

Thanks, that certainly is a cute trick!

~ Patrick

There are in fact good reasons in favor of the request / response split.
First of all request and response are in fact two different things, so from
that point of view it's not a bad idea to separate them. The interface of a
combined request response instance is likely to get too bloated. There are
use cases where you only need the response (say, a page that displays the
current time) and there might be others where you don't need the response
(can't think of any at the moment though, some kind of upload maybe :-)).

Well, all HTTP requests have responses, though some are pretty spartan
(302, for example)

There's basically two models at work here: the servlet-ish model, with
separation, and the apache request-cycle model, without.

I don't see them as contradictory, particularly. They're two views of
the same thing, eventually.

Apache has "handlers", each of which can snoop on the request at that
moment and tweak it as neccesary for later handlers to get. Its stacking
makes having one, big, durable object that persists the whole cycle
valuable: one can look back on the whole cycle for information on what
to do.

The request-response split also makes sense: they're very different in
some ways. A request has a method, a path, some headers and a body. The
response has a status code, headers, and sometimes a body. It seems a
perfect place to put some inheritance, since there's some shared
implementation (headers and body), and some specific things to each.

Another reason why I liked the separation (in Java) is that you can easily
wrap only one of them (common with filters in Java, but similar things can
be done with Ruby, too); examples are filtering of whitespace from the
response and adding default values for request parameters. If request and
response are encapsulated in a single instance this becomes much more
difficult to do - and the fun goes away. :slight_smile:

Not terribly, actually: in Java, you wrap; in Apache-style, you just
modify in place. (The analogy with gsub() and gsub!() is apparent to me,
at least)

I like the split, since I think all possibilities are available to both.
In one, one gets a req and a resp passed to the method; in the other,
you get req. In one, you have req.body and resp.body, the other is
req.request_body and req.response_body. I think the first is much
cleaner.

What really needs to happen is documentation of the request and response
cycle, and if filters need to happen, document how to add them, and what
hooks are available.

I think the real question is "what use cases are there for hooks,
handlers and filters?". I see several:

  * Filters (ala aspect programming), both header-filters for security,
and body content filters for content adjustment (XHTML2 -> XHTML1.1 for
example)
  * Additional file-type handlers (potentially for .erb, for .cgi, for
fast cgi, possibly.)[1]
  * Implement additional HTTP methods (PUT, DELETE, PROPFIND like DAV)

And then there's the question of how to implement that with the
mountpoint-oriented structure of something like webrick.[2]

Ari
  
[1] Don't let me start on "file extension" based dispatch. I don't like
it at all.

[2] Personally, I like WEBrick a lot. Nice simple structure.

Hello,

I wasn't able to make this continuation trick work for me. It flip flops -- it works the first time, crashes the second time, then mod_fastcgi restarts the process and the cycle repeats.

I wish I could make these continuations work, though.

Cheers,

Patrick

···

On Tuesday, August 24, 2004, at 12:01 AM, T. Onoma wrote:

Time to make it make sense.

Thought's this was intersting. On Matz's blog there was this snippet:

require 'cgi'
require 'fcgi.so'
class CGI
  class Fast < CGI
    CONTINUATION =
    def Fast::new(*args)
      at_exit do
        if CONTINUATION[0]
          CONTINUATION[0].call
        end
      end
      callcc do |c|
        CONTINUATION[0] = c
      end
      fcgi = FCGI::accept
      unless fcgi CONTINUATION[0] = nil
        exit
      end
      $defout = fcgi.out super(*args)
    end
  end
end

Does that make sense? Here's what matz says about it:

<quote>
About how to make correction of the existing CGI program minimum and make it
FastCGI correspondence

Before, such a trick has been written.

  [ above code here ]

I change "require'cgi'" into "require'fcgi'" and think that remarkable CGI
will operate as it is only by rewriting "CGI.new" to "CGI::Fast.new."
</quote>

T.

I haven't much dealt with session support yet; however, cookie support
itself is fine. The problem is that since Ruwiki is written to support
both WEBrick and CGI modes -- and does NOT use cgi.out (come to think
of it, Ruwiki uses very little of CGI.rb) -- I will need to have
compatible cookies for both.

-austin

···

On Sat, 4 Sep 2004 09:12:48 +0900, Patrick May <patrick@hexane.org> wrote:

Hello,
On Thursday, August 19, 2004, at 10:02 PM, Austin Ziegler wrote:
> What do I need? A standard interface for requests and responses that
> lets me treat various backends as if they were effectively the same.
> A way of handling caching might not be bad -- but it needs to be
> smart enough for me to deal with the reality that my most expensive
> cost is rendering the HTML from the Wiki source, but that I have to
> deal with the possiblity that changes to pages *other* than the page
> I'm rendering may require that the current page cache be
> invalidated. I will probably need session support; I will need
> cookie support.
What's right and wrong with cookie and session support in the standard
cgi.rb?

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca
: as of this email, I have [ 6 ] Gmail invitations

Seems to me there is good reason to seperate response from request,
for historical reasons as well as practical/semantic ones. Seperating
data coming in from data going out seems good enough reason to me(and
I also don't see the code redundancy between them).

Coming from the m$ asp world, cgi.rb was the one (of very few) big
burr in my side. Going back to asp of late has been comforting in that
respect (if only that! i want my
dbi,rexml,interpolation,heredoc,dynamic includes... :). I'd wager that
if ruby's cgi were implemented in similar fashion there would be far
fewer posts(from experienced and inexperienced coders) on here
regarding it.

//data in - this aint an array unless i want it to be
sform = Request.Form('var') // overrides Url
surl = Request.Url('var') //asp uses querystring..too long

Session('var') = surl //cant remember how to do that in ruby but it
aint clean.

//out
Response.Write(Session('var'))//puts works but this is more readable

All that seems obvious/transparent to me. It is tried and true
method(at least the distinct request/response) in every app server
i've used (cold fusion,asp,zope,.net,jsp...). To me, these things are
fundamental and wont be easily(or elegantly) extricated from the basic
workings of a web app - data in - data out - that's what we do as web
developers.

As far as an abstraction layer for backend data, that would be a huge
win for the ruby web crowd. Setting a var that would allow me to
say... hold session vars in a db rather than in ram or a file would be
great. I realize the new version has memorystore/pstore etc. Whichever
one you use, the implementation should be the same or similar.

What about application variables? Did i miss them in my ruby
adventures? I sure like/use them in asp/cf.

All web app servers i've seen have caching mechanisms baked in deep
and getting deeper.

Seems to me much could can still be learned from other mature web app
servers. Like them or not, each of them have their wins and warts.
Ruby's cgi is a wart,imo (and i truly mean no dis to the guy/gals[s]
who wrote/write it - i run across few with that level of programming
skill in my world - i just dont like using it) Asp's implementation of
cgi is the best i've used. So there, i said it :wink:

peace

Austin Ziegler <halostatue@gmail.com> wrote in message news:<9e7db91104082120163483bc91@mail.gmail.com>...

···

On Sun, 22 Aug 2004 06:19:08 +0900, Patrick May <patrick@hexane.org> wrote:
> P.S. <rant> About the only cgi design suggestion I see on ruby-talk
> that I outright disagree with is Request / Response.
>
> I experimented with this in Narf, and I think it is a mistake. You end
> up with two objects, with alot of shared implementation code, that
> always go together, split apart for no practical reason. I don't mind
> having Request / Response separated in the documentation, but splitting
> it in the code just adds typing. When will you ever want a request
> without the response? Martin Fowler has a name for this refactoring,
> but I don't have his book.

As someone who thinks that a request/response is a good thing, I'll
first agree with Andreas that while they may share implementations,
they don't share data (which suggests a Request class, a Response
class, and a "Message" class). Separating request and response, to me,
is as simple as the splitting of STDIN, STDOUT, and STDERR. In theory,
I could choose to request from one computer but respond in a different
location -- why should I be restricted to responding to the person who
made the request? (Granted, I can't see why I would do such a thing,
but who knows whether such a feature would be useful?)

-austin

David A. Black wrote:

Hi --

I am playing with different assignment statements and I am using the normal cross-language terinary operator

a = a==1 ? a : -1

Is there a shorter way to cheat this? I am dealing with a Hash and I would like to perhaps do something like:

hsh = { '*' => '(*)' , 'a' => '(1){2}' }
val = "b"
a = hsh[ val ] or hsh['*'] #to give me, a = '(*)'
val = "a"
a = hsh[ val ] or hsh['*'] #to give me, a = '(1){2}'
   
I'm not quite following. What's not working as you'd like exactly?

hsh = { '*' => '(*)' , 'a' => '(1){2}' }
val = "b"
a = hsh[ val ] or hsh['*'] #to give me, a = '(*)'
puts a
val = "a"
a = hsh[ val ] or hsh['*'] #to give me, a = '(1){2}'
puts a

I want the fourth line to output (*) instead it gives me nil.

Zach

···

On Fri, 20 Aug 2004, Zach Dennis wrote:

Patrick May wrote:

Hello,

I strongly disagree. Request and response are two completely different things; that their implementations _might_ have shared code (though I can't see where) doesn't mean that they have shared data.

The common resource is the connection to the client.

Not necessarily; for example one could save response objects in a cache.

Can you give an example of what advantage a combination of request and response would bring in practice?

···

On Saturday, August 21, 2004, at 07:50 PM, Andreas Schwarz wrote:

I don't really think that request / response are all that different.
They share the connection to the client.

Perhaps have both?

  module ClientBehavior; # ...; end
  module RequestBehavior; # ...; end
  module ResponseBehavior; # ...; end

  class Client; include ClientBehavior
    # ...
  end

  class Request; include ClientBehavior, RequestBehavior
    # ...
  end

  class Response; include ClientBehavior, ResponseBehavior
    # ...
  end

  class RoundTrip; include RequestBehavior, ResponseBehavior
    # ...
  end

Use those modules! :slight_smile:

···

--
T.

I took what is essentially a lazy approach. I created a marshallable,
incomplete copy of Apache::Request, basically, because it was familiar to me
already. I then needed a way to populate it with all of the necessary
data. I partitioned the world into two models: mod_ruby and not-mod-ruby-
so-assume-CGI. The mod_ruby world makes it very easy to put all of the
necessary data from the Apache::Request into my copy of Apache::Request.

For the non-mod-ruby world, though, I simply assume that the standard CGI
environment variables will be available, and I use those to fill out the
request object.

The nice thing about that model is that it then makes it trivial to make it
work with any server that provides a CGI-like interface. All it really has
to do is to create a request object, letting the object worry about the
details of how to populate itself with the necessary data, and then send the
object to the application, and it works for most things.

My understanding is that IIS does not work like this, though, so I would
need to do some work to get it to do the right thing with IIS.

Overall, I like the model, though I am certain that it can be improved
upon. So much code to write, and only two hands to do it with.... Anyway,
I would think that for what you are talking about, you would probably do
something somewhat similar in concept.

Let me throw you a wrinkle to think about.

File uploads. If you adopt a model where you are passing a request object
to the webapp, and the webapp may not even be on the same machine as the
webserver, what is the best way to handle uploaded files?

You can't just create a tempfile like the current CGI does. Do you transfer
the data with the request, but then write it to tempfiles on the other
side? Does Drb provide a way that one could write the uploaded files to
tempfiles on the server, but that one could access the tempfiles via the
request object in the webapp? Could be cool. Might be a bad idea.

Kirk Haines

···

On Tue, 24 Aug 2004 04:33:12 +0900, Patrick May wrote

The CGI object would provide the useful methods that make building
web apps easier. Each server would have a "CGD" that actually
provided the necessary common functionality. Different environments
may also have different ways of embedding the application, just like
you have iowa_fcgi.rb, iowa_webrick.rb, and mod_iowa.rb.

"Aredridel" <aredridel@nbtsc.org> schrieb im Newsbeitrag
news:1093655816.7142.21.camel@mizar.nbtsc.org...

<snip>totally reasonable stuff</snip>

That sums it up very nicely!

Kind regards

    robert

Hi,

···

In message "fastcgi & continuations (Re: Idea: Webshare)" on Tue, 31 Aug 2004 15:14:29 +0900, Patrick May <patrick@hexane.org> writes:

I wasn't able to make this continuation trick work for me. It flip
flops -- it works the first time, crashes the second time, then
mod_fastcgi restarts the process and the cycle repeats.

I wish I could make these continuations work, though.

Need more info. Operating system, interpreter version, Apache version
etc.

              matz.

Hello,

sform = Request.Form('var') // overrides Url
surl = Request.Url('var') //asp uses querystring..too long

Session('var') = surl //cant remember how to do that in ruby but it
aint clean.

//out
Response.Write(Session('var'))//puts works but this is more readable

In implementing those 3, you will need to tie them together with one controlling object. In Narf I call that controlling object Web(::CGI). Do this:

   Request = Response = Web
   Session = Web::session

   Request['var']
   Response << 'output' + Session['key']

and pretend the other methods don't exist.

~ Patrick

···

On Saturday, September 4, 2004, at 03:55 AM, paul vudmaska wrote:

Sorry for being so slow.

···

In message "Re: eval function efficiency" on Sun, 22 Aug 2004 13:23:41 +0900, Zach Dennis <zdennis@mktec.com> writes:

I am using the eval function excessively in one of my programs. Is there
any real performance drains from using it? Thanks,

If you call eval repeatedly, compile cost from string can be a
burden. Try avoiding eval within loops.

              matz.

Hi --

David A. Black wrote:

>I'm not quite following. What's not working as you'd like exactly?
>
>
>
hsh = { '*' => '(*)' , 'a' => '(1){2}' }
val = "b"
a = hsh[ val ] or hsh['*'] #to give me, a = '(*)'
puts a
val = "a"
a = hsh[ val ] or hsh['*'] #to give me, a = '(1){2}'
puts a

I want the fourth line to output (*) instead it gives me nil.

Whoops, I fell into the irb trap :slight_smile:

binds more tightly than or, so:

  a = hsh[val] || hsh['*']

should give you what you want.

David

···

On Fri, 20 Aug 2004, Zach Dennis wrote:

--
David A. Black
dblack@wobblini.net

Every web app I've written depends on a combination of request and response. I think that combining the two simplifies makes for cleaner, simpler code. Splitting up request / response you have to pass the objects around:

def delegate( request, response )
    case request["param"]
    when "submit"
        do_submit( request, response )
    else
        show_form( request, response )
     end
end

request, response = cgi.create
delegate( request, response )

It seemed simpler to use a single object:

def delegate( cgi )
     case cgi["param"]
     when "submit"
         do_submit( cgi )
     else
         show_form( cgi )
     end
end

delegate( CGI.new )

Now, I think the best API is to let a global manage a singleton:

def delegate
     case Web["param"]
     when "submit"
         do_submit
     else
         show_form
     end
end

delegate

Passing around all those objects felt like useless typing to me. And given that it made it easier to implement the library, that's how I've arrived at my opinion. Splitting request / response up just didn't seem to be justified, while merging them created visibly simpler code in my apps and the library.

(I think caching is a side issue. None of these designs supports caching by default because they all have a connection to the client in there. Any of these designs can be made to support caching with some effort.)

Cheers,

Patrick

p.s. another thread sprung up out of this conversation; see [ruby-talk 110096]

···

On Monday, August 23, 2004, at 06:45 AM, Andreas Schwarz wrote:

Can you give an example of what advantage a combination of request and response would bring in practice?

Here's a simple example of the bug(?). Save this as fast.rb:

   class Server
     CONTINUATION =
     def Server::new(*args)
       at_exit do
         puts 'at_exit'
         if CONTINUATION[0]
           CONTINUATION[0].call
         end
       end

       callcc do |c|
         CONTINUATION[0] = c
       end

       puts 'Do you want to continue?'
       answer = gets

       if (answer.strip == 'no')
         CONTINUATION[0] = nil
       end
     end
   end

   server = Server.new

Here's what happens when I run this script. Note that I am typing the 'yes' and 'no' in this example:

   [laputa:~/programming/narf-servers] patsplat% ruby fast.rb
   Do you want to continue?
   no
   at_exit
   [laputa:~/programming/narf-servers] patsplat% ruby fast.rb
   Do you want to continue?
   yes
   at_exit
   Do you want to continue?
   yes
   fast.rb:24: compile error (SyntaxError)
   fast.rb:24: [BUG] Bus Error
   ruby 1.8.1 (2003-12-25) [powerpc-darwin]

   Abort
   [laputa:~/programming/narf-servers] patsplat% ruby --version
   ruby 1.8.1 (2003-12-25) [powerpc-darwin]
   [laputa:~/programming/narf-servers] patsplat%

Cheers,

Patrick

···

On Thursday, September 2, 2004, at 08:16 PM, Yukihiro Matsumoto wrote:

Hi,

In message "fastcgi & continuations (Re: Idea: Webshare)" > on Tue, 31 Aug 2004 15:14:29 +0900, Patrick May > <patrick@hexane.org> writes:

>I wasn't able to make this continuation trick work for me. It flip
>flops -- it works the first time, crashes the second time, then
>mod_fastcgi restarts the process and the cycle repeats.
>
>I wish I could make these continuations work, though.

Need more info. Operating system, interpreter version, Apache version
etc.