[racket] Limiting net-repl provided functions

From: Eli Barzilay (eli at barzilay.org)
Date: Tue Jun 28 03:33:14 EDT 2011

10 minutes ago, Jukka Tuominen wrote:
> 
> > -----Original Message-----
> > From: Eli Barzilay [mailto:eli at barzilay.org]
> > Sent: 28 June 2011 09:45
> > To: Jukka Tuominen
> > Cc: Sam Tobin-Hochstadt; users at racket-lang.org
> > Subject: RE: [racket] Limiting net-repl provided functions
> >
> >
> > About a minute ago, Jukka Tuominen wrote:
> > >
> > > > The sandbox is working in an isolated world (by design, of
> > > > course), so you need to do the (require "sb-functions.rkt") inside
> > > > the sandbox.  For example, just use (sb-eval '(require ...)).
> > >
> > > Wouldn't that mean that the sb-evaluator has to be first initiated
> > > to understand 'require' plus many other primitives, not just the
> > > intented f1, f2, f3?
> >
> > Yes.
> >
> >
> > > Is this even possible?
> >
> > Yes.  You can get that with
> >
> >   (make-evaluator 'racket/base)
> 
> Sorry, I meant to say that is it possible to have only the f1, f2, and f3
> provided, but not even 'require'...
> >
> > If you want a limited language, then you can make up a language with
> > `require' and the limited set of bindings you want in.  If you also
> > don't want `require' in the language, you can make the language itself
> > provide the functions that you want to make public, but not `require'
> > itself.  Yet another option is to use `call-in-sandbox-context' with
> > `namespace-require'.
> 
> yes, I want to have a more limited language, yet without leaving the
> comfort of Racket, meaning that on the server side you have all the
> familiar tools to create new 'primitives', and on the client side,
> use these primitives just like any other, no matter how and where
> they take place.

So that's what you need to do.  Here's an example:

  ---- limited.rkt ---
  #lang racket/base
  (provide
   ;; special things
   #%app #%module-begin #%datum #%top #%top-interaction
   ;; visible primitives
   + - quote length
   ;; additional functions
   f1)
  ;; definitions for the additional functions
  (define (f1 l) (length l))

and then:

  > (require racket/sandbox)
  > (define e (make-evaluator "limited.rkt"))
  > (e '(+ 1 2))
  3
  > (e '(- (f1 '(x y z)) 1))
  2

and not much else works...  Specifically, `require' is not there:

  > (e '(require racket))
  reference to an identifier before its definition: require in module:
  "program"


> > (All of this is much more complicated then what Matthias
> > originally hinted at: if you know the set of functions that you
> > want to expose, then you can just dispatch on the input symbols
> > and call the corresponding function.)
> 
> I wish I was just pretending not to see the obvious (sigh)...  Yes
> please, I would very much like the obvious and simple solution! :)
> Not just for me, but also for the ones that hopefully will end up
> creating these new services eventually. Even the hint 2 isn't enough
> for me unfortunately (sigh 2)...

Just something like this:

  (require "server-functions.rkt")
  (define request (read from-client))
  (unless (and (list? request) (pair? request) (symbol? (car request)))
          ;; or use `match' instead
    (throw-error-to-port to-client "bad request"))
  (apply (case (car request)
           [(f1) f1]
           [(f2) f2]
           ... more here ...)
         (cdr request))

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


Posted on the users mailing list.