mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
refactor sendfile and add an example.
This commit is contained in:
parent
fc69d5e17c
commit
c17f7230e8
1
examples/hello.txt
Normal file
1
examples/hello.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hello world!
|
||||||
23
examples/sendfile.py
Normal file
23
examples/sendfile.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -
|
||||||
|
#
|
||||||
|
# This file is part of gunicorn released under the MIT license.
|
||||||
|
# See the NOTICE for more information.
|
||||||
|
#
|
||||||
|
# Example code from Eventlet sources
|
||||||
|
|
||||||
|
import os
|
||||||
|
from wsgiref.validate import validator
|
||||||
|
|
||||||
|
#@validator
|
||||||
|
def app(environ, start_response):
|
||||||
|
"""Simplest possible application object"""
|
||||||
|
status = '200 OK'
|
||||||
|
fname = os.path.join(os.path.dirname(__file__), "hello.txt")
|
||||||
|
f = open(fname, 'rb')
|
||||||
|
|
||||||
|
response_headers = [
|
||||||
|
('Content-type','text/plain'),
|
||||||
|
]
|
||||||
|
start_response(status, response_headers)
|
||||||
|
|
||||||
|
return environ['wsgi.file_wrapper'](f)
|
||||||
66
gunicorn/http/_sendfile.py
Normal file
66
gunicorn/http/_sendfile.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: utf-8 -
|
||||||
|
#
|
||||||
|
# This file is part of gunicorn released under the MIT license.
|
||||||
|
# See the NOTICE for more information.
|
||||||
|
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ctypes
|
||||||
|
import ctypes.util
|
||||||
|
except MemoryError:
|
||||||
|
# selinux execmem denial
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=488396
|
||||||
|
raise ImportError
|
||||||
|
|
||||||
|
SUPPORTED_PLATFORMS = (
|
||||||
|
'darwin',
|
||||||
|
'freebsd',
|
||||||
|
'dragonfly'
|
||||||
|
'linux2')
|
||||||
|
|
||||||
|
if sys.version_info < (2, 6) or \
|
||||||
|
sys.platform not in SUPPORTED_PLATFORMS:
|
||||||
|
raise ImportError("sendfile isn't supported on this platform")
|
||||||
|
|
||||||
|
_libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
|
||||||
|
_sendfile = _libc.sendfile
|
||||||
|
|
||||||
|
def sendfile(fdout, fdin, offset, nbytes):
|
||||||
|
if sys.platform == 'darwin':
|
||||||
|
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
|
||||||
|
ctypes.POINTER(ctypes.c_uint64), ctypes.c_voidp,
|
||||||
|
ctypes.c_int]
|
||||||
|
_nbytes = ctypes.c_uint64(nbytes)
|
||||||
|
result = _sendfile(fdin, fdout, offset, _nbytes, None, 0)
|
||||||
|
if result == -1:
|
||||||
|
e = ctypes.get_errno()
|
||||||
|
if e == errno.EAGAIN and _nbytes.value:
|
||||||
|
return nbytes.value
|
||||||
|
raise OSError(e, os.strerror(e))
|
||||||
|
return _nbytes.value
|
||||||
|
elif sys.platform in ('freebsd', 'dragonfly',):
|
||||||
|
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
|
||||||
|
ctypes.c_uint64, ctypes.c_voidp,
|
||||||
|
ctypes.POINTER(ctypes.c_uint64), ctypes.c_int]
|
||||||
|
_sbytes = ctypes.c_uint64(nbytes)
|
||||||
|
result = _sendfile(fdin, fdout, offset, nbytes, None, _sbytes, 0)
|
||||||
|
if result == -1:
|
||||||
|
e = ctypes.get_errno()
|
||||||
|
if e == errno.EAGAIN and _sbytes.value:
|
||||||
|
return _sbytes.value
|
||||||
|
raise OSError(e, os.strerror(e))
|
||||||
|
return _sbytes.value
|
||||||
|
|
||||||
|
else:
|
||||||
|
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int,
|
||||||
|
ctypes.POINTER(ctypes.c_uint64), ctypes.c_size_t]
|
||||||
|
|
||||||
|
_offset = ctypes.c_uint64(offset)
|
||||||
|
sent = _sendfile(fdout, fdin, _offset, nbytes)
|
||||||
|
if sent == -1:
|
||||||
|
e = ctypess.get_errno()
|
||||||
|
raise OSError(e, os.strerror(e))
|
||||||
|
return sent
|
||||||
@ -1,61 +0,0 @@
|
|||||||
# -*- coding: utf-8 -
|
|
||||||
#
|
|
||||||
# This file is part of gunicorn released under the MIT license.
|
|
||||||
# See the NOTICE for more information.
|
|
||||||
|
|
||||||
import errno
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# Python on Solaris compiled with Sun Studio doesn't have ctypes.
|
|
||||||
try:
|
|
||||||
import ctypes
|
|
||||||
import ctypes.util
|
|
||||||
|
|
||||||
if sys.version_info >= (2, 6):
|
|
||||||
_libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
|
|
||||||
_sendfile = _libc.sendfile
|
|
||||||
else:
|
|
||||||
_sendfile = None
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
_sendfile = None
|
|
||||||
|
|
||||||
if _sendfile:
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
# MacOS X - int sendfile(int fd, int s, off_t offset, off_t *len,
|
|
||||||
# struct sf_hdtr *hdtr, int flags);
|
|
||||||
|
|
||||||
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
|
|
||||||
ctypes.POINTER(ctypes.c_uint64), ctypes.c_voidp,
|
|
||||||
ctypes.c_int]
|
|
||||||
|
|
||||||
def sendfile(fileno, sockno, offset, nbytes):
|
|
||||||
_nbytes = ctypes.c_uint64(nbytes)
|
|
||||||
result = _sendfile(fileno, sockno, offset, _nbytes, None, 0)
|
|
||||||
if result == -1:
|
|
||||||
e = ctypes.get_errno()
|
|
||||||
if e == errno.EAGAIN and _nbytes.value:
|
|
||||||
return _nbytes.value
|
|
||||||
raise OSError(e, os.strerror(e))
|
|
||||||
return _nbytes.value
|
|
||||||
|
|
||||||
elif sys.platform == 'linux2':
|
|
||||||
# Linux - size_t sendfile(int out_fd, int in_fd, off_t *offset,
|
|
||||||
# size_t count);
|
|
||||||
|
|
||||||
_sendfile.argtypes = [ctypes.c_int, ctypes.c_int,
|
|
||||||
ctypes.POINTER(ctypes.c_uint64), ctypes.c_size_t]
|
|
||||||
|
|
||||||
def sendfile(fileno, sockno, offset, nbytes):
|
|
||||||
_offset = ctypes.c_uint64(offset)
|
|
||||||
result = _sendfile(sockno, fileno, _offset, nbytes)
|
|
||||||
if result == -1:
|
|
||||||
e = ctypes.get_errno()
|
|
||||||
raise OSError(e, os.strerror(e))
|
|
||||||
return result
|
|
||||||
|
|
||||||
else:
|
|
||||||
sendfile = None
|
|
||||||
else:
|
|
||||||
sendfile = None
|
|
||||||
@ -15,8 +15,11 @@ import gunicorn.util as util
|
|||||||
try:
|
try:
|
||||||
# Python 3.3 has os.sendfile().
|
# Python 3.3 has os.sendfile().
|
||||||
from os import sendfile
|
from os import sendfile
|
||||||
except:
|
except ImportError:
|
||||||
from sendfile import sendfile
|
try:
|
||||||
|
from _senfile import sendfile
|
||||||
|
except ImportError:
|
||||||
|
sendfile = None
|
||||||
|
|
||||||
NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
|
NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
|
||||||
|
|
||||||
@ -271,8 +274,9 @@ class Response(object):
|
|||||||
sent += sendfile(fileno, sockno, offset+sent, nbytes-sent)
|
sent += sendfile(fileno, sockno, offset+sent, nbytes-sent)
|
||||||
|
|
||||||
def write_file(self, respiter):
|
def write_file(self, respiter):
|
||||||
if sendfile and hasattr(respiter.filelike, 'fileno') and \
|
if sendfile is not None and \
|
||||||
hasattr(respiter.filelike, 'tell'):
|
hasattr(respiter.filelike, 'fileno') and \
|
||||||
|
hasattr(respiter.filelike, 'tell'):
|
||||||
|
|
||||||
fileno = respiter.filelike.fileno()
|
fileno = respiter.filelike.fileno()
|
||||||
fd_offset = os.lseek(fileno, 0, os.SEEK_CUR)
|
fd_offset = os.lseek(fileno, 0, os.SEEK_CUR)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user