Example #1
0
    def test_is_resource_modified(self):
        env = create_environ()

        # ignore POST
        env["REQUEST_METHOD"] = "POST"
        assert not http.is_resource_modified(env, etag="testing")
        env["REQUEST_METHOD"] = "GET"

        # etagify from data
        self.assert_raises(TypeError, http.is_resource_modified, env, data="42", etag="23")
        env["HTTP_IF_NONE_MATCH"] = http.generate_etag(b"awesome")
        assert not http.is_resource_modified(env, data=b"awesome")

        env["HTTP_IF_MODIFIED_SINCE"] = http.http_date(datetime(2008, 1, 1, 12, 30))
        assert not http.is_resource_modified(env, last_modified=datetime(2008, 1, 1, 12, 00))
        assert http.is_resource_modified(env, last_modified=datetime(2008, 1, 1, 13, 00))
    def make_conditional(self, request_or_environ):
        """Make the response conditional to the request.  This method works
        best if an etag was defined for the response already.  The `add_etag`
        method can be used to do that.  If called without etag just the date
        header is set.

        This does nothing if the request method in the request or enviorn is
        anything but GET or HEAD.

        It does not remove the body of the response because that's something
        the `__call__` function does for us automatically.

        Returns self so that you can do ``return resp.make_conditional(req)``
        but modifies the object in-place.
        """
        environ = getattr(request_or_environ, 'environ', request_or_environ)
        if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'):
            return
        self.headers['Date'] = http_date()
        if 'content-length' in self.headers:
            self.headers['Content-Length'] = len(self.data)
        if not is_resource_modified(environ, self.headers.get('etag'), None,
                                    self.headers.get('last-modified')):
            self.status_code = 304
        return self
Example #3
0
def feed(config, tz, template, page=None):
    include_day = config.include_day
    start = datetime.fromtimestamp(config.start_timestamp, tz)
    now = datetime.now(start.tzinfo)

    total_posts = count_dates(start, now, include_day)
    per_page = 50
    last_page = total_posts // per_page - 1

    headers = {
        'Date': http_date(now),
    }

    links = []
    if page is None:
        etag = quote_etag(str(total_posts))
        next_date, dates = recent_dates(start, now, include_day, per_page)
        max_age = int((next_date - now).total_seconds())
        if last_page >= 0:
            links.append(('prev-archive', last_page))
    elif page <= last_page:
        etag = '"0"'
        dates = archived_dates(start, include_day, page * per_page, per_page)
        max_age = 7 * 24 * 60 * 60
        links.append(('current', None))
        if page < last_page:
            links.append(('next-archive', page + 1))
        if page > 0:
            links.append(('prev-archive', page - 1))
    else:
        abort(404)

    headers['Cache-Control'] = "public, max-age={}, immutable".format(max_age)
    headers['Expires'] = http_date(now + timedelta(seconds=max_age))
    headers['ETag'] = etag
    if not is_resource_modified(request.environ, etag):
        return Response(status=304, headers=headers)

    day_names = [
        calendar.day_name[day] for day, included in enumerate(include_day)
        if included
    ]
    if len(day_names) > 1:
        days_description = '{} and {}'.format(
            ', '.join(day_names[:-1]),
            day_names[-1],
        )
    else:
        days_description = day_names[0]

    feed = render_template(
        "feed.xml",
        template=template,
        days_description=days_description,
        start=start,
        config=config,
        links=links,
        dates=dates,
    )
    return Response(feed, mimetype='application/rss+xml', headers=headers)
Example #4
0
        def decorated(*args, **kw):
            headers = {}
            kw['headers'] = headers

            if context_var == 'user' and 'user_id' in kw:
                user_id = kw['user_id']
                if user_id == '(null)':
                    return f(*args, **kw)
                context = g.user if user_id == 'me' else User.find(int(user_id))
            else:
                context = getattr(g, context_var, None)

            if not context:
                return f(*args, **kw)

            last_change = wigo_db.get_redis().hget(skey(context, 'meta'), field)
            if last_change:
                last_change = datetime.utcfromtimestamp(float(last_change))
            else:
                return f(*args, **kw)

            if last_change > datetime.utcnow():
                # if last-change is set to the future, the intent is to disable if-modified-since
                # until that time. Last-Modified can't be set to the future or that doesn't work.
                headers['Last-Modified'] = http_date(datetime.utcnow())
            else:
                headers['Last-Modified'] = http_date(last_change)

            if max_age:
                headers['Cache-Control'] = 'max-age={}'.format(max_age)

            if last_change and not is_resource_modified(request.environ, last_modified=last_change):
                return 'Not modified', 304, headers

            return f(*args, **kw)
Example #5
0
 def do_get(self, force_attachment=False, mimetype=None):
     hash = self.rev.meta.get(HASH_ALGORITHM)
     if is_resource_modified(request.environ, hash):  # use hash as etag
         return self._do_get_modified(hash,
                                      force_attachment=force_attachment,
                                      mimetype=mimetype)
     else:
         return Response(status=304)
Example #6
0
File: wrappers.py Project: Reve/eve
 def make_conditional(self, request_or_environ):
     environ = _get_environ(request_or_environ)
     if environ["REQUEST_METHOD"] in ("GET", "HEAD"):
         self.headers["Date"] = http_date()
         if "content-length" in self.headers:
             self.headers["Content-Length"] = len(self.data)
         if not is_resource_modified(environ, self.headers.get("etag"), None, self.headers.get("last-modified")):
             self.status_code = 304
     return self
Example #7
0
 def make_conditional(self, request_or_environ):
     environ = _get_environ(request_or_environ)
     if environ['REQUEST_METHOD'] in ('GET', 'HEAD'):
         self.headers['Date'] = http_date()
         if 'content-length' in self.headers:
             self.headers['Content-Length'] = len(self.data)
         if not is_resource_modified(environ, self.headers.get('etag'), None, self.headers.get('last-modified')):
             self.status_code = 304
     return self
Example #8
0
 def make_conditional(self, request_or_environ):
     environ = _get_environ(request_or_environ)
     if environ['REQUEST_METHOD'] in ('GET', 'HEAD'):
         self.headers['Date'] = http_date()
         if 'content-length' in self.headers:
             self.headers['Content-Length'] = len(self.data)
         if not is_resource_modified(environ, self.headers.get('etag'), None, self.headers.get('last-modified')):
             self.status_code = 304
     return self
Example #9
0
def validate_cache(request):
    etag = sha1(repr(sorted(request.cache_key.items()))).hexdigest()
    mod_time = request.cache_key.get("modified")
    if request.method != "GET":
        return etag, mod_time
    if not is_resource_modified(request.environ, etag=etag, last_modified=mod_time):
        raise NotModified()
    if request.if_none_match == etag:
        raise NotModified()
    return etag, mod_time
Example #10
0
def startupnews():
    dt = models.LastUpdated.get('startupnews')
    if dt and not is_resource_modified(request.environ, None, None, last_modified=dt):
        return Response(status=304)
    resp = Response(render_template(
                'startupnews.html',
                news_list=models.StartupNews.query.order_by('rank').all(),
                last_updated=dt))
    set_cache(resp, dt)
    return resp
Example #11
0
    def test_is_resource_modified(self):
        env = create_environ()

        # ignore POST
        env['REQUEST_METHOD'] = 'POST'
        assert not http.is_resource_modified(env, etag='testing')
        env['REQUEST_METHOD'] = 'GET'

        # etagify from data
        pytest.raises(TypeError, http.is_resource_modified, env,
                      data='42', etag='23')
        env['HTTP_IF_NONE_MATCH'] = http.generate_etag(b'awesome')
        assert not http.is_resource_modified(env, data=b'awesome')

        env['HTTP_IF_MODIFIED_SINCE'] = http.http_date(datetime(2008, 1, 1, 12, 30))
        assert not http.is_resource_modified(env,
                                             last_modified=datetime(2008, 1, 1, 12, 00))
        assert http.is_resource_modified(env,
                                         last_modified=datetime(2008, 1, 1, 13, 00))
Example #12
0
def startupnews():
    dt = models.LastUpdated.get('startupnews')
    if dt and not is_resource_modified(request.environ, None, None, last_modified=dt):
        return Response(status=304)
    resp = Response(render_template(
                'startupnews.html',
                news_list=models.StartupNews.query.order_by('rank').all(),
                last_updated=dt))
    set_cache(resp, dt)
    return resp
Example #13
0
    def test_is_resource_modified(self):
        env = create_environ()

        # ignore POST
        env['REQUEST_METHOD'] = 'POST'
        assert not http.is_resource_modified(env, etag='testing')
        env['REQUEST_METHOD'] = 'GET'

        # etagify from data
        self.assert_raises(TypeError, http.is_resource_modified, env,
                           data='42', etag='23')
        env['HTTP_IF_NONE_MATCH'] = http.generate_etag(b'awesome')
        assert not http.is_resource_modified(env, data=b'awesome')

        env['HTTP_IF_MODIFIED_SINCE'] = http.http_date(datetime(2008, 1, 1, 12, 30))
        assert not http.is_resource_modified(env,
            last_modified=datetime(2008, 1, 1, 12, 00))
        assert http.is_resource_modified(env,
            last_modified=datetime(2008, 1, 1, 13, 00))
Example #14
0
    def test_is_resource_modified(self):
        env = create_environ()

        # any method is allowed
        env["REQUEST_METHOD"] = "POST"
        assert http.is_resource_modified(env, etag="testing")
        env["REQUEST_METHOD"] = "GET"

        # etagify from data
        pytest.raises(TypeError, http.is_resource_modified, env, data="42", etag="23")
        env["HTTP_IF_NONE_MATCH"] = http.generate_etag(b"awesome")
        assert not http.is_resource_modified(env, data=b"awesome")

        env["HTTP_IF_MODIFIED_SINCE"] = http.http_date(datetime(2008, 1, 1, 12, 30))
        assert not http.is_resource_modified(
            env, last_modified=datetime(2008, 1, 1, 12, 00)
        )
        assert http.is_resource_modified(
            env, last_modified=datetime(2008, 1, 1, 13, 00)
        )
Example #15
0
    def get(self, model_id):
        instance = self.model.find(self.get_id(model_id))
        self.check_get(instance)

        modified = self.get_last_modified(instance)
        headers = {'Last-Modified': http_date(modified)}

        if not is_resource_modified(request.environ, last_modified=modified):
            return 'Not modified', 304, headers

        return self.serialize_list(self.model, [instance]), 200, headers
Example #16
0
def validate_cache(request):
    etag = sha1(repr(sorted(request.cache_key.items()))).hexdigest()
    mod_time = request.cache_key.get('modified')
    if request.method != 'GET':
        return etag, mod_time
    if not is_resource_modified(
            request.environ, etag=etag, last_modified=mod_time):
        raise NotModified()
    if request.if_none_match == etag:
        raise NotModified()
    return etag, mod_time
Example #17
0
    def __call__(self, environ, start_response):
        cleaned_path = get_path_info(environ)
        if PY2:
            cleaned_path = cleaned_path.encode(get_filesystem_encoding())
        # sanitize the path for non unix systems
        cleaned_path = cleaned_path.strip('/')
        for sep in os.sep, os.altsep:
            if sep and sep != '/':
                cleaned_path = cleaned_path.replace(sep, '/')
        path = '/' + '/'.join(x for x in cleaned_path.split('/')
                              if x and x != '..')
        file_loader = None
        for search_path, loader in self.exports:
            if search_path == path:
                real_filename, file_loader = loader(None)
                if file_loader is not None:
                    break
            if not search_path.endswith('/'):
                search_path += '/'
            if path.startswith(search_path):
                real_filename, file_loader = loader(path[len(search_path):])
                if file_loader is not None:
                    break
        if file_loader is None or not self.is_allowed(real_filename):
            return self.app(environ, start_response)

        guessed_type = mimetypes.guess_type(real_filename)
        mime_type = guessed_type[0] or self.fallback_mimetype
        f, mtime, file_size = file_loader()

        headers = [('Date', http_date())]
        if self.cache:
            timeout = self.cache_timeout
            etag = self.generate_etag(mtime, file_size, real_filename)
            headers += [
                ('Etag', '"%s"' % etag),
                ('Cache-Control', 'max-age=%d, public' % timeout)
            ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                start_response('304 Not Modified', headers)
                return []
            headers.append(('Expires', http_date(time() + timeout)))
        else:
            headers.append(('Cache-Control', 'public'))

        headers.extend((
            ('Content-Type', mime_type),
            ('Content-Length', str(file_size)),
            ('Last-Modified', http_date(mtime))
        ))
        start_response('200 OK', headers)
        return wrap_file(environ, f)
Example #18
0
    def __call__(self, environ, start_response):
        cleaned_path = get_path_info(environ)
        if PY2:
            cleaned_path = cleaned_path.encode(sys.getfilesystemencoding())
        # sanitize the path for non unix systems
        cleaned_path = cleaned_path.strip('/')
        for sep in os.sep, os.altsep:
            if sep and sep != '/':
                cleaned_path = cleaned_path.replace(sep, '/')
        path = '/' + '/'.join(x for x in cleaned_path.split('/')
                              if x and x != '..')
        file_loader = None
        for search_path, loader in iteritems(self.exports):
            if search_path == path:
                real_filename, file_loader = loader(None)
                if file_loader is not None:
                    break
            if not search_path.endswith('/'):
                search_path += '/'
            if path.startswith(search_path):
                real_filename, file_loader = loader(path[len(search_path):])
                if file_loader is not None:
                    break
        if file_loader is None or not self.is_allowed(real_filename):
            return self.app(environ, start_response)

        guessed_type = mimetypes.guess_type(real_filename)
        mime_type = guessed_type[0] or self.fallback_mimetype
        f, mtime, file_size = file_loader()

        headers = [('Date', http_date())]
        if self.cache:
            timeout = self.cache_timeout
            etag = self.generate_etag(mtime, file_size, real_filename)
            headers += [
                ('Etag', '"%s"' % etag),
                ('Cache-Control', 'max-age=%d, public' % timeout)
            ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                start_response('304 Not Modified', headers)
                return []
            headers.append(('Expires', http_date(time() + timeout)))
        else:
            headers.append(('Cache-Control', 'public'))

        headers.extend((
            ('Content-Type', mime_type),
            ('Content-Length', str(file_size)),
            ('Last-Modified', http_date(mtime))
        ))
        start_response('200 OK', headers)
        return wrap_file(environ, f)
 def _is_range_request_processable(self,
                                   environ: "WSGIEnvironment") -> bool:
     """Return ``True`` if `Range` header is present and if underlying
     resource is considered unchanged when compared with `If-Range` header.
     """
     return ("HTTP_IF_RANGE" not in environ or not is_resource_modified(
         environ,
         self.headers.get("etag"),
         None,
         self.headers.get("last-modified"),
         ignore_if_range=False,
     )) and "HTTP_RANGE" in environ
Example #20
0
    def __call__(self, environ, start_response):
        cleaned_path = get_path_info(environ)
        if PY2:
            cleaned_path = cleaned_path.encode(get_filesystem_encoding())
        # sanitize the path for non unix systems
        cleaned_path = cleaned_path.strip("/")
        for sep in os.sep, os.altsep:
            if sep and sep != "/":
                cleaned_path = cleaned_path.replace(sep, "/")
        path = "/" + "/".join(
            x for x in cleaned_path.split("/") if x and x != "..")
        file_loader = None
        for search_path, loader in self.exports:
            if search_path == path:
                real_filename, file_loader = loader(None)
                if file_loader is not None:
                    break
            if not search_path.endswith("/"):
                search_path += "/"
            if path.startswith(search_path):
                real_filename, file_loader = loader(path[len(search_path):])
                if file_loader is not None:
                    break
        if file_loader is None or not self.is_allowed(real_filename):
            return self.app(environ, start_response)

        guessed_type = mimetypes.guess_type(real_filename)
        mime_type = guessed_type[0] or self.fallback_mimetype
        f, mtime, file_size = file_loader()

        headers = [("Date", http_date())]
        if self.cache:
            timeout = self.cache_timeout
            etag = self.generate_etag(mtime, file_size, real_filename)
            headers += [
                ("Etag", '"%s"' % etag),
                ("Cache-Control", "max-age=%d, public" % timeout),
            ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                start_response("304 Not Modified", headers)
                return []
            headers.append(("Expires", http_date(time() + timeout)))
        else:
            headers.append(("Cache-Control", "public"))

        headers.extend((
            ("Content-Type", mime_type),
            ("Content-Length", str(file_size)),
            ("Last-Modified", http_date(mtime)),
        ))
        start_response("200 OK", headers)
        return wrap_file(environ, f)
Example #21
0
    def test_is_resource_modified_for_range_requests(self):
        env = create_environ()

        env['HTTP_IF_MODIFIED_SINCE'] = http.http_date(
            datetime(2008, 1, 1, 12, 30))
        env['HTTP_IF_RANGE'] = http.generate_etag(b'awesome_if_range')
        # Range header not present, so If-Range should be ignored
        assert not http.is_resource_modified(env,
                                             data=b'not_the_same',
                                             ignore_if_range=False,
                                             last_modified=datetime(
                                                 2008, 1, 1, 12, 30))

        env['HTTP_RANGE'] = ''
        assert not http.is_resource_modified(
            env, data=b'awesome_if_range', ignore_if_range=False)
        assert http.is_resource_modified(env,
                                         data=b'not_the_same',
                                         ignore_if_range=False)

        env['HTTP_IF_RANGE'] = http.http_date(datetime(2008, 1, 1, 13, 30))
        assert http.is_resource_modified(env,
                                         last_modified=datetime(
                                             2008, 1, 1, 14, 00),
                                         ignore_if_range=False)
        assert not http.is_resource_modified(env,
                                             last_modified=datetime(
                                                 2008, 1, 1, 13, 30),
                                             ignore_if_range=False)
        assert http.is_resource_modified(env,
                                         last_modified=datetime(
                                             2008, 1, 1, 13, 30),
                                         ignore_if_range=True)
Example #22
0
    def test_is_resource_modified_for_range_requests(self):
        env = create_environ()

        env["HTTP_IF_MODIFIED_SINCE"] = http.http_date(datetime(2008, 1, 1, 12, 30))
        env["HTTP_IF_RANGE"] = http.generate_etag(b"awesome_if_range")
        # Range header not present, so If-Range should be ignored
        assert not http.is_resource_modified(
            env,
            data=b"not_the_same",
            ignore_if_range=False,
            last_modified=datetime(2008, 1, 1, 12, 30),
        )

        env["HTTP_RANGE"] = ""
        assert not http.is_resource_modified(
            env, data=b"awesome_if_range", ignore_if_range=False
        )
        assert http.is_resource_modified(
            env, data=b"not_the_same", ignore_if_range=False
        )

        env["HTTP_IF_RANGE"] = http.http_date(datetime(2008, 1, 1, 13, 30))
        assert http.is_resource_modified(
            env, last_modified=datetime(2008, 1, 1, 14, 00), ignore_if_range=False
        )
        assert not http.is_resource_modified(
            env, last_modified=datetime(2008, 1, 1, 13, 30), ignore_if_range=False
        )
        assert http.is_resource_modified(
            env, last_modified=datetime(2008, 1, 1, 13, 30), ignore_if_range=True
        )
Example #23
0
    def handle_zip_directory_listing(zip, archivefile, subarchivepath):
        """List contents in a directory.
        """
        # ensure directory has trailing '/'
        if not request.path.endswith('/'):
            parts = urlsplit(request.url)
            new_parts = (parts[0], parts[1], parts[2] + '/', parts[3],
                         parts[4])
            new_url = urlunsplit(new_parts)
            return redirect(new_url)

        stats = os.lstat(archivefile)
        last_modified = http_date(stats.st_mtime)
        etag = "%s-%s-%s" % (
            stats.st_mtime,
            stats.st_size,
            adler32(archivefile.encode("utf-8")) & 0xFFFFFFFF,
        )

        headers = {
            'Cache-Control': 'no-cache',
        }

        if not is_resource_modified(
                request.environ, etag=etag, last_modified=last_modified):
            return http_response(status=304, headers=headers)

        headers.update({
            'Last-Modified': last_modified,
            'ETag': etag,
        })

        subentries = util.zip_listdir(zip, subarchivepath)

        try:
            body = render_template(
                'index.html',
                sitename=runtime['name'],
                is_local=is_local_access(),
                base=request.script_root,
                path=request.path,
                subarchivepath=subarchivepath,
                subentries=subentries,
            )
            zip.close()
            return http_response(body, headers=headers)
        except util.ZipDirNotFoundError:
            # zip may not close automatically in such case
            # (due to a raise in a generator?)
            zip.close()

            return http_error(404, "File does not exist.")
Example #24
0
def handle_cache(response):
    """On 302 redirect, set no-cache headers. If resource is the same, return 304."""
    if response.status_code == 302:
        response.headers['Last-Modified'] = datetime.now()
        response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0'
        response.headers['Pragma'] = 'no-cache'
        response.headers['Expires'] = '-1'
        return response

    elif response.status_code != 200:
        return response

    # If we set max-age=0, then make sure the response is not locally cached
    if response.cache_control.max_age == 0:
        response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0'
        response.headers['Pragma'] = 'no-cache'
        response.headers['Expires'] = '-1'

    matched = not is_resource_modified(request.environ, etag=response.headers.get('etag'))
    unmodified = not is_resource_modified(request.environ, last_modified=response.headers.get('last-modified'))
    return_304 = matched or unmodified
    return return_304 and Response(status=304) or response
Example #25
0
def validate_cache(keys=None, last_modified=None):
    if isinstance(last_modified, (list, tuple)):
        last_modified = max(last_modified)
    if keys is None or not isinstance(keys, dict):
        keys = {'keys': keys}
    keys['last_modified'] = last_modified
    request._grano_etag = generate_etag(keys)
    request._grano_modified = last_modified
    if not is_resource_modified(request.environ,
                                etag=request._grano_etag,
                                last_modified=last_modified):
        raise NotModified()
    if request.if_none_match == request._grano_etag:
        raise NotModified()
Example #26
0
def validate_cache(keys=None, last_modified=None):
    if isinstance(last_modified, (list, tuple)):
        last_modified = max(last_modified)
    if keys is None or not isinstance(keys, dict):
        keys = {'keys': keys}
    keys['last_modified'] = last_modified
    request._grano_etag = generate_etag(keys)
    request._grano_modified = last_modified
    if not is_resource_modified(request.environ,
        etag=request._grano_etag,
        last_modified=last_modified):
        raise NotModified()
    if request.if_none_match == request._grano_etag:
        raise NotModified()
Example #27
0
    def __call__(self, environ, start_response):
        cleaned_path = get_path_info(environ)
        if PY2:
            cleaned_path = cleaned_path.encode(get_filesystem_encoding())
        # sanitize the path for non unix systems
        cleaned_path = cleaned_path.strip("/")
        for sep in os.sep, os.altsep:
            if sep and sep != "/":
                cleaned_path = cleaned_path.replace(sep, "/")
        path = "/" + "/".join(x for x in cleaned_path.split("/") if x and x != "..")
        file_loader = None
        for search_path, loader in iteritems(self.exports):
            if search_path == path:
                real_filename, file_loader = loader(None)
                if file_loader is not None:
                    break
            if not search_path.endswith("/"):
                search_path += "/"
            if path.startswith(search_path):
                real_filename, file_loader = loader(path[len(search_path) :])
                if file_loader is not None:
                    break
        if file_loader is None or not self.is_allowed(real_filename):
            return self.app(environ, start_response)

        guessed_type = mimetypes.guess_type(real_filename)
        mime_type = guessed_type[0] or self.fallback_mimetype
        f, mtime, file_size = file_loader()

        headers = [("Date", http_date())]
        if self.cache:
            timeout = self.cache_timeout
            etag = self.generate_etag(mtime, file_size, real_filename)
            headers += [("Etag", '"%s"' % etag), ("Cache-Control", "max-age=%d, public" % timeout)]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                start_response("304 Not Modified", headers)
                return []
            headers.append(("Expires", http_date(time() + timeout)))
        else:
            headers.append(("Cache-Control", "public"))

        headers.extend(
            (("Content-Type", mime_type), ("Content-Length", str(file_size)), ("Last-Modified", http_date(mtime)))
        )
        start_response("200 OK", headers)
        return wrap_file(environ, f)
Example #28
0
def startupnews():
    dt = models.LastUpdated.get('startupnews')
    if dt and not is_resource_modified(request.environ, None, None, last_modified=dt):
        return Response(status=304)
    resp = Response(render_template('index.html',
                title='Startup News Digest',
                news_list=models.StartupNews.query.order_by('rank').all(),
                navs=[
                    ('Startup News', 'http://news.dbanotes.net/news'),
                    ('New', 'http://news.dbanotes.net/newest'),
                    ('Comments', 'http://news.dbanotes.net/newcomments'),
                    ('Leaders', 'http://news.dbanotes.net/leaders'),
                    ('Submit', 'http://news.dbanotes.net/submit')],
                last_updated = dt and human(dt, 1)
            ))
    set_cache(resp, dt)
    return resp
Example #29
0
def startupnews():
    dt = models.LastUpdated.get('startupnews')
    if dt and not is_resource_modified(
            request.environ, None, None, last_modified=dt):
        return Response(status=304)
    resp = Response(
        render_template(
            'index.html',
            title='Startup News Digest',
            news_list=models.StartupNews.query.order_by('rank').all(),
            navs=[('Startup News', 'http://news.dbanotes.net/news'),
                  ('New', 'http://news.dbanotes.net/newest'),
                  ('Comments', 'http://news.dbanotes.net/newcomments'),
                  ('Leaders', 'http://news.dbanotes.net/leaders'),
                  ('Submit', 'http://news.dbanotes.net/submit')],
            last_updated=dt and human(dt, 1)))
    set_cache(resp, dt)
    return resp
Example #30
0
def hackernews():
    dt = models.LastUpdated.get('hackernews')
    if dt and not is_resource_modified(request.environ, None, None, last_modified=dt):
        return Response(status=304)
    resp = Response(render_template('index.html',
                title='Hacker News Digest',
                news_list=models.HackerNews.query.order_by('rank').all(),
                navs=[
                    ('Hacker News', 'https://news.ycombinator.com/news'),
                    ('New', 'https://news.ycombinator.com/newest'),
                    ('Comments', 'https://news.ycombinator.com/newcomments'),
                    ('Show', 'https://news.ycombinator.com/show'),
                    ('Ask', 'https://news.ycombinator.com/ask'),
                    ('Jobs', 'https://news.ycombinator.com/jobs'),
                    ('Submit', 'https://news.ycombinator.com/submit')],
                last_updated = dt and human(dt, 1)
            ))
    set_cache(resp, dt)
    return resp
Example #31
0
def hackernews():
    dt = models.LastUpdated.get('hackernews')
    if dt and not is_resource_modified(
            request.environ, None, None, last_modified=dt):
        return Response(status=304)
    resp = Response(
        render_template(
            'index.html',
            title='Hacker News Digest',
            news_list=models.HackerNews.query.order_by('rank').all(),
            navs=[('Hacker News', 'https://news.ycombinator.com/news'),
                  ('New', 'https://news.ycombinator.com/newest'),
                  ('Comments', 'https://news.ycombinator.com/newcomments'),
                  ('Show', 'https://news.ycombinator.com/show'),
                  ('Ask', 'https://news.ycombinator.com/ask'),
                  ('Jobs', 'https://news.ycombinator.com/jobs'),
                  ('Submit', 'https://news.ycombinator.com/submit')],
            last_updated=dt and human(dt, 1)))
    set_cache(resp, dt)
    return resp
Example #32
0
    def prepare_response(self, request=None):
        if request is None:
            environ = dict()
        else:
            environ = request.environ

        guessed_type = mimetypes.guess_type(self.filename)
        mime_type = guessed_type[0] or 'text/plain'

        stream = open(self.filename)

        self.headers['Date'] = http_date()

        if self.cache_timeout and request:
            self.headers.extend((
                ('Etag', '"{:s}"'.format(self.etag)),
                ('Cache-Control', 'max-age={:d}, public'.format(
                    self.cache_timeout)),
            ))

            if not is_resource_modified(environ, self.etag):
                stream.close()
                self.status_code = 304
                return []

            self.headers['Expires'] = http_date(time() + self.cache_timeout)
        else:
            self.headers['Cache-Control'] = 'public'

        self.headers.extend((
            ('Content-Type', mime_type),
            ('Content-Length', str(self.size)),
            ('Last-Modified', http_date(self.mtime))
        ))

        if self.as_attachment:
            self.headers.set('Content-Disposition', 'attachment',
                             filename=self.attachment_filename)

        return wrap_file(environ, stream)
Example #33
0
def filedown(environ, filename, cache=True, cache_timeout=None, download=False, inline=False, real_filename=None):
    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or 'text/plain'
    real_filename = real_filename or filename
    f, mtime, file_size = _opener(real_filename)

    headers = [('Date', http_date())]
    
    d_filename = os.path.basename(filename)
    if download:
        headers.append(('Content-Disposition', 'attachment; filename=%s' % d_filename))
    if inline:
        headers.append(('Content-Disposition', 'inline; filename=%s' % d_filename))
    
    if cache:
        etag = _generate_etag(mtime, file_size, real_filename)
        headers += [
            ('ETag', '"%s"' % etag),
        ]
        if cache_timeout:
            headers += [
                ('Cache-Control', 'max-age=%d, public' % cache_timeout),
                ('Expires', http_date(time() + cache_timeout))
            ]
        if not is_resource_modified(environ, etag, last_modified=mtime):
            f.close()
            return Response(status=304, headers=headers)
    else:
        headers.append(('Cache-Control', 'public'))
    

    headers.extend((
        ('Content-Type', mime_type),
        ('Content-Length', str(file_size)),
        ('Last-Modified', http_date(mtime))
    ))
    
    return Response(wrap_file(environ, f), status=200, headers=headers,
        direct_passthrough=True)
Example #34
0
    def handle_markdown_output(filepath, filename):
        """Output processed markdown.
        """
        stats = os.stat(filename)
        last_modified = http_date(stats.st_mtime)
        etag = "%s-%s-%s" % (
            stats.st_mtime,
            stats.st_size,
            adler32(filename.encode("utf-8")) & 0xFFFFFFFF,
        )

        headers = {
            'Cache-Control': 'no-cache',
        }

        if not is_resource_modified(
                request.environ, etag=etag, last_modified=last_modified):
            return http_response(status=304, headers=headers)

        headers.update({
            'Last-Modified': last_modified,
            'ETag': etag,
        })

        # output processed content
        with open(filename, 'r', encoding='UTF-8') as f:
            body = f.read()
            f.close()

        body = render_template(
            'markdown.html',
            sitename=runtime['name'],
            is_local=is_local_access(),
            base=request.script_root,
            path=request.path,
            content=commonmark.commonmark(body),
        )

        return http_response(body, headers=headers)
Example #35
0
        def resp(environ, start_response):
            headers = [("Date", http_date())]
            if self.cache:
                timeout = self.cache_timeout
                etag = self.generate_etag(file.mtime, file.size, file.name)
                headers += [("Etag", '"%s"' % etag), ("Cache-Control", "max-age=%d, public" % timeout)]
                if not is_resource_modified(environ, etag, last_modified=file.mtime):
                    file.handle.close()
                    start_response("304 Not Modified", headers)
                    return []
                headers.append(("Expires", http_date(time() + timeout)))
            else:
                headers.append(("Cache-Control", "public"))

            headers.extend(
                (
                    ("Content-Type", file.mimetype),
                    ("Content-Length", str(file.size)),
                    ("Last-Modified", http_date(file.mtime)),
                )
            )
            start_response("200 OK", headers)
            return wrap_file(environ, file.handle)
Example #36
0
File: smart.py Project: btubbs/spa
        def resp(environ, start_response):
            file = self.get_file(filepath)
            try:
                headers = [('Date', http_date())]
                if self.cache:
                    timeout = self.cache_timeout
                    etag = self.generate_etag(file.mtime, file.size, file.name)
                    headers += [
                        ('Etag', '"%s"' % etag),
                        ('Cache-Control', 'max-age=%d, public' % timeout)
                    ]
                    if not is_resource_modified(environ, etag, last_modified=file.mtime):
                        start_response('304 Not Modified', headers)
                        return []
                    headers.append(('Expires', http_date(time() + timeout)))
                else:
                    headers.append(('Cache-Control', 'public'))

                contents = self.hash_cache.get_contents(filepath)

                if contents is None:
                    contents = file.handle.read().decode('utf-8')
                    for pat, tpl in self.css_url_patterns:
                        converter = self.get_converter(tpl)
                        contents = pat.sub(converter, contents)
                    self.hash_cache.set_contents(filepath, contents)

                headers.extend((
                    ('Content-Type', file.mimetype),
                    ('Content-Length', len(contents)),
                    ('Last-Modified', http_date(file.mtime))
                ))
                start_response('200 OK', headers)

                return [contents.encode('utf-8')]
            finally:
                file.handle.close()
Example #37
0
    def ep_file(self, request, _urls, path=''):
        """Read a file via WSGI"""

        # Check for unmodified requests
        etag = ('%s-%08x' % (self.etag, zlib.adler32(path.encode())))
        headers = [
            ('Date', http_date()),
            ('Etag', ('"%s"' % etag)),
            ('Cache-Control', ('max-age=%d, public' % CACHE_MAX_AGE)),
            ]
        if not is_resource_modified(request.environ, etag,
                                    last_modified=self.mtime):
            return BaseResponse(status=304, headers=headers)

        # Check for nonexistent files and for directories
        isostat = self.isostat(path)
        if isostat is None:
            raise NotFound()
        if isostat['is_dir']:
            raise Forbidden()

        # Construct file-like object
        start = (isostat['LSN'] * pycdio.ISO_BLOCKSIZE)
        size = isostat['size']
        filelike = IsoFile(self.fh, start, size, self.lock)
        wrapped = wrap_file(request.environ, filelike)

        # Construct WSGI response
        mimetype = (mimetypes.guess_type(path)[0] or 'text/plain')
        headers.extend((
            ('Content-Length', str(size)),
            ('Content-Type', mimetype),
            ('Last-Modified', http_date(self.mtime)),
            ('Expires', http_date(time() + CACHE_MAX_AGE)),
            ))
        return BaseResponse(wrapped, headers=headers, direct_passthrough=True)
Example #38
0
        def resp(environ, start_response):
            headers = [('Date', http_date())]
            if self.cache:
                timeout = self.cache_timeout
                etag = self.generate_etag(file.mtime, file.size, file.name)
                headers += [
                    ('Etag', '"%s"' % etag),
                    ('Cache-Control', 'max-age=%d, public' % timeout)
                ]
                if not is_resource_modified(environ, etag, last_modified=file.mtime):
                    file.handle.close()
                    start_response('304 Not Modified', headers)
                    return []
                headers.append(('Expires', http_date(time() + timeout)))
            else:
                headers.append(('Cache-Control', 'public'))

            headers.extend((
                ('Content-Type', file.mimetype),
                ('Content-Length', str(file.size)),
                ('Last-Modified', http_date(file.mtime))
            ))
            start_response('200 OK', headers)
            return wrap_file(environ, file.handle)
Example #39
0
def filedown(environ,
             filename,
             cache=True,
             cache_timeout=None,
             action=None,
             real_filename=None,
             x_sendfile=False,
             x_header_name=None,
             x_filename=None,
             fileobj=None,
             default_mimetype='application/octet-stream'):
    """
    @param filename: is used for display in download
    @param real_filename: if used for the real file location
    @param x_urlfile: is only used in x-sendfile, and be set to x-sendfile header
    @param fileobj: if provided, then returned as file content
    @type fileobj: (fobj, mtime, size)

    filedown now support web server controlled download, you should set
    xsendfile=True, and add x_header, for example:

    nginx
        ('X-Accel-Redirect', '/path/to/local_url')
    apache
        ('X-Sendfile', '/path/to/local_url')
    """
    from .common import safe_str
    from werkzeug.http import parse_range_header

    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or default_mimetype
    real_filename = real_filename or filename

    #make common headers
    headers = []
    headers.append(('Content-Type', mime_type))
    d_filename = _get_download_filename(environ, os.path.basename(filename))
    if action == 'download':
        headers.append(('Content-Disposition', 'attachment; %s' % d_filename))
    elif action == 'inline':
        headers.append(('Content-Disposition', 'inline; %s' % d_filename))
    if x_sendfile:
        if not x_header_name or not x_filename:
            raise Exception("x_header_name or x_filename can't be empty")
        headers.append((x_header_name, safe_str(x_filename)))
        return Response('',
                        status=200,
                        headers=headers,
                        direct_passthrough=True)
    else:
        request = environ.get('werkzeug.request')
        if request:
            range = request.range
        else:
            range = parse_range_header(environ.get('HTTP_RANGE'))
        #when request range,only recognize "bytes" as range units
        if range and range.units == "bytes":
            try:
                fsize = os.path.getsize(real_filename)
            except OSError as e:
                return Response("Not found", status=404)
            mtime = datetime.utcfromtimestamp(os.path.getmtime(real_filename))
            mtime_str = http_date(mtime)
            if cache:
                etag = _generate_etag(mtime, fsize, real_filename)
            else:
                etag = mtime_str

            if_range = environ.get('HTTP_IF_RANGE')
            if if_range:
                check_if_range_ok = (if_range.strip('"') == etag)
                #print "check_if_range_ok (%s) = (%s ==%s)"%(check_if_range_ok,if_range.strip('"'),etag)
            else:
                check_if_range_ok = True

            rbegin, rend = range.ranges[0]
            if check_if_range_ok and (rbegin + 1) < fsize:
                if rend == None:
                    rend = fsize

                headers.append(('Content-Length', str(rend - rbegin)))
                #werkzeug do not count rend with the same way of rfc7233,so -1
                headers.append(
                    ('Content-Range',
                     '%s %d-%d/%d' % (range.units, rbegin, rend - 1, fsize)))
                headers.append(('Last-Modified', mtime_str))
                if cache:
                    headers.append(('ETag', '"%s"' % etag))
                #for small file, read it to memory and return directly
                #and this can avoid some issue with google chrome
                if (rend - rbegin) < FileIterator.chunk_size:
                    s = "".join([
                        chunk
                        for chunk in FileIterator(real_filename, rbegin, rend)
                    ])
                    return Response(s,
                                    status=206,
                                    headers=headers,
                                    direct_passthrough=True)
                else:
                    return Response(FileIterator(real_filename, rbegin, rend),
                                    status=206,
                                    headers=headers,
                                    direct_passthrough=True)

        #process fileobj
        if fileobj:
            f, mtime, file_size = fileobj
        else:
            f, mtime, file_size = _opener(real_filename)
        headers.append(('Date', http_date()))

        if cache:
            etag = _generate_etag(mtime, file_size, real_filename)
            headers += [
                ('ETag', '"%s"' % etag),
            ]
            if cache_timeout:
                headers += [('Cache-Control',
                             'max-age=%d, public' % cache_timeout),
                            ('Expires', http_date(time() + cache_timeout))]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                return Response(status=304, headers=headers)
        else:
            headers.append(('Cache-Control', 'public'))

        headers.extend(
            (('Content-Length', str(file_size)), ('Last-Modified',
                                                  http_date(mtime))))

        return Response(wrap_file(environ, f),
                        status=200,
                        headers=headers,
                        direct_passthrough=True)
Example #40
0
def filedown(environ, filename, cache=True, cache_timeout=None, 
    action=None, real_filename=None, x_sendfile=False,
    x_header_name=None, x_filename=None, fileobj=None,
    default_mimetype='application/octet-stream'):
    """
    @param filename: is used for display in download
    @param real_filename: if used for the real file location
    @param x_urlfile: is only used in x-sendfile, and be set to x-sendfile header
    @param fileobj: if provided, then returned as file content 
    @type fileobj: (fobj, mtime, size)
    
    filedown now support web server controlled download, you should set
    xsendfile=True, and add x_header, for example:
    
    nginx
        ('X-Accel-Redirect', '/path/to/local_url')
    apache
        ('X-Sendfile', '/path/to/local_url')
    """
    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or default_mimetype
    real_filename = real_filename or filename
    
    #make common headers
    headers = []
    headers.append(('Content-Type', mime_type))
    d_filename = _get_download_filename(environ, os.path.basename(filename))
    if action == 'download':
        headers.append(('Content-Disposition', 'attachment; %s' % d_filename))
    elif action == 'inline':
        headers.append(('Content-Disposition', 'inline; %s' % d_filename))
    if x_sendfile:
        if not x_header_name or not x_filename:
            raise Exception, "x_header_name or x_filename can't be empty"
        headers.append((x_header_name, x_filename))
        return Response('', status=200, headers=headers,
            direct_passthrough=True)
    else:
        #process fileobj
        if fileobj:
            f, mtime, file_size = fileobj
        else:
            f, mtime, file_size = _opener(real_filename)
        headers.append(('Date', http_date()))
    
        if cache:
            etag = _generate_etag(mtime, file_size, real_filename)
            headers += [
                ('ETag', '"%s"' % etag),
            ]
            if cache_timeout:
                headers += [
                    ('Cache-Control', 'max-age=%d, public' % cache_timeout),
                    ('Expires', http_date(time() + cache_timeout))
                ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                return Response(status=304, headers=headers)
        else:
            headers.append(('Cache-Control', 'public'))
    

        headers.extend((
            ('Content-Length', str(file_size)),
            ('Last-Modified', http_date(mtime))
        ))
    
        return Response(wrap_file(environ, f), status=200, headers=headers,
            direct_passthrough=True)
Example #41
0
def filedown(environ, filename, cache=True, cache_timeout=None, 
    action=None, real_filename=None, x_sendfile=False,
    x_header_name=None, x_filename=None, fileobj=None,
    default_mimetype='application/octet-stream'):
    """
    @param filename: is used for display in download
    @param real_filename: if used for the real file location
    @param x_urlfile: is only used in x-sendfile, and be set to x-sendfile header
    @param fileobj: if provided, then returned as file content 
    @type fileobj: (fobj, mtime, size)
    
    filedown now support web server controlled download, you should set
    xsendfile=True, and add x_header, for example:
    
    nginx
        ('X-Accel-Redirect', '/path/to/local_url')
    apache
        ('X-Sendfile', '/path/to/local_url')
    """
    from werkzeug.http import parse_range_header
    
    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or default_mimetype
    real_filename = real_filename or filename
    
    #make common headers
    headers = []
    headers.append(('Content-Type', mime_type))
    d_filename = _get_download_filename(environ, os.path.basename(filename))
    if action == 'download':
        headers.append(('Content-Disposition', 'attachment; %s' % d_filename))
    elif action == 'inline':
        headers.append(('Content-Disposition', 'inline; %s' % d_filename))
    if x_sendfile:
        if not x_header_name or not x_filename:
            raise Exception, "x_header_name or x_filename can't be empty"
        headers.append((x_header_name, x_filename))
        return Response('', status=200, headers=headers,
            direct_passthrough=True)
    else:
        request = environ.get('werkzeug.request')
        if request:
            range = request.range
        else:
            range = parse_range_header(environ.get('HTTP_RANGE'))
        #when request range,only recognize "bytes" as range units
        if range!=None and range.units=="bytes":
            rbegin,rend = range.ranges[0]
            try:
                fsize = os.path.getsize(real_filename)
            except OSError,e:
                return Response("Not found",status=404)
            if (rbegin+1)<fsize:
                if rend == None:
                    rend = fsize-1
                headers.append(('Content-Length',str(rend-rbegin+1)))
                headers.append(('Content-Range','%s %d-%d/%d' %(range.units,rbegin, rend, fsize)))
                return Response(FileIterator(real_filename,rbegin,rend),
                    status=206, headers=headers, direct_passthrough=True)
        
        #process fileobj
        if fileobj:
            f, mtime, file_size = fileobj
        else:
            f, mtime, file_size = _opener(real_filename)
        headers.append(('Date', http_date()))
    
        if cache:
            etag = _generate_etag(mtime, file_size, real_filename)
            headers += [
                ('ETag', '"%s"' % etag),
            ]
            if cache_timeout:
                headers += [
                    ('Cache-Control', 'max-age=%d, public' % cache_timeout),
                    ('Expires', http_date(time() + cache_timeout))
                ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                return Response(status=304, headers=headers)
        else:
            headers.append(('Cache-Control', 'public'))
    

        headers.extend((
            ('Content-Length', str(file_size)),
            ('Last-Modified', http_date(mtime))
        ))
    
        return Response(wrap_file(environ, f), status=200, headers=headers,
            direct_passthrough=True)
Example #42
0
def filedown(environ, filename, cache=True, cache_timeout=None,
    action=None, real_filename=None, x_sendfile=False,
    x_header_name=None, x_filename=None, fileobj=None,
    default_mimetype='application/octet-stream'):
    """
    @param filename: is used for display in download
    @param real_filename: if used for the real file location
    @param x_urlfile: is only used in x-sendfile, and be set to x-sendfile header
    @param fileobj: if provided, then returned as file content
    @type fileobj: (fobj, mtime, size)

    filedown now support web server controlled download, you should set
    xsendfile=True, and add x_header, for example:

    nginx
        ('X-Accel-Redirect', '/path/to/local_url')
    apache
        ('X-Sendfile', '/path/to/local_url')
    """
    from .common import safe_str
    from werkzeug.http import parse_range_header

    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or default_mimetype
    real_filename = real_filename or filename

    #make common headers
    headers = []
    headers.append(('Content-Type', mime_type))
    d_filename = _get_download_filename(environ, os.path.basename(filename))
    if action == 'download':
        headers.append(('Content-Disposition', 'attachment; %s' % d_filename))
    elif action == 'inline':
        headers.append(('Content-Disposition', 'inline; %s' % d_filename))
    if x_sendfile:
        if not x_header_name or not x_filename:
            raise Exception("x_header_name or x_filename can't be empty")
        headers.append((x_header_name, safe_str(x_filename)))
        return Response('', status=200, headers=headers,
            direct_passthrough=True)
    else:
        request = environ.get('werkzeug.request')
        if request:
            range = request.range
        else:
            range = parse_range_header(environ.get('HTTP_RANGE'))
        #when request range,only recognize "bytes" as range units
        if range and range.units=="bytes":
            try:
                fsize = os.path.getsize(real_filename)
            except OSError as e:
                return Response("Not found",status=404)
            mtime = datetime.utcfromtimestamp(os.path.getmtime(real_filename))
            mtime_str = http_date(mtime)
            if cache:
                etag = _generate_etag(mtime, fsize, real_filename)
            else:
                etag = mtime_str

            if_range = environ.get('HTTP_IF_RANGE')
            if if_range:
                check_if_range_ok = (if_range.strip('"')==etag)
                #print "check_if_range_ok (%s) = (%s ==%s)"%(check_if_range_ok,if_range.strip('"'),etag)
            else:
                check_if_range_ok = True

            rbegin,rend = range.ranges[0]
            if check_if_range_ok and (rbegin+1)<fsize:
                if rend == None:
                    rend = fsize

                headers.append(('Content-Length',str(rend-rbegin)))
                #werkzeug do not count rend with the same way of rfc7233,so -1
                headers.append(('Content-Range','%s %d-%d/%d' %(range.units,rbegin, rend-1, fsize)))
                headers.append(('Last-Modified', mtime_str))
                if cache:
                    headers.append(('ETag', '"%s"' % etag))
                #for small file, read it to memory and return directly
                #and this can avoid some issue with google chrome
                if (rend-rbegin) < FileIterator.chunk_size:
                    s = "".join([chunk for chunk in FileIterator(real_filename,rbegin,rend)])
                    return Response(s,status=206, headers=headers, direct_passthrough=True)
                else:
                    return Response(FileIterator(real_filename,rbegin,rend),
                        status=206, headers=headers, direct_passthrough=True)

        #process fileobj
        if fileobj:
            f, mtime, file_size = fileobj
        else:
            f, mtime, file_size = _opener(real_filename)
        headers.append(('Date', http_date()))

        if cache:
            etag = _generate_etag(mtime, file_size, real_filename)
            headers += [
                ('ETag', '"%s"' % etag),
            ]
            if cache_timeout:
                headers += [
                    ('Cache-Control', 'max-age=%d, public' % cache_timeout),
                    ('Expires', http_date(time() + cache_timeout))
                ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                return Response(status=304, headers=headers)
        else:
            headers.append(('Cache-Control', 'public'))


        headers.extend((
            ('Content-Length', str(file_size)),
            ('Last-Modified', http_date(mtime))
        ))

        return Response(wrap_file(environ, f), status=200, headers=headers,
            direct_passthrough=True)
    def make_conditional(
        self,
        request_or_environ: "WSGIEnvironment",
        accept_ranges: t.Union[bool, str] = False,
        complete_length: t.Optional[int] = None,
    ) -> "Response":
        """Make the response conditional to the request.  This method works
        best if an etag was defined for the response already.  The `add_etag`
        method can be used to do that.  If called without etag just the date
        header is set.

        This does nothing if the request method in the request or environ is
        anything but GET or HEAD.

        For optimal performance when handling range requests, it's recommended
        that your response data object implements `seekable`, `seek` and `tell`
        methods as described by :py:class:`io.IOBase`.  Objects returned by
        :meth:`~werkzeug.wsgi.wrap_file` automatically implement those methods.

        It does not remove the body of the response because that's something
        the :meth:`__call__` function does for us automatically.

        Returns self so that you can do ``return resp.make_conditional(req)``
        but modifies the object in-place.

        :param request_or_environ: a request object or WSGI environment to be
                                   used to make the response conditional
                                   against.
        :param accept_ranges: This parameter dictates the value of
                              `Accept-Ranges` header. If ``False`` (default),
                              the header is not set. If ``True``, it will be set
                              to ``"bytes"``. If ``None``, it will be set to
                              ``"none"``. If it's a string, it will use this
                              value.
        :param complete_length: Will be used only in valid Range Requests.
                                It will set `Content-Range` complete length
                                value and compute `Content-Length` real value.
                                This parameter is mandatory for successful
                                Range Requests completion.
        :raises: :class:`~werkzeug.exceptions.RequestedRangeNotSatisfiable`
                 if `Range` header could not be parsed or satisfied.

        .. versionchanged:: 2.0
            Range processing is skipped if length is 0 instead of
            raising a 416 Range Not Satisfiable error.
        """
        environ = _get_environ(request_or_environ)
        if environ["REQUEST_METHOD"] in ("GET", "HEAD"):
            # if the date is not in the headers, add it now.  We however
            # will not override an already existing header.  Unfortunately
            # this header will be overriden by many WSGI servers including
            # wsgiref.
            if "date" not in self.headers:
                self.headers["Date"] = http_date()
            accept_ranges = _clean_accept_ranges(accept_ranges)
            is206 = self._process_range_request(environ, complete_length,
                                                accept_ranges)
            if not is206 and not is_resource_modified(
                    environ,
                    self.headers.get("etag"),
                    None,
                    self.headers.get("last-modified"),
            ):
                if parse_etags(environ.get("HTTP_IF_MATCH")):
                    self.status_code = 412
                else:
                    self.status_code = 304
            if (self.automatically_set_content_length
                    and "content-length" not in self.headers):
                length = self.calculate_content_length()
                if length is not None:
                    self.headers["Content-Length"] = length
        return self
Example #44
0
def filedown(environ,
             filename,
             cache=True,
             cache_timeout=None,
             action=None,
             real_filename=None,
             x_sendfile=False,
             x_header_name=None,
             x_filename=None,
             fileobj=None,
             default_mimetype='application/octet-stream'):
    """
    @param filename: is used for display in download
    @param real_filename: if used for the real file location
    @param x_urlfile: is only used in x-sendfile, and be set to x-sendfile header
    @param fileobj: if provided, then returned as file content 
    @type fileobj: (fobj, mtime, size)
    
    filedown now support web server controlled download, you should set
    xsendfile=True, and add x_header, for example:
    
    nginx
        ('X-Accel-Redirect', '/path/to/local_url')
    apache
        ('X-Sendfile', '/path/to/local_url')
    """
    from werkzeug.http import parse_range_header

    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or default_mimetype
    real_filename = real_filename or filename

    #make common headers
    headers = []
    headers.append(('Content-Type', mime_type))
    d_filename = _get_download_filename(environ, os.path.basename(filename))
    if action == 'download':
        headers.append(('Content-Disposition', 'attachment; %s' % d_filename))
    elif action == 'inline':
        headers.append(('Content-Disposition', 'inline; %s' % d_filename))
    if x_sendfile:
        if not x_header_name or not x_filename:
            raise Exception, "x_header_name or x_filename can't be empty"
        headers.append((x_header_name, x_filename))
        return Response('',
                        status=200,
                        headers=headers,
                        direct_passthrough=True)
    else:
        request = environ.get('werkzeug.request')
        if request:
            range = request.range
        else:
            range = parse_range_header(environ.get('HTTP_RANGE'))
        #when request range,only recognize "bytes" as range units
        if range != None and range.units == "bytes":
            rbegin, rend = range.ranges[0]
            try:
                fsize = os.path.getsize(real_filename)
            except OSError, e:
                return Response("Not found", status=404)
            if (rbegin + 1) < fsize:
                if rend == None:
                    rend = fsize - 1
                headers.append(('Content-Length', str(rend - rbegin + 1)))
                headers.append(
                    ('Content-Range',
                     '%s %d-%d/%d' % (range.units, rbegin, rend, fsize)))
                return Response(FileIterator(real_filename, rbegin, rend),
                                status=206,
                                headers=headers,
                                direct_passthrough=True)

        #process fileobj
        if fileobj:
            f, mtime, file_size = fileobj
        else:
            f, mtime, file_size = _opener(real_filename)
        headers.append(('Date', http_date()))

        if cache:
            etag = _generate_etag(mtime, file_size, real_filename)
            headers += [
                ('ETag', '"%s"' % etag),
            ]
            if cache_timeout:
                headers += [('Cache-Control',
                             'max-age=%d, public' % cache_timeout),
                            ('Expires', http_date(time() + cache_timeout))]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                return Response(status=304, headers=headers)
        else:
            headers.append(('Cache-Control', 'public'))

        headers.extend(
            (('Content-Length', str(file_size)), ('Last-Modified',
                                                  http_date(mtime))))

        return Response(wrap_file(environ, f),
                        status=200,
                        headers=headers,
                        direct_passthrough=True)
Example #45
0
def filedown(environ, filename, cache=True, cache_timeout=None, 
    action=None, real_filename=None, x_sendfile=False,
    x_header_name=None, x_filename=None, fileobj=None,
    default_mimetype='application/octet-stream'):
    """
    @param filename: is used for display in download
    @param real_filename: if used for the real file location
    @param x_urlfile: is only used in x-sendfile, and be set to x-sendfile header
    @param fileobj: if provided, then returned as file content 
    @type fileobj: (fobj, mtime, size)
    
    filedown now support web server controlled download, you should set
    xsendfile=True, and add x_header, for example:
    
    nginx
        ('X-Accel-Redirect', '/path/to/local_url')
    apache
        ('X-Sendfile', '/path/to/local_url')
    """
    guessed_type = mimetypes.guess_type(filename)
    mime_type = guessed_type[0] or default_mimetype
    real_filename = real_filename or filename
    
    #make common headers
    headers = []
    headers.append(('Content-Type', mime_type))
    d_filename = os.path.basename(filename)
    if action == 'download':
        headers.append(('Content-Disposition', 'attachment; filename=%s' % d_filename))
    elif action == 'inline':
        headers.append(('Content-Disposition', 'inline; filename=%s' % d_filename))
    if x_sendfile:
        if not x_header_name or not x_filename:
            raise Exception, "x_header_name or x_filename can't be empty"
        headers.append((x_header_name, x_filename))
        return Response('', status=200, headers=headers,
            direct_passthrough=True)
    else:
        #process fileobj
        if fileobj:
            f, mtime, file_size = fileobj
        else:
            f, mtime, file_size = _opener(real_filename)
        headers.append(('Date', http_date()))
    
        if cache:
            etag = _generate_etag(mtime, file_size, real_filename)
            headers += [
                ('ETag', '"%s"' % etag),
            ]
            if cache_timeout:
                headers += [
                    ('Cache-Control', 'max-age=%d, public' % cache_timeout),
                    ('Expires', http_date(time() + cache_timeout))
                ]
            if not is_resource_modified(environ, etag, last_modified=mtime):
                f.close()
                return Response(status=304, headers=headers)
        else:
            headers.append(('Cache-Control', 'public'))
    

        headers.extend((
            ('Content-Length', str(file_size)),
            ('Last-Modified', http_date(mtime))
        ))
    
        return Response(wrap_file(environ, f), status=200, headers=headers,
            direct_passthrough=True)