[Zope-Checkins] CVS: Zope/ZServer - ICPServer.py:1.1.8.1 FTPServer.py:1.21.36.1 HTTPResponse.py:1.37.12.1
Casey Duncan
casey@zope.com
Wed, 27 Mar 2002 15:52:01 -0500
Update of /cvs-repository/Zope/ZServer
In directory cvs.zope.org:/tmp/cvs-serv22094/ZServer
Modified Files:
Tag: casey-death_to_index_html-branch
FTPServer.py HTTPResponse.py
Added Files:
Tag: casey-death_to_index_html-branch
ICPServer.py
Log Message:
Updating branch to head for testing
=== Added File Zope/ZServer/ICPServer.py ===
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
#
##############################################################################
# Medusa ICP server
#
# Why would you want to use this?
# see http://www.zope.org/Members/htrd/icp/intro
import sys, string, os, socket, errno, struct
import asyncore
from medusa import counter
ICP_OP_QUERY = 1
ICP_OP_HIT = 2
ICP_OP_MISS = 3
ICP_OP_ERR = 4
ICP_OP_MISS_NOFETCH = 21
ICP_OP_DENIED = 22
class BaseICPServer(asyncore.dispatcher):
REQUESTS_PER_LOOP = 4
def __init__ (self,ip,port):
asyncore.dispatcher.__init__(self)
self.create_socket (socket.AF_INET, socket.SOCK_DGRAM)
self.set_reuse_addr()
self.bind((ip,port))
if ip=='':
addr = 'any'
else:
addr = ip
self.log_info('ICP server started\n\tAddress: %s\n\tPort: %s' % (addr,port) )
def handle_read(self):
for i in range(self.REQUESTS_PER_LOOP):
try:
request, whence = self.socket.recvfrom(16384)
except socket.error,e:
if e[0]==errno.EWOULDBLOCK:
break
else:
raise
else:
if self.check_whence(whence):
reply = self.calc_reply(request)
if reply:
self.socket.sendto(reply,whence)
def readable(self):
return 1
def writable(self):
return 0
def handle_write (self):
self.log_info ('unexpected write event', 'warning')
def handle_error (self): # don't close the socket on error
(file,fun,line), t, v, tbinfo = asyncore.compact_traceback()
self.log_info('Problem in ICP (%s:%s %s)' % (t, v, tbinfo),
'error')
def check_whence(self,whence):
return 1
def calc_reply(self,request):
if len(request)>20:
opcode,version,length,number,options,opdata,junk = struct.unpack('!BBHIIII',request[:20])
if version==2:
if opcode==ICP_OP_QUERY:
if len(request)!=length:
out_opcode = ICP_OP_ERR
else:
url = request[24:]
if url[-1:]=='\x00':
url = url[:-1]
out_opcode = self.check_url(url)
return struct.pack('!BBHIIII',out_opcode,2,20,number,0,0,0)
def check_url(self,url):
# derived classes replace this with a more
# useful policy
return ICP_OP_MISS
class ICPServer(BaseICPServer):
# Products that want to do special ICP handling should .append their hooks into
# this list. Each hook is called in turn with the URL as a parameter, and
# they must return an ICP_OP code from above or None. The first
# non-None return is used as the ICP response
hooks = []
def check_url(self,url):
for hook in self.hooks:
r = hook(url)
if r is not None:
return r
return ICP_OP_MISS
=== Zope/ZServer/FTPServer.py 1.21 => 1.21.36.1 ===
def handle_accept (self):
- conn, addr = self.accept()
+ try:
+ conn, addr = self.accept()
+ except TypeError:
+ # unpack non-sequence as result of accept
+ # returning None (in case of EWOULDBLOCK)
+ return
self.total_sessions.increment()
self.log_info('Incoming connection from %s:%d' % (addr[0], addr[1]))
self.ftp_channel_class (self, conn, addr, self.module)
=== Zope/ZServer/HTTPResponse.py 1.37 => 1.37.12.1 ===
response=self.__class__(stdout=self.stdout, stderr=self.stderr)
+ response.headers=self.headers
response._http_version=self._http_version
response._http_connection=self._http_connection
response._server_version=self._server_version
@@ -296,6 +297,9 @@
self._close=1
self._request.reply_code=response.status
+
+is_proxying_match = re.compile(r'[^ ]* [^ \\]*:').match
+proxying_connection_re = re.compile ('Proxy-Connection: (.*)', re.IGNORECASE)
def make_response(request, headers):
"Simple http response factory"
@@ -303,9 +307,16 @@
response=ZServerHTTPResponse(stdout=ChannelPipe(request), stderr=StringIO())
response._http_version=request.version
- response._http_connection=(
- http_server.get_header(http_server.CONNECTION, request.header)).lower()
+ if request.version=='1.0' and is_proxying_match(request.request):
+ # a request that was made as if this zope was an http 1.0 proxy.
+ # that means we have to use some slightly different http
+ # headers to manage persistent connections.
+ connection_re = proxying_connection_re
+ else:
+ # a normal http request
+ connection_re = http_server.CONNECTION
+ response._http_connection = http_server.get_header(connection_re,
+ request.header).lower()
response._server_version=request.channel.server.SERVER_IDENT
return response
-