Anonymous avatar Anonymous committed 71b9b9c

Fix for FileApp replying to non-GET requests, and giving the body for HEAD requests

Comments (0)

Files changed (3)

 svn trunk
 ---------
 
+* **Backward incompatible change**: ``paste.fileapp.FileApp`` properly
+  supports request methods, including HEAD.  If you were subclassing
+  ``FileApp`` or ``DataApp`` and overriding ``__call__()`` you may have
+  to subclass ``get()`` instead.
+
 * paste.httpheaders now parses the HTTP Accept-Language header and returns
   a list of languages the browser supports in the order it prefers them.
 
         return self
 
     def __call__(self, environ, start_response):
+        method = environ['REQUEST_METHOD'].upper()
+        if method not in ('GET', 'HEAD'):
+            exc = HTTPMethodNotAllowed(
+                'You cannot %s a file' % method,
+                headers=[('Allow', 'GET, HEAD')])
+            return exc(environ, start_response)
+        return self.get(environ, start_response)
+
+    def get(self, environ, start_response):
         headers = self.headers[:]
         current_etag = str(self.last_modified)
         ETAG.update(headers, current_etag)
             # called
             LAST_MODIFIED.update(self.headers, time=self.last_modified)
 
-    def __call__(self, environ, start_response):
+    def get(self, environ, start_response):
+        is_head = environ['REQUEST_METHOD'].upper() == 'HEAD'
         if 'max-age=0' in CACHE_CONTROL(environ).lower():
             self.update(force=True) # RFC 2616 13.2.6
         else:
                     'You are not permitted to view this file (%s)' % e)
                 return exc.wsgi_application(
                     environ, start_response)
-        retval = DataApp.__call__(self, environ, start_response)
+        retval = DataApp.get(self, environ, start_response)
         if isinstance(retval, list):
             # cached content, exception, or not-modified
+            if is_head:
+                return ['']
             return retval
         (lower, content_length) = retval
+        if is_head:
+            return ['']
         file.seek(lower)
         return _FileIter(file, size=content_length)
 

tests/test_fileapp.py

                   status=304)
     res = app.get('/', headers={'If-Modified-Since': 'invalid date'},
                   status=400)
+
+def test_methods():
+    from paste import fileapp
+    filename = os.path.join(os.path.dirname(__file__),
+                            'urlparser_data', 'secured.txt')
+    app = TestApp(fileapp.FileApp(filename))
+    get_res = app.get('')
+    res = app.get('', extra_environ={'REQUEST_METHOD': 'HEAD'})
+    assert res.headers == get_res.headers
+    assert not res.body
+    app.post('', status=405) # Method Not Allowed
+    
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.