Commit c4fcba3a authored by Amos Latteier's avatar Amos Latteier

Added a lock to tempfile producers. Thanks to Toby Dickenson. This should...

Added a lock to tempfile producers. Thanks to Toby Dickenson. This should avoid possible corruption of responses from FCGI and large HTTP responses.
parent 1dd29bd5
...@@ -117,6 +117,7 @@ from cStringIO import StringIO ...@@ -117,6 +117,7 @@ from cStringIO import StringIO
from tempfile import TemporaryFile from tempfile import TemporaryFile
import socket, string, os, sys, time import socket, string, os, sys, time
from types import StringType from types import StringType
import thread
tz_for_log = compute_timezone_for_log() tz_for_log = compute_timezone_for_log()
...@@ -716,6 +717,7 @@ class FCGIServer(asyncore.dispatcher): ...@@ -716,6 +717,7 @@ class FCGIServer(asyncore.dispatcher):
class FCGIResponse(HTTPResponse): class FCGIResponse(HTTPResponse):
_tempfile=None _tempfile=None
_templock=None
_tempstart=0 _tempstart=0
def setChannel(self, channel): def setChannel(self, channel):
...@@ -731,6 +733,7 @@ class FCGIResponse(HTTPResponse): ...@@ -731,6 +733,7 @@ class FCGIResponse(HTTPResponse):
if type(l) is type(''): l=string.atoi(l) if type(l) is type(''): l=string.atoi(l)
if l > 128000: if l > 128000:
self._tempfile=TemporaryFile() self._tempfile=TemporaryFile()
self._templock=thread.allocate_lock()
except: pass except: pass
stdout.write(str(self)) stdout.write(str(self))
...@@ -750,10 +753,14 @@ class FCGIResponse(HTTPResponse): ...@@ -750,10 +753,14 @@ class FCGIResponse(HTTPResponse):
l=len(chunk) l=len(chunk)
b=self._tempstart b=self._tempstart
e=b+l e=b+l
t.seek(b) self._templock.acquire()
t.write(chunk) try:
t.seek(b)
t.write(chunk)
finally:
self._templock.release()
self._tempstart=e self._tempstart=e
stdout.write((file_part_producer(t,b,e), l)) stdout.write((file_part_producer(t,self._templock,b,e), l))
def _finish(self): def _finish(self):
self.channel.reply_code=self.status self.channel.reply_code=self.status
......
...@@ -91,7 +91,7 @@ and logging duties. ...@@ -91,7 +91,7 @@ and logging duties.
""" """
import time, regex, string, sys, tempfile import time, regex, string, sys, tempfile
from cStringIO import StringIO from cStringIO import StringIO
import thread
from ZPublisher.HTTPResponse import HTTPResponse, end_of_header_search from ZPublisher.HTTPResponse import HTTPResponse, end_of_header_search
from medusa.http_date import build_http_date from medusa.http_date import build_http_date
from PubCore.ZEvent import Wakeup from PubCore.ZEvent import Wakeup
...@@ -215,7 +215,9 @@ class ZServerHTTPResponse(HTTPResponse): ...@@ -215,7 +215,9 @@ class ZServerHTTPResponse(HTTPResponse):
return string.join(headersl,'\r\n') return string.join(headersl,'\r\n')
_tempfile=None _tempfile=None
_templock=None
_tempstart=0 _tempstart=0
def write(self,data): def write(self,data):
"""\ """\
Return data as a stream Return data as a stream
...@@ -240,6 +242,7 @@ class ZServerHTTPResponse(HTTPResponse): ...@@ -240,6 +242,7 @@ class ZServerHTTPResponse(HTTPResponse):
if type(l) is type(''): l=string.atoi(l) if type(l) is type(''): l=string.atoi(l)
if l > 128000: if l > 128000:
self._tempfile=tempfile.TemporaryFile() self._tempfile=tempfile.TemporaryFile()
self._templock=thread.allocate_lock()
except: pass except: pass
stdout.write(str(self)) stdout.write(str(self))
...@@ -254,10 +257,14 @@ class ZServerHTTPResponse(HTTPResponse): ...@@ -254,10 +257,14 @@ class ZServerHTTPResponse(HTTPResponse):
l=len(data) l=len(data)
b=self._tempstart b=self._tempstart
e=b+l e=b+l
t.seek(b) self._templock.acquire()
t.write(data) try:
t.seek(b)
t.write(data)
finally:
self._templock.release()
self._tempstart=e self._tempstart=e
stdout.write(file_part_producer(t,b,e), l) stdout.write(file_part_producer(t,self._templock,b,e), l)
def _finish(self): def _finish(self):
stdout=self.stdout stdout=self.stdout
......
...@@ -128,8 +128,9 @@ class file_part_producer: ...@@ -128,8 +128,9 @@ class file_part_producer:
# match http_channel's outgoing buffer size # match http_channel's outgoing buffer size
out_buffer_size = 1<<16 out_buffer_size = 1<<16
def __init__(self, file, start, end): def __init__(self, file, lock, start, end):
self.file=file self.file=file
self.lock=lock
self.start=start self.start=start
self.end=end self.end=end
...@@ -140,12 +141,17 @@ class file_part_producer: ...@@ -140,12 +141,17 @@ class file_part_producer:
if start >= end: return '' if start >= end: return ''
file=self.file file=self.file
file.seek(start)
size=end-start size=end-start
bsize=self.out_buffer_size bsize=self.out_buffer_size
if size > bsize: size=bsize if size > bsize: size=bsize
data = file.read(size) self.lock.acquire()
try:
file.seek(start)
data = file.read(size)
finally:
self.lock.release()
if data: if data:
start=start+len(data) start=start+len(data)
if start < end: if start < end:
......
...@@ -117,6 +117,7 @@ from cStringIO import StringIO ...@@ -117,6 +117,7 @@ from cStringIO import StringIO
from tempfile import TemporaryFile from tempfile import TemporaryFile
import socket, string, os, sys, time import socket, string, os, sys, time
from types import StringType from types import StringType
import thread
tz_for_log = compute_timezone_for_log() tz_for_log = compute_timezone_for_log()
...@@ -716,6 +717,7 @@ class FCGIServer(asyncore.dispatcher): ...@@ -716,6 +717,7 @@ class FCGIServer(asyncore.dispatcher):
class FCGIResponse(HTTPResponse): class FCGIResponse(HTTPResponse):
_tempfile=None _tempfile=None
_templock=None
_tempstart=0 _tempstart=0
def setChannel(self, channel): def setChannel(self, channel):
...@@ -731,6 +733,7 @@ class FCGIResponse(HTTPResponse): ...@@ -731,6 +733,7 @@ class FCGIResponse(HTTPResponse):
if type(l) is type(''): l=string.atoi(l) if type(l) is type(''): l=string.atoi(l)
if l > 128000: if l > 128000:
self._tempfile=TemporaryFile() self._tempfile=TemporaryFile()
self._templock=thread.allocate_lock()
except: pass except: pass
stdout.write(str(self)) stdout.write(str(self))
...@@ -750,10 +753,14 @@ class FCGIResponse(HTTPResponse): ...@@ -750,10 +753,14 @@ class FCGIResponse(HTTPResponse):
l=len(chunk) l=len(chunk)
b=self._tempstart b=self._tempstart
e=b+l e=b+l
t.seek(b) self._templock.acquire()
t.write(chunk) try:
t.seek(b)
t.write(chunk)
finally:
self._templock.release()
self._tempstart=e self._tempstart=e
stdout.write((file_part_producer(t,b,e), l)) stdout.write((file_part_producer(t,self._templock,b,e), l))
def _finish(self): def _finish(self):
self.channel.reply_code=self.status self.channel.reply_code=self.status
......
...@@ -91,7 +91,7 @@ and logging duties. ...@@ -91,7 +91,7 @@ and logging duties.
""" """
import time, regex, string, sys, tempfile import time, regex, string, sys, tempfile
from cStringIO import StringIO from cStringIO import StringIO
import thread
from ZPublisher.HTTPResponse import HTTPResponse, end_of_header_search from ZPublisher.HTTPResponse import HTTPResponse, end_of_header_search
from medusa.http_date import build_http_date from medusa.http_date import build_http_date
from PubCore.ZEvent import Wakeup from PubCore.ZEvent import Wakeup
...@@ -215,7 +215,9 @@ class ZServerHTTPResponse(HTTPResponse): ...@@ -215,7 +215,9 @@ class ZServerHTTPResponse(HTTPResponse):
return string.join(headersl,'\r\n') return string.join(headersl,'\r\n')
_tempfile=None _tempfile=None
_templock=None
_tempstart=0 _tempstart=0
def write(self,data): def write(self,data):
"""\ """\
Return data as a stream Return data as a stream
...@@ -240,6 +242,7 @@ class ZServerHTTPResponse(HTTPResponse): ...@@ -240,6 +242,7 @@ class ZServerHTTPResponse(HTTPResponse):
if type(l) is type(''): l=string.atoi(l) if type(l) is type(''): l=string.atoi(l)
if l > 128000: if l > 128000:
self._tempfile=tempfile.TemporaryFile() self._tempfile=tempfile.TemporaryFile()
self._templock=thread.allocate_lock()
except: pass except: pass
stdout.write(str(self)) stdout.write(str(self))
...@@ -254,10 +257,14 @@ class ZServerHTTPResponse(HTTPResponse): ...@@ -254,10 +257,14 @@ class ZServerHTTPResponse(HTTPResponse):
l=len(data) l=len(data)
b=self._tempstart b=self._tempstart
e=b+l e=b+l
t.seek(b) self._templock.acquire()
t.write(data) try:
t.seek(b)
t.write(data)
finally:
self._templock.release()
self._tempstart=e self._tempstart=e
stdout.write(file_part_producer(t,b,e), l) stdout.write(file_part_producer(t,self._templock,b,e), l)
def _finish(self): def _finish(self):
stdout=self.stdout stdout=self.stdout
......
...@@ -128,8 +128,9 @@ class file_part_producer: ...@@ -128,8 +128,9 @@ class file_part_producer:
# match http_channel's outgoing buffer size # match http_channel's outgoing buffer size
out_buffer_size = 1<<16 out_buffer_size = 1<<16
def __init__(self, file, start, end): def __init__(self, file, lock, start, end):
self.file=file self.file=file
self.lock=lock
self.start=start self.start=start
self.end=end self.end=end
...@@ -140,12 +141,17 @@ class file_part_producer: ...@@ -140,12 +141,17 @@ class file_part_producer:
if start >= end: return '' if start >= end: return ''
file=self.file file=self.file
file.seek(start)
size=end-start size=end-start
bsize=self.out_buffer_size bsize=self.out_buffer_size
if size > bsize: size=bsize if size > bsize: size=bsize
data = file.read(size) self.lock.acquire()
try:
file.seek(start)
data = file.read(size)
finally:
self.lock.release()
if data: if data:
start=start+len(data) start=start+len(data)
if start < end: if start < end:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment