[Zope-CMF] A bit of a glitch with FTP PUT

seb bacon seb@jamkit.com
Mon, 21 May 2001 12:39:55 +0100


* Tres Seaver <tseaver@novacoxmail.com> [010519 17:17]:
> Jonathan Corbet wrote:
> > I can work around this, but, to me, a proper solution is non-obvious.  It
> > would be nice if FTP uploads that create items didn't circumvent the
> > workflow mechanism.  Something for somebody's list, maybe...
> 
> Improving our FTP and WebDAV integration story is pretty high on
> our list;  we'll look at that this week.

I've been struggling with the WebDAV, myself.  I mentioned last week
that one problem is that CookieCrumbler does redirection when
Unauthorized is raised, which breaks WebDAV.  FWIW, although it's not
exactly a watertight solution, I've found the attached works with all
the clients I've tested it on.  And I can't think of any other way
round it, unfortunately.

The next problem is that uploading Files fails.  I think it's because
there's no fallback for default, globbed-style mimetypes in the
_mime_type_registry hack in PortalFolder: for example, the
NullResource PUT factory ends up trying to create an
application/octet-stream file as a normal File object, and of course
fails.  I fixed it with a cheesey hack, because I know you've got
this in mind for a TTW, fully configurable solution.  Any idea when
you might be looking at this - it'd be pretty useful - please :)

many thanks,

seb 



*** /tmp/CookieCrumbler.py	Mon May 21 11:29:28 2001
--- /tmp/CookieCrumbler.py13600WQ	Mon May 21 11:29:28 2001
***************
*** 11,16 ****
--- 11,17 ----
  from Globals import HTMLFile
  from zLOG import LOG, ERROR
  import sys
+ import string
  
  # Constants.
  ATTEMPT_NONE = 0
***************
*** 113,124 ****
                  return ATTEMPT_CONT
          return ATTEMPT_NONE
  
      def __call__(self, container, req):
          '''The __before_publishing_traverse__ hook.'''
          resp = self.REQUEST['RESPONSE']
          attempt = self.modifyRequest(req, resp)
          if self.auto_login_page:
!             if not req.get('disable_cookie_login__', 0):
                  if (attempt == ATTEMPT_LOGIN or
                      not getattr(resp, '_auth', 0)):
                      page = getattr(container, self.auto_login_page, None)
--- 114,157 ----
                  return ATTEMPT_CONT
          return ATTEMPT_NONE
  
+     def intercept_allowed(self,req):
+         '''Can we intercept the unauthorized exception?
+            WebDAV clients will get confused by redirect.  Kludgy ways of
+            detecting them...'''
+ 
+         clients = ['neon/',
+                    'Microsoft Data Access Internet Publishing',
+                    ]
+ 
+         allowed = 1
+ 
+         # explicit cookie 
+         if req.get('disable_cookie_login__', 0):
+             allowed = 0
+ 
+         # unorthodox method (may be PROPFIND, OPTIONS, etc..)
+         method=req.get('REQUEST_METHOD', 'GET')
+         if not method in ('GET','POST'):
+             allowed = 0
+ 
+         # existence of known WebDAV client
+         ua = req.get_header('User-Agent','')
+         for c in clients:
+             if string.find(ua,c) > 0:
+                 allowed = 0
+ 
+         # existence of webdav-only header
+         if req.get_header('Depth',None) is not None:
+             allowed = 0
+ 
+         return allowed
+                     
      def __call__(self, container, req):
          '''The __before_publishing_traverse__ hook.'''
          resp = self.REQUEST['RESPONSE']
          attempt = self.modifyRequest(req, resp)
          if self.auto_login_page:
!             if self.intercept_allowed(req):
                  if (attempt == ATTEMPT_LOGIN or
                      not getattr(resp, '_auth', 0)):
                      page = getattr(container, self.auto_login_page, None)