[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - HTTPServer2.py:1.1.2.2 dual_mode_channel.py:1.1.2.2
Shane Hathaway
shane@digicool.com
Mon, 26 Nov 2001 09:57:24 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Server
In directory cvs.zope.org:/tmp/cvs-serv4654
Modified Files:
Tag: Zope-3x-branch
HTTPServer2.py dual_mode_channel.py
Log Message:
- Better in sync with HTTP spec.
- Pipelineable without making unnecessary buffers
- Added ZPL
- Moved task management out of dual_mode_channel
=== Zope3/lib/python/Zope/Server/HTTPServer2.py 1.1.2.1 => 1.1.2.2 === (436/536 lines abridged)
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
# This server uses asyncore to accept connections and do initial
# processing but threads to do work.
@@ -17,14 +25,15 @@
from dual_mode_channel import simultaneous_mode_channel as channel_type
else:
from dual_mode_channel import dual_mode_channel as channel_type
-
-from dual_mode_channel import synchronous_instream
+from dual_mode_channel import OverflowableBuffer
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
+from thread import allocate_lock
+
if 1:
# Patch asyncore for speed.
@@ -32,6 +41,9 @@
del asyncore.dispatcher.__getattr__
+default_body = "The HTTP server is running!\r\n" * 10
+
+
class http_task:
# __implements__ = ITask
@@ -42,14 +54,18 @@
wrote_header = 0
accumulated_headers = None
- def __init__(self, channel, request_header_plus, body_start):
+ def __init__(self, channel, request_data):
self.channel = channel
- self.request_header_plus = request_header_plus
- self.body_start = body_start
+ self.request_data = request_data
self.response_headers = {
'Server' : 'Zope.Server.HTTPServer',
[-=- -=- -=- 436 lines omitted -=- -=- -=-]
+ return
+ conn, addr = v
except socket.error:
# linux: on rare occasions we get a bogus socket back from
# accept. socketmodule.c:makesockaddr complains that the
@@ -303,33 +493,8 @@
task.service()
-first_line_re = re.compile (
- '([^ ]+) (?:[^ :?#]+://[^ ?#/]*)?([^ ]+)(( HTTP/([0-9.]+))$|$)')
-
-def crack_first_line (r):
- m = first_line_re.match (r)
- if m is not None and m.end() == len(r):
- if m.group(3):
- version = m.group(5)
- else:
- version = None
- return m.group(1).upper(), m.group(2), version
- else:
- return None, None, None
-def get_header_lines(header):
- """
- Splits the header into lines, putting multi-line headers together.
- """
- r = []
- lines = header.split('\r\n')
- for line in lines:
- if line and line[0] in ' \t':
- r[-1] = r[-1] + line[1:]
- else:
- r.append(line)
- return r
if __name__ == '__main__':
@@ -338,7 +503,9 @@
tasks.setThreadCount(4)
http_server('', 8080, tasks=tasks)
try:
- asyncore.loop()
+ while 1:
+ asyncore.poll(5)
+ #print http_channel.active_channels
except KeyboardInterrupt:
print 'shutting down...'
tasks.shutdown()
=== Zope3/lib/python/Zope/Server/dual_mode_channel.py 1.1.2.1 => 1.1.2.2 === (710/810 lines abridged)
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
import asyncore
import socket
import sys
-import time
+from time import time
try:
from cStringIO import StringIO
@@ -15,6 +22,9 @@
pull_trigger = trigger().pull_trigger
+# copy_bytes controls the size of temp. strings for shuffling data around.
+COPY_BYTES = 1 << 18 # 64K
+
class dual_mode_channel (asyncore.dispatcher):
@@ -24,40 +34,28 @@
# recv_bytes is the argument to pass to socket.recv().
recv_bytes = 8192
+ # send_bytes is the number of bytes to send to socket.send().
+ send_bytes = 8192
- # outbuf_maxsize specifies maximum outbuf is allowed to hold
- # before the application starts blocking on output.
- # Raising outbuf_maxsize will improve throughput if you have
- # files larger than outbuf_maxsize being transferred over
- # more concurrent, slow connections than your worker thread count.
- # Expect maximum RAM consumption by outbufs to be
- # at most (number_of_concurrent_connections * outbuf_maxsize),
- # but if you're using ZODB and everyone is downloading the
- # same file then the normal RAM consumption is only a little more
- # than (number of ZODB threads * outbuf_maxsize) because of
- # ConservingStringBuffer. Also, if ZODB is changed to
- # share strings among threads, normal RAM consumption by outbufs
- # will decrease significantly.
- outbuf_maxsize = 4200000 # About 4 MB
-
- # Create a tempfile if the input data gets larger than inbuf_overflow.
[-=- -=- -=- 710 lines omitted -=- -=- -=-]
+ self.strbuf = ''
+ return
+ buf = self._create_buffer()
+ buf.skip(bytes, allow_prune)
- def del_bytes(self, bytes):
+ def prune(self):
"""
- Deletes the given number of bytes from the start of the buffer.
+ A potentially expensive operation that removes all data
+ already retrieved from the buffer.
"""
- gotbytes = 0
- data = self.data
- for index in range(len(data)):
- s = data[index]
- slen = len(s)
- gotbytes = gotbytes + slen
- if gotbytes > bytes:
- position = slen - (gotbytes - bytes)
- del data[:index]
- data[0] = s[position:]
- self.len = self.len - bytes
- return
- elif gotbytes == bytes:
- del data[:index + 1]
- self.len = self.len - bytes
- return
- # Hmm, too many!
- raise ValueError, (
- "Can't delete %d bytes from buffer of %d bytes" %
- (bytes, gotbytes))
+ buf = self.buf
+ if buf is None:
+ self.strbuf = ''
+ return
+ buf.prune()
+ if self.overflowed:
+ sz = len(buf)
+ if sz < self.overflow:
+ # Revert to a faster buffer.
+ self._set_small_buffer()
+
+ def getfile(self):
+ buf = self.buf
+ if buf is None:
+ buf = self._create_buffer()
+ return buf.getfile()