mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
new http parser. need to add TE support yet
This commit is contained in:
parent
09bcc05c5c
commit
fcbaae054a
0
examples/djangotest/__init__.py
Executable file
0
examples/djangotest/__init__.py
Executable file
11
examples/djangotest/manage.py
Executable file
11
examples/djangotest/manage.py
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from django.core.management import execute_manager
|
||||||
|
try:
|
||||||
|
import settings # Assumed to be in the same directory.
|
||||||
|
except ImportError:
|
||||||
|
import sys
|
||||||
|
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
execute_manager(settings)
|
||||||
80
examples/djangotest/settings.py
Executable file
80
examples/djangotest/settings.py
Executable file
@ -0,0 +1,80 @@
|
|||||||
|
# Django settings for djangotest project.
|
||||||
|
|
||||||
|
DEBUG = True
|
||||||
|
TEMPLATE_DEBUG = DEBUG
|
||||||
|
|
||||||
|
ADMINS = (
|
||||||
|
# ('Your Name', 'your_email@domain.com'),
|
||||||
|
)
|
||||||
|
|
||||||
|
MANAGERS = ADMINS
|
||||||
|
|
||||||
|
DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||||
|
DATABASE_NAME = 'test.db' # Or path to database file if using sqlite3.
|
||||||
|
DATABASE_USER = '' # Not used with sqlite3.
|
||||||
|
DATABASE_PASSWORD = '' # Not used with sqlite3.
|
||||||
|
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
|
||||||
|
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
|
||||||
|
|
||||||
|
# Local time zone for this installation. Choices can be found here:
|
||||||
|
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||||
|
# although not all choices may be available on all operating systems.
|
||||||
|
# If running in a Windows environment this must be set to the same as your
|
||||||
|
# system time zone.
|
||||||
|
TIME_ZONE = 'America/Chicago'
|
||||||
|
|
||||||
|
# Language code for this installation. All choices can be found here:
|
||||||
|
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
SITE_ID = 1
|
||||||
|
|
||||||
|
# If you set this to False, Django will make some optimizations so as not
|
||||||
|
# to load the internationalization machinery.
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
# Absolute path to the directory that holds media.
|
||||||
|
# Example: "/home/media/media.lawrence.com/"
|
||||||
|
MEDIA_ROOT = ''
|
||||||
|
|
||||||
|
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||||
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
|
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||||
|
MEDIA_URL = ''
|
||||||
|
|
||||||
|
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||||
|
# trailing slash.
|
||||||
|
# Examples: "http://foo.com/media/", "/media/".
|
||||||
|
ADMIN_MEDIA_PREFIX = '/media/'
|
||||||
|
|
||||||
|
# Make this unique, and don't share it with anybody.
|
||||||
|
SECRET_KEY = '+$ke3e&)ai+p2vzg@!ku9m=xq=b02-jam9m=_w%n*ys@a8r8va'
|
||||||
|
|
||||||
|
# List of callables that know how to import templates from various sources.
|
||||||
|
TEMPLATE_LOADERS = (
|
||||||
|
'django.template.loaders.filesystem.load_template_source',
|
||||||
|
'django.template.loaders.app_directories.load_template_source',
|
||||||
|
# 'django.template.loaders.eggs.load_template_source',
|
||||||
|
)
|
||||||
|
|
||||||
|
MIDDLEWARE_CLASSES = (
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
)
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'djangotest.urls'
|
||||||
|
|
||||||
|
TEMPLATE_DIRS = (
|
||||||
|
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
||||||
|
# Always use forward slashes, even on Windows.
|
||||||
|
# Don't forget to use absolute paths, not relative paths.
|
||||||
|
)
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.sites',
|
||||||
|
'djangotest.testing'
|
||||||
|
)
|
||||||
0
examples/djangotest/testing/__init__.py
Executable file
0
examples/djangotest/testing/__init__.py
Executable file
3
examples/djangotest/testing/models.py
Executable file
3
examples/djangotest/testing/models.py
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
33
examples/djangotest/testing/templates/base.html
Normal file
33
examples/djangotest/testing/templates/base.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>gunicorn django example app</title>
|
||||||
|
<!--[if IE]>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// allow IE to recognize HTMl5 elements
|
||||||
|
document.createElement('section');
|
||||||
|
document.createElement('article');
|
||||||
|
document.createElement('aside');
|
||||||
|
document.createElement('footer');
|
||||||
|
document.createElement('header');
|
||||||
|
document.createElement('nav');
|
||||||
|
document.createElement('time');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header id="top">
|
||||||
|
<h1>test app</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<footer></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
16
examples/djangotest/testing/templates/home.html
Normal file
16
examples/djangotest/testing/templates/home.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form method="post">
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
<input type="submit" id="submit" value="submit">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h2>Got</h2>
|
||||||
|
{% if subject %}
|
||||||
|
<p><strong>subject:</strong><br>{{ subject}}</p>
|
||||||
|
<p><strong>message:</strong><br>{{ message }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock content %}
|
||||||
23
examples/djangotest/testing/tests.py
Executable file
23
examples/djangotest/testing/tests.py
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
This file demonstrates two different styles of tests (one doctest and one
|
||||||
|
unittest). These will both pass when you run "manage.py test".
|
||||||
|
|
||||||
|
Replace these with more appropriate tests for your application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
class SimpleTest(TestCase):
|
||||||
|
def test_basic_addition(self):
|
||||||
|
"""
|
||||||
|
Tests that 1 + 1 always equals 2.
|
||||||
|
"""
|
||||||
|
self.failUnlessEqual(1 + 1, 2)
|
||||||
|
|
||||||
|
__test__ = {"doctest": """
|
||||||
|
Another way to test that 1 + 1 is equal to 2.
|
||||||
|
|
||||||
|
>>> 1 + 1 == 2
|
||||||
|
True
|
||||||
|
"""}
|
||||||
|
|
||||||
31
examples/djangotest/testing/views.py
Executable file
31
examples/djangotest/testing/views.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.shortcuts import render_to_response
|
||||||
|
|
||||||
|
class MsgForm(forms.Form):
|
||||||
|
subject = forms.CharField(max_length=100)
|
||||||
|
message = forms.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
def home(request):
|
||||||
|
|
||||||
|
subject = None
|
||||||
|
message = None
|
||||||
|
if request.POST:
|
||||||
|
form = MsgForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
subject = form.cleaned_data['subject']
|
||||||
|
message = form.cleaned_data['message']
|
||||||
|
else:
|
||||||
|
form = MsgForm()
|
||||||
|
|
||||||
|
|
||||||
|
return render_to_response('home.html', {
|
||||||
|
'form': form,
|
||||||
|
'subject': subject,
|
||||||
|
'message': message
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
examples/djangotest/urls.py
Executable file
6
examples/djangotest/urls.py
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^$', 'djangotest.testing.views.home'),
|
||||||
|
)
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class HttpParser(object):
|
|||||||
return (transfert_encoding == "chunked")
|
return (transfert_encoding == "chunked")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def content_length(self):
|
def content_len(self):
|
||||||
transfert_encoding = self._headers.get('Transfer-Encoding')
|
transfert_encoding = self._headers.get('Transfer-Encoding')
|
||||||
content_length = self._headers.get('Content-Length')
|
content_length = self._headers.get('Content-Length')
|
||||||
if transfert_encoding is None:
|
if transfert_encoding is None:
|
||||||
@ -115,24 +115,33 @@ class HttpParser(object):
|
|||||||
|
|
||||||
def body_eof(self):
|
def body_eof(self):
|
||||||
#TODO : add chunk
|
#TODO : add chunk
|
||||||
if self._len_content == 0:
|
if self._content_len == 0:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def fetch_body(self, buf, data):
|
def read_chunk(self, data):
|
||||||
dlen = len(data)
|
dlen = len(data)
|
||||||
resize(buf, sizeof(data))
|
i = data.find("\n")
|
||||||
s = data.value
|
if i != -1:
|
||||||
|
chunk = data[:i].strip().split(";", 1)
|
||||||
|
chunk_size = int(line.pop(0), 16)
|
||||||
|
if chunk_size <= 0:
|
||||||
|
self._chunk_eof = True
|
||||||
|
return None
|
||||||
|
self.start_offset = i+1
|
||||||
|
|
||||||
|
def filter_body(self, data):
|
||||||
|
dlen = len(data)
|
||||||
|
chunk = None
|
||||||
if self.is_chunked:
|
if self.is_chunked:
|
||||||
# do chunk
|
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if self.content_len > 0:
|
if self._content_len > 0:
|
||||||
nr = min(len(data), self._content_len)
|
nr = min(dlen, self._content_len)
|
||||||
# addessof may be not needed here
|
print nr
|
||||||
memmove(addressof(buf), addressof(data), nr)
|
chunk = data[:nr]
|
||||||
self._content_len -= nr
|
self._content_len -= nr
|
||||||
data.value = None
|
data = None
|
||||||
resize(buf, nr)
|
|
||||||
self.start_offset = 0
|
self.start_offset = 0
|
||||||
return data
|
return chunk, data
|
||||||
@ -42,7 +42,7 @@ from ..util import CHUNK_SIZE, read_partial
|
|||||||
|
|
||||||
NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
|
NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
def _normalize_name(name):
|
def _normalize_name(name):
|
||||||
return "-".join([w.lower().capitalize() for w in name.split("-")])
|
return "-".join([w.lower().capitalize() for w in name.split("-")])
|
||||||
@ -54,9 +54,8 @@ class RequestError(Exception):
|
|||||||
class HTTPRequest(object):
|
class HTTPRequest(object):
|
||||||
|
|
||||||
SERVER_VERSION = "gunicorn/%s" % __version__
|
SERVER_VERSION = "gunicorn/%s" % __version__
|
||||||
|
|
||||||
def __init__(self, socket, client_address, server_address, wid):
|
def __init__(self, socket, client_address, server_address):
|
||||||
self.wid = wid
|
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
self.client_address = client_address
|
self.client_address = client_address
|
||||||
self.server_address = server_address
|
self.server_address = server_address
|
||||||
@ -66,6 +65,8 @@ class HTTPRequest(object):
|
|||||||
self.parser = HttpParser()
|
self.parser = HttpParser()
|
||||||
self.start_response_called = False
|
self.start_response_called = False
|
||||||
|
|
||||||
|
self.log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
headers = {}
|
headers = {}
|
||||||
remain = CHUNK_SIZE
|
remain = CHUNK_SIZE
|
||||||
@ -79,14 +80,15 @@ class HTTPRequest(object):
|
|||||||
buf += data
|
buf += data
|
||||||
i = self.parser.headers(headers, buf)
|
i = self.parser.headers(headers, buf)
|
||||||
if i != -1: break
|
if i != -1: break
|
||||||
|
if not buf:
|
||||||
|
self.socket.close()
|
||||||
if not headers:
|
if not headers:
|
||||||
return
|
return {}
|
||||||
|
|
||||||
buf = buf[i:]
|
buf = buf[i:]
|
||||||
|
|
||||||
|
|
||||||
log.info("worker %s. got headers:\n%s" % (self.wid, headers))
|
self.log.info("Got headers:\n%s" % headers)
|
||||||
|
|
||||||
if headers.get('Except', '').lower() == "100-continue":
|
if headers.get('Except', '').lower() == "100-continue":
|
||||||
self.socket.send("100 Continue\n")
|
self.socket.send("100 Continue\n")
|
||||||
@ -97,10 +99,13 @@ class HTTPRequest(object):
|
|||||||
path_info = self.parser.path
|
path_info = self.parser.path
|
||||||
query = ""
|
query = ""
|
||||||
|
|
||||||
if not self.parser.content_length and not self.parser.is_chunked:
|
if not self.parser.content_len and not self.parser.is_chunked:
|
||||||
wsgi_input = StringIO.StringIO()
|
wsgi_input = StringIO.StringIO()
|
||||||
else:
|
else:
|
||||||
wsgi_input = TeeInput(self.socket, parser, buf, remain)
|
wsgi_input = TeeInput(self.socket, self.parser, buf)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
environ = {
|
environ = {
|
||||||
"wsgi.url_scheme": 'http',
|
"wsgi.url_scheme": 'http',
|
||||||
|
|||||||
@ -25,9 +25,10 @@
|
|||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
import socket
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from ..util import http_date, write
|
from ..util import http_date, write, read_partial
|
||||||
|
|
||||||
class HTTPResponse(object):
|
class HTTPResponse(object):
|
||||||
|
|
||||||
@ -40,26 +41,25 @@ class HTTPResponse(object):
|
|||||||
self.SERVER_VERSION = req.SERVER_VERSION
|
self.SERVER_VERSION = req.SERVER_VERSION
|
||||||
|
|
||||||
def send(self):
|
def send(self):
|
||||||
if self.req.parser.headers:
|
# send headers
|
||||||
# send headers
|
resp_head = []
|
||||||
resp_head = []
|
resp_head.append("HTTP/1.0 %s\r\n" % (self.status))
|
||||||
resp_head.append("HTTP/1.0 %s\r\n" % (self.status))
|
|
||||||
|
resp_head.append("Server: %s\r\n" % self.SERVER_VERSION)
|
||||||
|
resp_head.append("Date: %s\r\n" % http_date())
|
||||||
|
# broken clients
|
||||||
|
resp_head.append("Status: %s\r\n" % str(self.status))
|
||||||
|
# always close the conenction
|
||||||
|
#resp_head.append("Connection: close\r\n")
|
||||||
|
for name, value in self.headers.items():
|
||||||
|
resp_head.append("%s: %s\r\n" % (name, value))
|
||||||
|
|
||||||
resp_head.append("Server: %s\r\n" % self.SERVER_VERSION)
|
write(self.sock, "%s\r\n" % "".join(resp_head))
|
||||||
resp_head.append("Date: %s\r\n" % http_date())
|
|
||||||
# broken clients
|
|
||||||
resp_head.append("Status: %s\r\n" % str(self.status))
|
|
||||||
# always close the conenction
|
|
||||||
resp_head.append("Connection: close\r\n")
|
|
||||||
for name, value in self.headers.items():
|
|
||||||
resp_head.append("%s: %s\r\n" % (name, value))
|
|
||||||
|
|
||||||
write(self.sock, "%s\r\n" % "".join(resp_head))
|
|
||||||
|
|
||||||
for chunk in self.data:
|
for chunk in self.data:
|
||||||
write(self.sock, chunk)
|
write(self.sock, chunk)
|
||||||
|
|
||||||
self.sock.close()
|
self.sock.close()
|
||||||
|
|
||||||
if hasattr(self.data, "close"):
|
if hasattr(self.data, "close"):
|
||||||
self.data.close()
|
self.data.close()
|
||||||
@ -40,30 +40,31 @@ from ..util import MAX_BODY, CHUNK_SIZE
|
|||||||
|
|
||||||
class TeeInput(object):
|
class TeeInput(object):
|
||||||
|
|
||||||
def __init__(self, socket, parser, buf, remain):
|
def __init__(self, socket, parser, buf):
|
||||||
self.buf = buf
|
self.buf = buf
|
||||||
self.remain = remain
|
|
||||||
self.parser = parser
|
self.parser = parser
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
self._len = parser.content_length
|
self._len = parser.content_len
|
||||||
if self._len and self._len < MAX_BODY:
|
if self._len and self._len < MAX_BODY:
|
||||||
self.tmp = StringIO.StringIO()
|
self.tmp = StringIO.StringIO()
|
||||||
else:
|
else:
|
||||||
self.tmp = tempfile.TemporaryFile()
|
self.tmp = tempfile.TemporaryFile()
|
||||||
self.buf2 = create_string_buffer(tmp)
|
|
||||||
if len(buf) > 0:
|
if len(buf) > 0:
|
||||||
parser.filter_body(self.buf2, buf)
|
chunk, self.buf = parser.filter_body(buf)
|
||||||
|
print chunk
|
||||||
|
if chunk:
|
||||||
|
self.tmp.write(chunk)
|
||||||
|
self.tmp.seek(0)
|
||||||
self._finalize()
|
self._finalize()
|
||||||
self.tmp.write(self.buf2)
|
|
||||||
self.tmp.seek(0)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def len(self):
|
def len(self):
|
||||||
if self._len: return self._len
|
if self._len: return self._len
|
||||||
if self.remain:
|
if self.socket:
|
||||||
pos = self.tmp.tell()
|
pos = self.tmp.tell()
|
||||||
while True:
|
while True:
|
||||||
if not self._tee(self.remain, self.buf2):
|
if not self._tee(CHUNK_SIZE):
|
||||||
break
|
break
|
||||||
self.tmp.seek(pos)
|
self.tmp.seek(pos)
|
||||||
self._len = self._tmp_size()
|
self._len = self._tmp_size()
|
||||||
@ -72,56 +73,86 @@ class TeeInput(object):
|
|||||||
|
|
||||||
def read(self, length=None):
|
def read(self, length=None):
|
||||||
""" read """
|
""" read """
|
||||||
if not self.remain:
|
print "la"
|
||||||
|
if not self.socket:
|
||||||
return self.tmp.read(length)
|
return self.tmp.read(length)
|
||||||
|
|
||||||
if not length:
|
if length is None:
|
||||||
|
print "ici"
|
||||||
r = self.tmp.read() or ""
|
r = self.tmp.read() or ""
|
||||||
while self._tee(self.remain, self.buf2):
|
while True:
|
||||||
r += self.buf2.value
|
chunk = self._tee(CHUNK_SIZE)
|
||||||
|
if not chunk: break
|
||||||
|
r += chunk
|
||||||
return r
|
return r
|
||||||
else:
|
else:
|
||||||
r = self.buf2
|
|
||||||
diff = self._tmp_size() - self.tmp.tell()
|
diff = self._tmp_size() - self.tmp.tell()
|
||||||
if not diff:
|
if not diff:
|
||||||
return self._ensure_length(self._tee(self.remain, r), self.remain)
|
return self._ensure_length(self._tee(length), length)
|
||||||
else:
|
else:
|
||||||
length = min(diff, self.remain)
|
l = min(diff, length)
|
||||||
return self._ensure_length(self._tee(length, r), length)
|
return self._ensure_length(self.tmp.read(l), length)
|
||||||
|
|
||||||
def readline(self, amt=-1):
|
def readline(self, size=-1):
|
||||||
pass
|
if not self.socket:
|
||||||
|
return self.tmp.readline(size)
|
||||||
|
|
||||||
|
orig_size = self._tmp_size()
|
||||||
|
if self.tmp.tell() == orig_size:
|
||||||
|
if not self._tee(CHUNK_SIZE):
|
||||||
|
return ''
|
||||||
|
self.tmp.seek(orig_size)
|
||||||
|
|
||||||
|
# now we can get line
|
||||||
|
line = self.tmp.readline()
|
||||||
|
if size > 0 and len(line) < size:
|
||||||
|
self.tmp.seek(orig_size)
|
||||||
|
while True:
|
||||||
|
if not self._tee(CHUNK_SIZE):
|
||||||
|
self.tmp.seek(orig_size)
|
||||||
|
return self.temp.readline(size)
|
||||||
|
return line
|
||||||
|
|
||||||
def readlines(self, sizehints=0):
|
def readlines(self, sizehints=0):
|
||||||
pass
|
lines = []
|
||||||
|
line = self.readline()
|
||||||
|
while line:
|
||||||
|
lines.append(line)
|
||||||
|
total += len(line)
|
||||||
|
if 0 < sizehint <= total:
|
||||||
|
break
|
||||||
|
line = self.readline()
|
||||||
|
return lines
|
||||||
|
|
||||||
def __next__(self):
|
|
||||||
|
def next(self):
|
||||||
r = self.readline()
|
r = self.readline()
|
||||||
if not r:
|
if not r:
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
return r
|
return r
|
||||||
next = __next__
|
__next__ = next
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _tee(self, length, dst):
|
def _tee(self, length):
|
||||||
""" fetch partial body"""
|
""" fetch partial body"""
|
||||||
while not self.parser.body_eof() and self.remain:
|
while not self.parser.body_eof():
|
||||||
data = create_string_buffer(length)
|
data = read_partial(self.socket, length)
|
||||||
length -= self.socket.recv_into(data, length)
|
self.buf += data
|
||||||
self.remain = length
|
chunk, self.buf = self.parser.filter_body(self.buf)
|
||||||
if self.parser.filter_body(dst, data):
|
if chunk:
|
||||||
self.tmp.write(dst.value)
|
self.tmp.write(chunk)
|
||||||
self.tmp.seek(0, os.SEEK_END)
|
self.tmp.seek(0, os.SEEK_END)
|
||||||
return dst
|
return chunk
|
||||||
self._finalize()
|
self._finalize()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def _finalize(self):
|
def _finalize(self):
|
||||||
""" here we wil fetch final trailers
|
""" here we wil fetch final trailers
|
||||||
if any."""
|
if any."""
|
||||||
|
if self.parser.body_eof():
|
||||||
|
self.socket = None
|
||||||
|
|
||||||
def _tmp_size(self):
|
def _tmp_size(self):
|
||||||
if isinstance(self.tmp, StringIO.StringIO):
|
if isinstance(self.tmp, StringIO.StringIO):
|
||||||
@ -133,6 +164,5 @@ class TeeInput(object):
|
|||||||
if not buf or not self._len:
|
if not buf or not self._len:
|
||||||
return buf
|
return buf
|
||||||
while len(buf) < length and self.len != self.tmp.pos():
|
while len(buf) < length and self.len != self.tmp.pos():
|
||||||
buf += self._tee(length - len(buf), self.buf2)
|
buf += self._tee(length - len(buf))
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
@ -55,14 +55,13 @@ def read_partial(sock, length):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def write(sock, data):
|
def write(sock, data):
|
||||||
for i in xrange(2):
|
for i in range(2):
|
||||||
print i
|
|
||||||
try:
|
try:
|
||||||
return sock.send(data)
|
return sock.send(data)
|
||||||
except socket.error:
|
except socket.error, e:
|
||||||
if i == 2:
|
if i == 0:
|
||||||
print "raise"
|
continue
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def write_nonblock(sock, data):
|
def write_nonblock(sock, data):
|
||||||
while True:
|
while True:
|
||||||
@ -71,9 +70,10 @@ def write_nonblock(sock, data):
|
|||||||
if ret[1]: break
|
if ret[1]: break
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
if e[0] == errno.EINTR:
|
if e[0] == errno.EINTR:
|
||||||
|
time.sleep(1)
|
||||||
break
|
break
|
||||||
raise
|
raise
|
||||||
sock.send(data)
|
write(sock, data)
|
||||||
|
|
||||||
def import_app(module):
|
def import_app(module):
|
||||||
parts = module.rsplit(":", 1)
|
parts = module.rsplit(":", 1)
|
||||||
|
|||||||
@ -38,8 +38,6 @@ import time
|
|||||||
from . import http
|
from . import http
|
||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class Worker(object):
|
class Worker(object):
|
||||||
|
|
||||||
SIGNALS = map(
|
SIGNALS = map(
|
||||||
@ -63,6 +61,8 @@ class Worker(object):
|
|||||||
|
|
||||||
self.app = app
|
self.app = app
|
||||||
self.alive = True
|
self.alive = True
|
||||||
|
|
||||||
|
self.log = logging.getLogger(__name__)
|
||||||
|
|
||||||
def close_on_exec(self, fd):
|
def close_on_exec(self, fd):
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC
|
flags = fcntl.fcntl(fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC
|
||||||
@ -115,7 +115,10 @@ class Worker(object):
|
|||||||
# loop and wait for some lovin.
|
# loop and wait for some lovin.
|
||||||
while self.alive:
|
while self.alive:
|
||||||
try:
|
try:
|
||||||
client, addr = self.socket.accept()
|
res = self.socket.accept()
|
||||||
|
if res is None:
|
||||||
|
break
|
||||||
|
client, addr = res
|
||||||
client.setblocking(0)
|
client.setblocking(0)
|
||||||
|
|
||||||
# handle connection
|
# handle connection
|
||||||
@ -130,18 +133,15 @@ class Worker(object):
|
|||||||
errno.EWOULDBLOCK]:
|
errno.EWOULDBLOCK]:
|
||||||
break # Uh oh!
|
break # Uh oh!
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def handle(self, client, addr):
|
def handle(self, client, addr):
|
||||||
self.close_on_exec(client)
|
self.close_on_exec(client)
|
||||||
try:
|
try:
|
||||||
req = http.HTTPRequest(client, addr, self.address, self.id)
|
req = http.HTTPRequest(client, addr, self.address)
|
||||||
response = self.app(req.read(), req.start_response)
|
response = self.app(req.read(), req.start_response)
|
||||||
http.HTTPResponse(client, response, req).send()
|
http.HTTPResponse(client, response, req).send()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.exception("Error processing request. [%s]" % str(e))
|
self.log.exception("Error processing request. [%s]" % str(e))
|
||||||
msg = "HTTP/1.0 500 Internal Server Error\r\n\r\n"
|
msg = "HTTP/1.0 500 Internal Server Error\r\n\r\n"
|
||||||
util.write_nonblock(client, msg)
|
util.write_nonblock(client, msg)
|
||||||
client.close()
|
client.close()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user