[Zope3-dev] Re: [Zope3-Users] Re: Is this a bug of HTTP response's head handling? (publisherhttpserver.py)
Thanks Philipp, here is the unified diffs. --- httptask.py.orig Fri Jan 06 02:15:48 2006+++ httptask.py Thu Sep 21 17:31:17 2006@@ -126,6 +126,15 @@ else: close_it = 1 elif version == '1.1':+ #modified by Simon + thisflag = False+ for each in self.accumulated_headers:+ if each.lower() == 'connection: keep-alive':+ thisflag = True+ break + if thisflag == False:+ close_it = 1+ if connection == 'close': close_it = 1 elif 'Transfer-Encoding' in response_headers:@@ -134,8 +143,15 @@ elif self.status == '304': # Replying with headers only. pass+ #modified by simon elif not ('Content-Length' in response_headers): - close_it = 1+ thisflag = False+ for each in self.accumulated_headers:+ if each[:14].lower() == 'content-length':+ thisflag = True + break+ if thisflag == False: #only content_length not exist in accumulated headers too+ close_it = 1 else: # Close if unrecognized HTTP version. close_it = 1 On 9/21/06, Philipp von Weitershausen [EMAIL PROTECTED] wrote: Simon Hang wrote: How about below changes?There aren't many of us who know the zope.server code that well,unfortunately. This is one of the reasons we want to get out of theserver business.That said, it would *much* easier to understand what you're trying to doif you provided *unified diffs* (create them with svn diff or diff -u). Philipp in httptask.py def prepareResponseHeaders(self): version = self.version # Figure out whether the connection should be closed. connection = self.request_data.headers.get('CONNECTION', '').lower() close_it = 0 response_headers = self.response_headers if version == '1.0': if connection == 'keep-alive': if not ('Content-Length' in response_headers): close_it = 1 else: response_headers['Connection'] = 'Keep-Alive' else: close_it = 1 elif version == '1.1': #insert by Simon thisflag = False for each in self.accumulated_headers: if each.lower() == 'connection: keep-alive': thisflag = True break if thisflag == False: close_it = 1 #end of insert if connection == 'close': close_it = 1 elif 'Transfer-Encoding' in response_headers: if not response_headers['Transfer-Encoding'] == 'chunked': close_it = 1 elif self.status == '304': # Replying with headers only. pass #insert by simon elif not ('Content-Length' in response_headers): thisflag = False for each in self.accumulated_headers: if each[:14].upper() == 'CONTENT-LENGTH': thisflag = True break if thisflag == False: #only CONTENT_LENGTH not exist in accumulated headers too #end of insert close_it = 1 else: # Close if unrecognized HTTP version. close_it = 1 self.close_on_finish = close_it if close_it: self.response_headers ['Connection'] = 'close' On 9/19/06, *Simon Hang* [EMAIL PROTECTED] mailto: [EMAIL PROTECTED] wrote: Dear all, While I was exploring my options to implement NTLM authentication, I found some strange behavior of Zope HTTP server. in zope.server.http.wsgihttpserver.WSGIHTTPServer, It use below function to handle response's head: def start_response(status, headers): # Prepare the headers for output status, reason = re.match('([0-9]*) (.*)', status).groups() task.setResponseStatus(status, reason) task.appendResponseHeaders(['%s: %s' % i for i in headers]) # Return the write method used to write the response data. return fakeWrite The result is all response's head from the content part of program will be stored in task.accumulated_headers. See below function from zope.server.http.httptask.HTTPTask. def appendResponseHeaders(self, lst): See zope.publisher.interfaces.http.IHeaderOutput accum = self.accumulated_headers if accum is None: self.accumulated_headers = accum = [] accum.extend(lst) But, the problem is while httptask to determin whether to close the connection or not, it use below code. The code is only checking self.response_headers which has nothing to do with the response our application generated. So zope ends up to disconnect connection for each single request.def prepareResponseHeaders(self): version = self.version # Figure out whether the connection should be closed. connection = self.request_data.headers.get('CONNECTION', '').lower() close_it = 0 response_headers = self.response_headers if version == ' 1.0': if connection == 'keep-alive': if not ('Content-Length' in response_headers): close_it = 1 else: response_headers['Connection'] = 'Keep-Alive' else: close_it = 1 elif version == '1.1': thisflag = False if connection == 'close': close_it = 1 elif 'Transfer-Encoding' in response_headers: if not response_headers['Transfer-Encoding'] == 'chunked': close_it = 1 elif self.status == '304': # Replying with headers only. pass elif not ('Content-Length' in response_headers): close_it = 1 else: # Close if unrecognized HTTP version. close_it = 1 self.close_on_finish = close_it if close_it: self.response_headers['Connection'] = 'close' Can somebody tell me why the thing is implement like this, is there special reason to do this? Or can we change it a little bit to let zope support persistence connection? Thanks, Simon
[Zope3-dev] Re: [Zope3-Users] Re: Is this a bug of HTTP response's head handling? (publisherhttpserver.py)
Philipp, Sorry for being lazy, and thanks for the tips. Here is my update version. --- httptask.py.orig Fri Jan 06 02:15:48 2006+++ httptask.py Fri Sep 22 09:13:48 2006@@ -126,6 +126,11 @@ else: close_it = 1 elif version == '1.1':+ #modified by Simon + if 'connection: close' in (header.lower() for header in+ self.accumulated_headers):+ #Close if 'connection: close' found in http response's header + close_it = 1 if connection == 'close': close_it = 1 elif 'Transfer-Encoding' in response_headers:@@ -134,8 +139,13 @@ elif self.status == '304': # Replying with headers only. pass+ #modified by simon elif not ('Content-Length' in response_headers):- close_it = 1 + if 'content-length' not in (header[:14].lower() for header in+ self.accumulated_headers):+ #Close if 'content-length' not found in + #http response's header and self.response_headers+ close_it = 1 else: # Close if unrecognized HTTP version. close_it = 1 On 9/21/06, Philipp von Weitershausen [EMAIL PROTECTED] wrote: Hi Simon,I have a few comments regarding style. First::if thisflag == False:... is unnecessarily long. Just write::if not thisflag:...Also, what is thisflag? It'd be better to give it a descriptive name. --- httptask.py.origFri Jan 06 02:15:48 2006 +++ httptask.py Thu Sep 21 17:31:17 2006 @@ -126,6 +126,15 @@else:close_it = 1elif version == '1.1': +#modified by Simon +thisflag = False +for each in self.accumulated_headers: +if each.lower() == 'connection: keep-alive': +thisflag = True +break +if thisflag == False: +close_it = 1 +I think you make this a lot simpler::if 'connection: keep-alive' not in (header.lower() for header in self.accumulated_headers):close_it = 1(instead of the lines you added)if connection == 'close':close_it = 1elif 'Transfer-Encoding' in response_headers: @@ -134,8 +143,15 @@elif self.status == '304':# Replying with headers only.pass +#modified by simonelif not ('Content-Length' in response_headers): -close_it = 1 +thisflag = False +for each in self.accumulated_headers: +if each[:14].lower() == 'content-length': +thisflag = True +break +if thisflag == False: #only content_length not exist in accumulated headers too +close_it = 1I don't understand the comment (English grammar not correct), but my suggestion would apply here as well, I think. ___ Zope3-dev mailing list Zope3-dev@zope.org Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com
[Zope3-dev] Is this a bug of HTTP response's head handling? (publisherhttpserver.py)
Dear all, While I was exploringmy options to implement NTLM authentication, I found some strange behavior of Zope HTTP server. in zope.server.http.wsgihttpserver.WSGIHTTPServer, It use below function to handle response's head: def start_response(status, headers): # Prepare the headers for output status, reason = re.match('([0-9]*) (.*)', status).groups() task.setResponseStatus(status, reason) task.appendResponseHeaders(['%s: %s' % i for i in headers]) # Return the write method used to write the response data. return fakeWrite The result is all response's head from the content part of program will be stored in task.accumulated_headers. See below function from zope.server.http.httptask.HTTPTask. def appendResponseHeaders(self, lst): See zope.publisher.interfaces.http.IHeaderOutput accum = self.accumulated_headers if accum is None: self.accumulated_headers = accum = [] accum.extend(lst) But, the problem is while httptask to determin whether to close the connection or not, it use below code. The code is only checking self.response_headers which has nothing to do with the response our application generated. So zope ends up to disconnect connection for each single request. def prepareResponseHeaders(self): version = self.version # Figure out whether the connection should be closed. connection = self.request_data.headers.get('CONNECTION', '').lower() close_it = 0 response_headers = self.response_headers if version == '1.0': if connection == 'keep-alive': if not ('Content-Length' in response_headers): close_it = 1 else: response_headers['Connection'] = 'Keep-Alive' else: close_it = 1 elif version == '1.1': thisflag = False if connection == 'close': close_it = 1 elif 'Transfer-Encoding' in response_headers: if not response_headers['Transfer-Encoding'] == 'chunked': close_it = 1 elif self.status == '304': # Replying with headers only. pass elif not ('Content-Length' in response_headers): close_it = 1 else: # Close if unrecognized HTTP version. close_it = 1 self.close_on_finish = close_it if close_it: self.response_headers['Connection'] = 'close' Can somebody tell me why the thing is implement like this, is there special reason to do this? Or can we change it a little bit to let zope support persistence connection? Thanks,Simon ___ Zope3-dev mailing list Zope3-dev@zope.org Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com
Re: [Zope3-dev] (zope/app/cache/ram.py) class Storage's cleanup problem.
Hi Stephan, Is these code all right? Regards, SimonOn 11/13/05, Simon Hang [EMAIL PROTECTED] wrote: Thanks Stephan, Here is the test:(test_ramcache.py) class TestStorage(TestCase): def test_getEntry(self): --snipped-- def test_getEntry_do_cleanup(self): from zope.app.cache.ram import Storage s = Storage(cleanupInterval=300, maxAge=300) object = 'object' key = ('view', (), ('answer', 42)) value = 'yes' s.setEntry(object, key, value) s._data[object][key][1] = time() - 400 s.lastCleanup = time() - 400 try: s.getEntry(object, key) except KeyError: pass else: raise cleanup not called def test_setEntry(self): --snipped-- On 11/12/05, Stephan Richter [EMAIL PROTECTED] wrote: On Tuesday 01 November 2005 05:10, Simon Hang wrote: Dear all, I'm happen to find out call Storage only do cleanup when new Entry comes and do nothing when entries get from storage. So entries will be next expired if there are only read activities.I agree with your analysis and solution. If you provide a test for the fix,I'll check it in. If you cannot write a test, please add least add an issueto the issue collector. Regards,Stephan--Stephan RichterCBU Physics Chemistry (B.S.) / Tufts Physics (Ph.D. student)Web2k - Web Software Design, Development and Training ___ Zope3-dev mailing list Zope3-dev@zope.org Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com
Re: [Zope3-dev] (zope/app/cache/ram.py) class Storage's cleanup problem.
Thanks Stephan, Here is the test:(test_ramcache.py) class TestStorage(TestCase): def test_getEntry(self): --snipped-- def test_getEntry_do_cleanup(self): from zope.app.cache.ram import Storage s = Storage(cleanupInterval=300, maxAge=300) object = 'object' key = ('view', (), ('answer', 42)) value = 'yes' s.setEntry(object, key, value) s._data[object][key][1] = time() - 400 s.lastCleanup = time() - 400 try: s.getEntry(object, key) except KeyError: pass else: raise cleanup not called def test_setEntry(self): --snipped-- On 11/12/05, Stephan Richter [EMAIL PROTECTED] wrote: On Tuesday 01 November 2005 05:10, Simon Hang wrote: Dear all, I'm happen to find out call Storage only do cleanup when new Entry comes and do nothing when entries get from storage. So entries will be next expired if there are only read activities.I agree with your analysis and solution. If you provide a test for the fix,I'll check it in. If you cannot write a test, please add least add an issueto the issue collector. Regards,Stephan--Stephan RichterCBU Physics Chemistry (B.S.) / Tufts Physics (Ph.D. student)Web2k - Web Software Design, Development and Training ___ Zope3-dev mailing list Zope3-dev@zope.org Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com
[Zope3-dev] (zope/app/cache/ram.py) class Storage's cleanup problem.
Dear all, I'm happen to find out call Storage only do cleanup when new Entry comes and do nothing when entries get from storage. So entries will be next expired if there are only read activities. So I suggest we may change the getEntry as below: def getEntry(self, ob, key): # start of insert if self.lastCleanup = time() - self.cleanupInterval: self.cleanup() # end of insert try: data = ""> except KeyError: if ob not in self._misses: self._misses[ob] = 0 self._misses[ob] += 1 raise else: data[2] += 1 # increment access count return data[0] Can somebody update this into the repository? Thanks, Simon ___ Zope3-dev mailing list Zope3-dev@zope.org Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com