This commit is contained in:
Ryan Williams
2010-01-04 21:52:16 -08:00
5 changed files with 48 additions and 12 deletions

View File

@@ -23,6 +23,7 @@ Linden Lab Contributors
Thanks To
---------
* Michael Barton, 100-continue patch, content-length bugfixes for wsgi
* gholt, wsgi patches for accepting a custom pool, and returning 400 if content-length is invalid
* Luke Tucker, bug report regarding wsgi + webob
* Chuck Thier, reporting a bug in processes.py

View File

@@ -22,9 +22,7 @@
<p>Eventlet is a networking library written in Python. It achieves high scalability by using <a class="reference external" href="http://en.wikipedia.org/wiki/Asynchronous_I/O#Select.28.2Fpoll.29_loops">non-blocking io</a> while at the same time retaining high programmer usability by using <a class="reference external" href="http://en.wikipedia.org/wiki/Coroutine">coroutines</a> to make the non-blocking io operations appear blocking at the source code level.</p>
<h3>Documentation</h3>
<a href="doc/">API Documentation</a>
<h3><a href="doc/">API Documentation</a></h3>
<h3>Installation</h3>
@@ -47,10 +45,16 @@ easy_install eventlet
<h3>Development</h3>
<p><a href="http://bitbucket.org/which_linden/eventlet/">"root" repository</a></p>
<p><a href="http://bitbucket.org/which_linden/eventlet/">trunk repository</a></p>
<p>We use Mercurial for our source control, hosted by BitBucket. It's easy to branch off the main repository and contribute patches, tests, and documentation back upstream.</p>
<h4>Bugs</h4>
<p><a href="http://bitbucket.org/which_linden/eventlet/issues/new/">Bug Report Form</a></p>
<p>No registration is required. Please be sure to report bugs <a href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">as effectively as possible</a>, to ensure that we understand and act on them quickly.</p>
<div class="section" id="web-crawler-example">
<h2>Web Crawler Example<a class="headerlink" href="#web-crawler-example" title="Permalink to this headline"></a></h2>
<p>This is a simple web &#8220;crawler&#8221; that fetches a bunch of urls using a coroutine pool. It has as much concurrency (i.e. pages being fetched simultaneously) as coroutines in the pool.</p>
@@ -78,9 +82,13 @@ easy_install eventlet
<span class="k">for</span> <span class="n">waiter</span> <span class="ow">in</span> <span class="n">waiters</span><span class="p">:</span>
<span class="n">waiter</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
</pre></div>
<h3>Stats</h3>
<script type="text/javascript" src="http://www.ohloh.net/p/480234/widgets/project_basic_stats.js"></script>
</div>
</div>
</div>
<div class="section" id="contents">
</div>
</div>
@@ -92,6 +100,7 @@ easy_install eventlet
<ul>
<li><a class="reference external" href="doc/">Documentation</a></li>
<li><a class="reference external" href="https://lists.secondlife.com/pipermail/eventletdev/">Mailing list archives</a></li>
</ul>
</div>
</div>
</div>

View File

@@ -297,14 +297,14 @@ class GenericConnectionWrapper(object):
def character_set_name(self,*args, **kwargs): return self._base.character_set_name(*args, **kwargs)
def close(self,*args, **kwargs): return self._base.close(*args, **kwargs)
def commit(self,*args, **kwargs): return self._base.commit(*args, **kwargs)
def cursor(self, cursorclass=None, **kwargs): return self._base.cursor(cursorclass, **kwargs)
def cursor(self, *args, **kwargs): return self._base.cursor(*args, **kwargs)
def dump_debug_info(self,*args, **kwargs): return self._base.dump_debug_info(*args, **kwargs)
def errno(self,*args, **kwargs): return self._base.errno(*args, **kwargs)
def error(self,*args, **kwargs): return self._base.error(*args, **kwargs)
def errorhandler(self, conn, curs, errcls, errval): return self._base.errorhandler(conn, curs, errcls, errval)
def literal(self, o): return self._base.literal(o)
def set_character_set(self, charset): return self._base.set_character_set(charset)
def set_sql_mode(self, sql_mode): return self._base.set_sql_mode(sql_mode)
def errorhandler(self, *args, **kwargs): return self._base.errorhandler(*args, **kwargs)
def literal(self, *args, **kwargs): return self._base.literal(*args, **kwargs)
def set_character_set(self, *args, **kwargs): return self._base.set_character_set(*args, **kwargs)
def set_sql_mode(self, *args, **kwargs): return self._base.set_sql_mode(*args, **kwargs)
def show_warnings(self): return self._base.show_warnings()
def warning_count(self): return self._base.warning_count()
def ping(self,*args, **kwargs): return self._base.ping(*args, **kwargs)
@@ -315,7 +315,7 @@ class GenericConnectionWrapper(object):
def server_capabilities(self,*args, **kwargs): return self._base.server_capabilities(*args, **kwargs)
def shutdown(self,*args, **kwargs): return self._base.shutdown(*args, **kwargs)
def sqlstate(self,*args, **kwargs): return self._base.sqlstate(*args, **kwargs)
def stat(self,*args, **kwargs): return self._base.stat(*args, **kwargs)
def stat(self, *args, **kwargs): return self._base.stat(*args, **kwargs)
def store_result(self,*args, **kwargs): return self._base.store_result(*args, **kwargs)
def string_literal(self,*args, **kwargs): return self._base.string_literal(*args, **kwargs)
def thread_id(self,*args, **kwargs): return self._base.thread_id(*args, **kwargs)

View File

@@ -297,8 +297,10 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
if hasattr(result, 'close'):
result.close()
if self.environ['eventlet.input'].position < self.environ.get('CONTENT_LENGTH', 0):
## Read and discard body
self.environ['eventlet.input'].read()
## Read and discard body if there was no pending 100-continue
if not self.environ['eventlet.input'].wfile:
while self.environ['eventlet.input'].read(MINIMUM_CHUNK_SIZE):
pass
finish = time.time()
self.server.log_message('%s - - [%s] "%s" %s %s %.6f' % (

View File

@@ -585,6 +585,30 @@ class TestHttpd(LimitedTestCase):
self.assert_('400 Bad Request' in result)
self.assert_('500' not in result)
def test_024_expect_100_continue(self):
def wsgi_app(environ, start_response):
if int(environ['CONTENT_LENGTH']) > 1024:
start_response('417 Expectation Failed', [('Content-Length', '7')])
return ['failure']
else:
text = environ['wsgi.input'].read()
start_response('200 OK', [('Content-Length', str(len(text)))])
return [text]
self.site.application = wsgi_app
sock = api.connect_tcp(('localhost', self.port))
fd = sock.makeGreenFile()
fd.write('PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\nExpect: 100-continue\r\n\r\n')
result = fd.readuntil('\r\n\r\n')
self.assert_(result.startswith('HTTP/1.1 417 Expectation Failed'))
self.assertEquals(fd.read(7), 'failure')
fd.write('PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\nExpect: 100-continue\r\n\r\ntesting')
result = fd.readuntil('\r\n\r\n')
self.assert_(result.startswith('HTTP/1.1 100 Continue'))
result = fd.readuntil('\r\n\r\n')
self.assert_(result.startswith('HTTP/1.1 200 OK'))
self.assertEquals(fd.read(7), 'testing')
fd.close()
if __name__ == '__main__':
main()