You are not logged in Log in Join
You are here: Home » Members » Toby Dickenson » tree.diff » View File

Log in
Name

Password

 

tree.diff

File details
Size
6 K
File type
text/x-diff

File contents

Index: TreeTag.py
===================================================================
RCS file: /cvs-repository/Zope/lib/python/TreeDisplay/TreeTag.py,v
retrieving revision 1.53
diff -c -2 -r1.53 TreeTag.py
*** TreeTag.py	14 Aug 2002 22:02:25 -0000	1.53
--- TreeTag.py	16 Dec 2002 20:44:48 -0000
***************
*** 19,25 ****
  from DocumentTemplate.DT_String import String
  
  from string import translate
  from urllib import quote, unquote
! from zlib import compress, decompress
  from binascii import b2a_base64, a2b_base64
  import re
--- 19,26 ----
  from DocumentTemplate.DT_String import String
  
+ from cPickle import dumps
  from string import translate
  from urllib import quote, unquote
! from zlib import compress, decompressobj
  from binascii import b2a_base64, a2b_base64
  import re
***************
*** 104,116 ****
        ['eagle'], ['jeep', [1983, 1985]]  # eagle, jeep, 1983 jeep and 1985 jeep
  
!     where the items are object ids. The state will be converted to a
      compressed and base64ed string that gets unencoded, uncompressed,
!     and evaluated on the other side.
  
      Note that ids used in state need not be connected to urls, since
      state manipulation is internal to rendering logic.
  
!     Note that to make eval safe, we do not allow the character '*' in
!     the state.
      """
  
--- 105,117 ----
        ['eagle'], ['jeep', [1983, 1985]]  # eagle, jeep, 1983 jeep and 1985 jeep
  
!     where the items are object ids. The state will be pickled to a
      compressed and base64ed string that gets unencoded, uncompressed,
!     and unpickled on the other side.
  
      Note that ids used in state need not be connected to urls, since
      state manipulation is internal to rendering logic.
  
!     Note that to make unpickling safe, we use the MiniPickle module,
!     that only creates safe objects
      """
  
***************
*** 324,328 ****
              ####################################
              # Mostly inline encode_seq for speed
!             s=compress(str(diff))
              if len(s) > 57: s=encode_str(s)
              else:
--- 325,329 ----
              ####################################
              # Mostly inline encode_seq for speed
!             s=compress(dumps(diff,1))
              if len(s) > 57: s=encode_str(s)
              else:
***************
*** 515,519 ****
  def encode_seq(state):
      "Convert a sequence to an encoded string"
!     state=compress(str(state))
      l=len(state)
  
--- 516,520 ----
  def encode_seq(state):
      "Convert a sequence to an encoded string"
!     state=compress(dumps(state))
      l=len(state)
  
***************
*** 575,582 ****
  
      state=decompress(state)
!     if state.find('*') >= 0: raise 'Illegal State', state
!     try: return list(eval(state,{'__builtins__':{}}))
      except: return []
  
  
  def tpStateLevel(state, level=0):
--- 576,593 ----
  
      state=decompress(state)
!     try: return list(MiniUnpickler(StringIO(state)).load())
      except: return []
  
+ def decompress(input,max_size=10240):
+     # This sillyness can go away in python 2.2
+     d = decompressobj()
+     output = ''
+     while input:
+         fragment_size = max(1,(max_size-len(output))/1000)
+         fragment,input = input[:fragment_size],input[fragment_size:]
+         output += d.decompress(fragment)
+         if len(output)>max_size:
+             raise ValueError('Compressed input too large')
+     return output+d.flush()
  
  def tpStateLevel(state, level=0):
***************
*** 625,626 ****
--- 636,716 ----
  #icoPlus ='<IMG SRC="Plus_icon" BORDER="0">'
  #icoMinus='<IMG SRC="Minus_icon" BORDER="0">'
+ 
+ 
+ 
+ 
+ 
+ ###############################################################################
+ ## Everthing below here should go in a MiniPickle.py module, but keeping it
+ ## internal makes an easier patch
+ 
+ 
+ import pickle
+ from cStringIO import StringIO
+ 
+ 
+ if pickle.format_version!="1.3":
+     # Maybe the format changed, and opened a security hole
+     raise 'Invalid pickle version'
+ 
+ 
+ class MiniUnpickler(pickle.Unpickler):
+     """An unpickler that can only handle simple types.
+     """
+     def refuse_to_unpickle(self):
+         raise pickle.UnpicklingError, 'Refused'
+ 
+     dispatch = pickle.Unpickler.dispatch.copy()
+ 
+     for k,v in dispatch.items():
+         if k=='' or k in '().012FGIJKLMNTUVX]adeghjlpqrstu}':
+             # This key is necessary and safe, so leave it in the map
+             pass
+         else:
+             dispatch[k] = refuse_to_unpickle
+             # Anything unnecessary is banned, but here is some logic to explain why
+             if k in [pickle.GLOBAL, pickle.OBJ, pickle.INST, pickle.REDUCE, pickle.BUILD]:
+                 # These are definite security holes
+                 pass
+             elif k in [pickle.PERSID, pickle.BINPERSID]:
+                 # These are just unnecessary
+                 pass
+             elif k in [pickle.STRING]:
+                 # This one is controversial: A string is harmlessm, but the
+                 # implementation of pickle leaks memory (strings may be interned)
+                 # The problem can be avoided by using binary pickles.
+                 pass
+             else:
+                 # Someone added a key but did not increment the version.
+                 raise 'Invalid pickle key',k
+     del k
+     del v
+ 
+ def _should_succeed(x,binary=1):
+     if x != MiniUnpickler(StringIO(pickle.dumps(x,binary))).load():
+         raise ValueError(x)
+ 
+ def _should_fail(x,binary=1):
+     try:
+         MiniUnpickler(StringIO(pickle.dumps(x,binary))).load()
+         raise ValueError(x)
+     except pickle.UnpicklingError, e:
+         if e[0]!='Refused': raise ValueError(x)
+ 
+ class _junk_class: pass
+ 
+ def _test():
+     _should_fail('hello',0)
+     _should_succeed('hello')
+     _should_succeed(1)
+     _should_succeed(1L)
+     _should_succeed(1.0)
+     _should_succeed((1,2,3))
+     _should_succeed([1,2,3])
+     _should_succeed({1:2,3:4})
+     _should_fail(open)
+     _should_fail(_junk_class)
+     _should_fail(_junk_class())
+ 
+ # Test MiniPickle on every import
+ _test()