Skip to content

Commit

Permalink
refactor sendfile and add an example.
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitc committed May 11, 2011
1 parent fc69d5e commit c17f723
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 65 deletions.
1 change: 1 addition & 0 deletions examples/hello.txt
@@ -0,0 +1 @@
Hello world!
23 changes: 23 additions & 0 deletions examples/sendfile.py
@@ -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 changes: 66 additions & 0 deletions gunicorn/http/_sendfile.py
@@ -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
61 changes: 0 additions & 61 deletions gunicorn/http/sendfile.py

This file was deleted.

12 changes: 8 additions & 4 deletions gunicorn/http/wsgi.py
Expand Up @@ -15,8 +15,11 @@
try:
# Python 3.3 has os.sendfile().
from os import sendfile
except:
from sendfile import sendfile
except ImportError:
try:
from _senfile import sendfile
except ImportError:
sendfile = None

NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')

Expand Down Expand Up @@ -271,8 +274,9 @@ def sendfile_all(self, fileno, sockno, offset, nbytes):
sent += sendfile(fileno, sockno, offset+sent, nbytes-sent)

def write_file(self, respiter):
if sendfile and hasattr(respiter.filelike, 'fileno') and \
hasattr(respiter.filelike, 'tell'):
if sendfile is not None and \
hasattr(respiter.filelike, 'fileno') and \
hasattr(respiter.filelike, 'tell'):

fileno = respiter.filelike.fileno()
fd_offset = os.lseek(fileno, 0, os.SEEK_CUR)
Expand Down

0 comments on commit c17f723

Please sign in to comment.