<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jython Journeys &#187; performance</title>
	<atom:link href="http://jython.xhaus.com/tag/performance/feed/" rel="self" type="application/rss+xml" />
	<link>http://jython.xhaus.com</link>
	<description>Notes about my work with jython and python</description>
	<lastBuildDate>Tue, 01 Dec 2009 19:37:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Twisted and Zope: high performance asynchronous network servers in jython.</title>
		<link>http://jython.xhaus.com/twisted-and-zope-high-performance-asynchronous-network-servers-in-jython/</link>
		<comments>http://jython.xhaus.com/twisted-and-zope-high-performance-asynchronous-network-servers-in-jython/#comments</comments>
		<pubDate>Mon, 15 Sep 2008 19:10:13 +0000</pubDate>
		<dc:creator>alan.kennedy</dc:creator>
				<category><![CDATA[jython]]></category>
		<category><![CDATA[asynchronous]]></category>
		<category><![CDATA[networking]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://jython.xhaus.com/?p=5</guid>
		<description><![CDATA[I&#8217;m tremendously excited this week; it looks like the work I did on supporting asynchronous sockets and select in jython has paid off.

Cpython excels in a very specific area; asynchronous (aka non-blocking) network servers. Back in the days before multi-threading was invented, asynchronous designs were the only available mechanism for managing more than one connection [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m tremendously excited this week; it looks like <a href="http://fisheye3.atlassian.com/changelog/jython?cs=3227">the work I did on supporting asynchronous sockets and select in jython</a> has paid off.</p>
<p><span id="more-5"></span></p>
<p>Cpython excels in a very specific area; <a href="http://en.wikipedia.org/wiki/Asynchronous_I/O">asynchronous (aka non-blocking) network servers</a>. Back in the days before <a href="http://en.wikipedia.org/wiki/Thread_(computer_science)">multi-threading</a> was invented, asynchronous designs were the only available mechanism for managing more than one connection in a single <a href="http://en.wikipedia.org/wiki/Process_(computing)">process</a>. Although it was possible to spawn off <a href="http://en.wikipedia.org/wiki/Child_process">new processes</a> to service incoming requests, that made <a href="http://en.wikipedia.org/wiki/Inter-process_communication">communicating and sharing</a> information and resources (e.g. database connections) between server components more complex and intractable.</p>
<p>With an asynchronous design, all of the incoming socket connections are managed by a single process. Current socket connections are kept in a simple data structure, such as a list, along with state information relating to the connection, and perhaps a handler, i.e. a piece of code that services the incoming requests. The single process used the unix <a href="http://docs.python.org/lib/module-select.html">select</a> call (or its descendants such as <a href="http://docs.python.org/lib/poll-objects.html">poll</a>) to monitor the state of every connection simultaneously, and then invoking the associated handlers when a network event of interest to them occurred (i.e. following a <a href="http://en.wikipedia.org/wiki/Reactor_pattern">reactor pattern</a>). And therein lies the problem.</p>
<p>When the asynch server calls the handler to service a request, that handler cannot delay before it returns; it must return very quickly, or it holds up the entire server. Returning quickly is easy if you&#8217;re doing trivial processing, e.g. an echo or chat server.  But if you need to connect to a database, or even do something as simple as a DNS lookup, that requires forming another network connection, sending a request packet and waiting for a response. Which means that if your database or DNS library waits until the response arrives, hundreds of milliseconds or even seconds later, then the entire network server is held up, and clients must wait possibly seconds for service; clearly unacceptable. So with asynchronous servers, you must always use libraries that are aware they are operating in an asynchronous environment, are able to surrender control while they are awaiting a network response, and can add themselves to the server <a href="http://en.wikipedia.org/wiki/Reactor_pattern">reactor</a>, so that they can be notified when their response arrives.</p>
<p>While asynchronous architectures thrived in many areas, they proved to be overly complex for the mainstream programming market. Making all libraries asynch-aware, and tracking all of the interactions between them, was complex, difficult to understand, and thus error-prone. <a href="http://en.wikipedia.org/wiki/Thread_(computer_science)">Multi-threading</a> was invented to circumvent these problems. Instead of a single thread of execution controlling network service, separate threads of execution could be created, giving the illusion that there were multiple copies of the server code executing simultaneously, inside the same process, sharing memory, etc. Actually all the threads were running on the same linear processor, and the available <a href="http://en.wikipedia.org/wiki/Preemptive_multitasking#Time_slice">timeslices</a> were divided between them, in much the same way that most modern operating systems timeslice a single processor between multiple processes. The threads would generally run the same instructions, but would have their own program counter and call stack. Threads made programmers lives much easier, since threads could be designed to execute in a linear fashion. If the thread needed to pause at any stage, e.g. to await the response to a network request, it simply suspended itself, and a different thread <a href="http://en.wikipedia.org/wiki/Context_switch">would be selected to be given CPU time</a>. At low cost.</p>
<p>Well, not quite.</p>
<p>There are problem with threads. Threads can have <a href="http://forums.sun.com/thread.jspa?messageID=3803197">very large memory overheads</a>, perhaps measuring in megabytes. Threads must <a href="http://en.wikipedia.org/wiki/Synchronization_(computer_science)">synchronised</a>, so that they don&#8217;t corrupt shared data structures, e.g. <a href="http://en.wikipedia.org/wiki/Race_condition">race conditions</a>, which can be very hard to recognise when they happen, and complex to avoid in design. And threads can <a href="http://en.wikipedia.org/wiki/Deadlock">deadlock</a>, which can be enormously difficult to debug.</p>
<p>The overhead of threads is such that it is rare to see a threading-based server outperform a well designed asynchronous server, on identical hardware. Threaded servers rarely service more than a couple of thousand network connections simultaneously; many can only service in the hundreds per second. There have been incredible increases in all forms of hardware capacity in recent decades; commodity boxes come  with gigahertz processors, gigabytes of memory, terabytes of hard disk, and gigabits of network bandwidth. But although threaded-based servers have vastly improved in design, they still cannot match the performance of asynchronous servers, and address the <a href="http://www.kegel.com/c10k.html">C10K problem</a>.</p>
<p>The C10K problem is a simple one; how to service 10,000 simultaneous network requests. I refer to you the <a href="http://www.kegel.com/c10k.html">C10K website</a> for enormously detailed technical information on this complex problem. Suffice it to say that asynchronous architectures, with their much smaller memory usage, and lack of need for locking, synchronisation and context-switching, are generally considered to be far more performant than threaded architectures.</p>
<p>So where does python come in? It so happens that python is an excellent language for writing asynchronous servers. Python&#8217;s expressiveness and conciseness make it an excellent choice for developing simple and elegant solutions to the problems posed by asynchronous designs. Python was first published in 1991, years before java, and did not develop multi-threading until much later; <a href="http://docs.python.org/lib/module-threading.html">python&#8217;s threading design</a> borrows much from java&#8217;s design. Before threading came to python, asynchronous was the design of choice; none more so than Sam Rushing&#8217;s <a href="http://www.nightmare.com/medusa/">medusa</a>, which is still considered the archetypal asychronous design, and was adapted into python as the <a href="http://www.python.org/doc/current/lib/module-asyncore.html">asyncore module</a>.</p>
<p>But asyncore is basic, and doesn&#8217;t provide non-blocking support for the protocols necessary in a real-world application; database protocols, DNS lookups, etc. But there are two heavyweights in the python asynchronous world that have the required support, in a robust form. <a href="http://www.zope.com">Zope Corporation</a> was there first with their venerable <a href="http://en.wikipedia.org/wiki/Zope">Zope</a> product, arguably the grand-daddy of all python web frameworks. But dissatisfaction with Zope&#8217;s complexity lead to a new initiative; the <a href="http://en.wikipedia.org/wiki/Twisted_(software)">Twisted Matrix</a>. I won&#8217;t try to introduce Twisted here; take a look at the names of the sponsors on the <a href="http://twistedmatrix.com/">Twisted website</a> to see how important a framework it is.</p>
<p>And that&#8217;s why I&#8217;m excited; Twisted could soon be running on jython!</p>
<p>Back in the old days, jython 2.1 could not do aysnchronous socket operations. Jython 2.1 was written in the days when the only socket support in java was <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/net/package-summary.html">java.net</a>, which was threading oriented. It was only in <a href="http://java.sun.com/j2se/1.4.2/docs/guide/nio/">version 1.4 of the JVM that asynchronous support arrived</a>, in the shape of the <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/nio/package-summary.html">java.nio</a> package. Now java has robust asynchronous support, after several years in the field.</p>
<p>I saw the possibility of using java.nio to enable jython to do asynchronous sockets a couple of years ago. I developed the support, and <a href="&lt;a href=">checked it into jython 2.2 last year</a>, in the hope that it would draw the attention of developers of the big cpython asynchronous frameworks. Java has some distinct advantages over cpython in high performance network serving world, with the most obvious being the ability to run on all cores of <a href="http://en.wikipedia.org/wiki/Multi-core_(computing)">multi-core processors</a> simultaneously. Cpython is restricted in this regard by it&#8217;s <a href="http://en.wikipedia.org/wiki/Global_Interpreter_Lock">Global Interpreter Lock</a>, which prevents multiple threads running pure python code from running on multiple cores or processors simultanously. In java, and thus in jython, every single core in the multi-core system can be running its own reactor, actually simultaneously.</p>
<p>It&#8217;s looking more like those cpython asynchronous frameworks could be coming to jython soon.</p>
<p>The founder and chief architect of Twisted, <a href="http://glyph.twistedmatrix.com/">Glyph Lefkowitz</a>, logged three bugs (<a href="http://bugs.jython.org/issue1119">1119</a>, <a href="http://bugs.jython.org/issue1120">1120</a>, <a href="http://bugs.jython.org/issue1121">1121</a>) against the jython socket module last week; I fixed them yesterday. I&#8217;m glad to say that they were all relating to corner cases and unusual usage; so far there have been no reports of serious bugs in the main functionality of the socket module. So hopefully the road to running twisted on jython is clear and obstacle free, at least at the level of socket communications.</p>
<p>And the Zope people have an ongoing project to get Zope running on jython; see the <a href="http://www.nabble.com/forum/Search.jtp?query=jython&amp;sort=date&amp;local=y&amp;forum=6720">Zope-dev archives</a> for ongoing updates.</p>
<p>Yes, exciting times indeed!</p>
<p>If you are interested in reading further about asynchronous I/O in the java.nio package, I thoroughly recommend Ron Hitchens book <a href="http://javanio.info">Java NIO</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jython.xhaus.com/twisted-and-zope-high-performance-asynchronous-network-servers-in-jython/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTTP Compression in python and jython</title>
		<link>http://jython.xhaus.com/http-compression-in-python-and-jython/</link>
		<comments>http://jython.xhaus.com/http-compression-in-python-and-jython/#comments</comments>
		<pubDate>Sun, 13 Jan 2002 10:00:46 +0000</pubDate>
		<dc:creator>alan.kennedy</dc:creator>
				<category><![CDATA[jython]]></category>
		<category><![CDATA[networking]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[web technology]]></category>

		<guid isPermaLink="false">http://jython.xhaus.com/?p=124</guid>
		<description><![CDATA[Index

Introduction
Can the browser handle GZIPped content?
GZIP vs ZLIB
Content-encoding vs Transfer-encoding
Content-length
Character translation on Windows and OS/2
OutputStream vs. Writer in jython servlets
Some links for related reading
Some sample CGI code
Some sample code for mod_python
Some sample code for jython servlets


		
Introduction

			These are some notes on how to do HTTP compression, i.e. compress content before it is sent to the user. [...]]]></description>
			<content:encoded><![CDATA[<h3>Index</h3>
<ol>
<li><a class="a" href="#intro">Introduction</a></li>
<li><a class="a" href="#browser">Can the browser handle GZIPped content?</a></li>
<li><a class="a" href="#gzip">GZIP vs ZLIB</a></li>
<li><a class="a" href="#encoding">Content-encoding vs Transfer-encoding</a></li>
<li><a class="a" href="#length">Content-length</a></li>
<li><a class="a" href="#chartrans">Character translation on Windows and OS/2</a></li>
<li><a class="a" href="#servletout">OutputStream vs. Writer in jython servlets</a></li>
<li><a class="a" href="#links">Some links for related reading</a></li>
<li><a class="a" href="#cgicode">Some sample CGI code</a></li>
<li><a class="a" href="#modpython">Some sample code for mod_python</a></li>
<li><a class="a" href="#jython">Some sample code for jython servlets</a></li>
</ol>
<hr/>
		<a name="intro"></a></p>
<h3>Introduction</h3>
<p>
			These are some notes on how to do HTTP compression, i.e. compress content before it is sent to the user. The benefits are
		</p>
<ol>
<li>You transmit less bandwidth. If the amount of bandwidth you can serve is limited (i.e. you have fixed allocation of X gig/month), then compressing your content before you send it can dramatically lower your transmitted bandwidth.</li>
<li>Your client receives less bandwidth, meaning that pages load faster for them. This is particularly important for people using modems. (Although some modems already do compression. I have no idea how efficient modem compression is compared to gzip. See the <a class="a" href="#links">Links section</a> for a link to an article which discusses HTML compression vs. modem compression.)</li>
</ol>
<p>
			Some points to remember
		</p>
<ol>
<li>Although you save on bandwidth transmitted from your server, it comes at a cost of increased CPU usage on the server.</li>
<li>Compressing images probably isn&#8217;t worth it. Specialised image compression formats such as <b>GIF</b>, <b>JPEG</b>, and <b>PNG</b> are optimised for the content they carry, and probably cannot be much improved on. So it&#8217;s probably not worth compressing images using these techniques.</li>
<li>The best bandwidth saving will be achieved on textual files, i.e. mime types like <code>&lt;text/plain&gt;, &lt;text/html&gt;, &lt;text/xml&gt;</code>.</li>
</ol>
<p>
			I&#8217;m not going to go into the details of the rationale or the mechanisms of compression here, I&#8217;m just going to stick to telling you how to do http compression in python. If you want to know about the nuts and bolts of compression and http, I suggest you read
		</p>
<ol>
<li><a class="a" href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616: Hypertext Transfer Protocol &#8212; HTTP/1.1</a></li>
<li><a class="a" href="http://www.ietf.org/rfc/rfc1952.txt">RFC1952: GZIP file format specification version 4.3</a></li>
</ol>
<hr/>
<p>		<a name="browser"></a></p>
<h3>Can the browser handle GZIPped content?</h3>
<p>
			Not all browsers can handle compressed content. Old browsers that support HTTP version 0.9 are unlikely to support compressed content. Compression was optional in version 1.0 of the HTTP spec, so only some HTTP 1.0 clients support it, most notably versions 4.x of Netscape Navigator. Support for compression is compulsory in HTTP 1.1, so all HTTP 1.1 clients should support compression. HTTP 1.1 clients include Internet Explorer 5.0 and up. Although I don&#8217;t know if Internet Explorer 4.0 is HTTP 1.1 or 1.0, I&#8217;m sure IE 4.0 supports gzip compression.
		</p>
<p>
			Fortunately, you don&#8217;t have to guess or keep a list of which browsers do or do not support compression, since the browsers themselves will inform you of it in their HTTP request. Browsers that support compression will inform you via the HTTP header <code>Accept-Encoding</code> (Check your browser&#8217;s headers <a href="http://www.xhaus.com/headers">here</a>). Possible compression methods, as mentioned in RFC2616, include <b>gzip</b>, <b>compress</b>, <b>deflate</b>, and <b>identity</b>. Note that the last one, <b>identity</b>, means <b>no</b> compression. Note also that I&#8217;m only going to cover <b>gzip</b> in this document.
		</p>
<p>
			So if a browser supports compression, its HTTP request will include a header similar to one of the following
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">Accept-Encoding: <span style="color: #dc143c;">gzip</span>
Accept-Encoding: <span style="color: #dc143c;">gzip</span>, deflate</pre></div></div>

<p>
			So you need to get the value of the <code>Accept-Encoding</code> header, and check if it contains <code>gzip</code>. If it does, then you can send gzip-compressed content to that browser. Here is some CGI code that checks the content of the header
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">string</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
&nbsp;
acceptsGzip = <span style="color: #ff4500;">0</span>
<span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">string</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;HTTP_ACCEPT_ENCODING&quot;</span><span style="color: black;">&#93;</span>, <span style="color: #483d8b;">&quot;gzip&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span>:
        acceptsGzip = <span style="color: #ff4500;">1</span>
<span style="color: #ff7700;font-weight:bold;">except</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>
			And here is some mod_python code that checks the content of the header.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">string</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> acceptsGzip<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
        Checks if a browser request indicates that the browser will accept
        gzipped content in reply.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> req.<span style="color: black;">headers_in</span>.<span style="color: black;">has_key</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'accept-encoding'</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">encodings</span> = req.<span style="color: black;">headers_in</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'accept-encoding'</span><span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">encodings</span>, <span style="color: #483d8b;">&quot;gzip&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span></pre></div></div>

<p>
			And here is some jython servlet code that checks the content of the header.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">string</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> acceptsGzip<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;
        Checks if a browser request indicates that the browser will accept
        gzipped content in reply.
    &quot;&quot;&quot;</span>
    <span style="color: #dc143c;">encodings</span> = req.<span style="color: black;">getHeader</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'accept-encoding'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">encodings</span> <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">encodings</span>, <span style="color: #483d8b;">&quot;gzip&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span></pre></div></div>

</p>
<hr/>
<p>		<a name="gzip"></a></p>
<h3>GZIP vs ZLIB</h3>
<p>
			There are a few compression libraries that come with Python. The one which is used in HTTP compression is <b>GZIP</b>. <b>ZLIB</b>, although it is used by GZIP to do part of its job, should <b>not</b> be needed directly in your code.
		</p>
<p>
			When a file is compressed for transmission through http, it must be preceded by some special header bytes and followed by some special trailer bytes. Conveniently enough, the python GZIP module constructs exactly those headers and trailers. The details of what those headers and trailers are can be found in <a class="a" href="http://www.ietf.org/rfc/rfc1952.txt">RFC1952</a>.
		</p>
<p>
			In order to compress using the GZIP module, you&#8217;ll need to use code something like this.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">gzip</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> compressBuf<span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>:
    zbuf = <span style="color: #dc143c;">cStringIO</span>.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    zfile = <span style="color: #dc143c;">gzip</span>.<span style="color: black;">GzipFile</span><span style="color: black;">&#40;</span>mode = <span style="color: #483d8b;">'wb'</span>,  fileobj = zbuf, compresslevel = <span style="color: #ff4500;">9</span><span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">write</span><span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> zbuf.<span style="color: black;">getvalue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>
			Note that this code compresses into a buffer held in memory, rather than a disk file. This is done through the use of <code>cStringIO.StringIO()</code>.
		</p>
<p>
			You can vary the compression level by changing the value of the <code>compresslevel</code> parameter, with compresslevel = 9 giving the best compression but consuming the most CPU cycles, and compresslevel = 1 giving the least compression and also consuming the least CPU.
		</p>
<hr/>
<p>		<a name="encoding"></a></p>
<h3>Content-encoding vs Transfer-encoding</h3>
<p>
		When you&#8217;re sending compressed content back to the browser, you have to inform the browser of the compression. This is done by the header <code>Content-Encoding</code>. So you should include a header in your response that looks like this.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">Content-Encoding: <span style="color: #dc143c;">gzip</span></pre></div></div>

<p>
		You don&#8217;t need to read any further in this section. The note below about different methods of declaring encoding is just here for interest and completeness.
		</p>
<p>
		Note: There is another possible way to communicate the encoding: the <code>Transfer-Encoding</code> header. According to RFC2616, the difference between the two headers is as follows
		</p>
<ol>
<li><b>Content-Encoding</b> should be used when the encoding is a property of the content. So if you were serving a static file that is always compressed, then this is the header to use.</li>
<li><b>Transfer-Encoding</b> should be used when the encoding is a property of the message used to transmit the content. So you were sending a static file that is normally uncompressed, and were compressing it just so as to minimise bandwidth during the transmission, then this is the header you should use.</li>
</ol>
<p>
		However, RFC2616 is unclear what encoding to use if you are generating dynamic content, which may only be transient in memory and has no lifetime beyond the HTTP request-response pair it was contructed for. In such a situation, an argument could be made for using either <code>Content-Encoding</code> or <code>Transfer-Encoding</code>.
		</p>
<p>
		Rather than try to resolve that (potentially unresolvable) issue, I would just like to point out that majority of software &quot;out there&quot; seems to have opted for using <code>Content-Encoding</code>, and that&#8217;s the choice that I&#8217;ve made as well. You are, of course, free to choose otherwise.
		</p>
<hr/>
<p>		<a name="length"></a></p>
<h3>Content-Length</h3>
<p>
		You also need to tell the client browser the length of the compressed content you are sending. This is done by sending a <code>Content-Length</code> header, like this.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">Content-Length: xyz</pre></div></div>

<p>
		where <b>xyz</b> is the <b>COMPRESSED</b> length of the content.
		</p>
<p>
		There seems to be some &quot;folk wisdom&quot; out there on the &#8216;net that you should send the <b>uncompressed</b> length of the content. This is <b>wrong</b>! <a class="a" href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a> is quite clear about this. If you are interested, read sections 7.2.2 Entity-Length and 4.4 Message Length.
		</p>
<p>
		As far as I can see, the definitive statement on this matter is at the end of section 4.4 (I have underlined the relevant statement)
		</p>
<blockquote><p>
<u>When a Content-Length is given in a message where a message-body<br />
is allowed, its field value MUST exactly match the number of OCTETs<br />
in the message-body</u>. HTTP/1.1 user agents MUST notify the user when<br />
an invalid length is received and detected.
			</p></blockquote>
<hr/>
<p>		<a name="chartrans"></a></p>
<h3>Character translation on Windows and OS/2</h3>
<p>
		If you&#8217;re working in CGI, and on Windows or on OS/2, you need to be careful about character translation.
		</p>
<p>
		As you may be aware, Windows and OS/2 are different from other platforms in the way that they represent an end of line. Whereas most platforms, including *nix, represent line ends as an ASCII linefeed (hex 0&#215;0A, octal 012, python escape string &#8216;\n&#8217;), Windows and OS/2 represent end-of-line as a sequence of two characters, an ASCII carriage return followed by an ASCII linefeed (hex 0&#215;0D 0&#215;0A, octal 015 012, python escape string &#8216;\r\n&#8217;). Therefore, when you print anything in python, or write anything to <code>sys.stdout</code>, using code like this
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Hello World!&quot;</span>
<span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Hello World!<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>
		then both Windows and OS/2 filter the characters, and turn all linefeed characters into a sequence of carriage return followed by linefeed.
		</p>
<p>
		This is fine when you&#8217;re printing text. But when you&#8217;re trying to send binary information, particularly a compressed gzipped file, then this translation will corrupt the binary content, and your transmission of gzip compressed content will fail. Therefore, you have to disable this character translation in order for transmission of gzipped content to work.
		</p>
<p>
			When you&#8217;re working in CGI, the best way to do this is with the &#8220;-u&#8221; command line flag to python. This was kindly pointed out by <b>Richie Hindle</b>, who says
		</p>
<blockquote><p><b><br />
		&#8230;&#8230; There is a much simpler way to switch off character translation of the standard<br />
channels.  The python interpreter accepts the -u switch to mean &#8220;make the<br />
standard channels both unbuffered and binary.&#8221;  This is tailor-made for<br />
CGI &#8211; change your shebang line from &#8220;#!&#8230;python&#8221; to &#8220;#!&#8230;python -u&#8221; and<br />
everything will work without changing your code (and without relying on<br />
platorm-specific modules like msvcrt).  Responsiveness may even improve<br />
due to the lack of buffering &#8211; and that&#8217;s also true on platforms like Unix<br />
which don&#8217;t do character translation.<br />
		</b></p></blockquote>
<p>
		A less convenient method is to execute some platform specific code to disable character translation inside your script. On Windows (MSVC), you should execute some code like this
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">msvcrt</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #dc143c;">msvcrt</span>.<span style="color: black;">setmode</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">fileno</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: #dc143c;">os</span>.<span style="color: black;">O_BINARY</span><span style="color: black;">&#41;</span></pre></div></div>

<p>
		I don&#8217;t know what the equivalent code is on Windows (CygWin) or OS/2. If anyone does, <a class="a" href="http://www.xhaus.com/contact/alan">email it to me</a>, and I&#8217;ll include it in this page.
		</p>
<hr/>
<p>		<a name="servletout"></a></p>
<h3>OutputStream vs. Writer in jython servlets.</h3>
<p>
		Under the J2EE Servlet interface, you have a choice of two different ways to output generated content. They are
		</p>
<ol>
<li>Through an <b>OutputStream</b> (obtained by calling <code>ServletResponse.getOutputStream()</code>). <code>OutputStream</code>s do not carry out character translation on their output.</li>
<li>Through a <b>Writer</b> (obtained by calling <code>ServletResponse.getWriter()</code>). <code>Writer</code>s carry out character translation on their output, i.e. they will change the value of bytes in the content output by the servlet, to ensure that it meets the character encoding requirements of the client.</li>
</ol>
<p>
		Since compressed gzip content is a (dense) binary format, none of the output bytes should be translated. If any bytes are translated, the output may be corrupted and the recipient may be unable to decode it. Therefore, you must output compressed content through a (non-translating) <code>OutputStream</code> object.
		</p>
<hr/>
<p>		<a name="links"></a></p>
<h3>Some links for related reading</h3>
<ul>
<li>W3C: <a class="a" href="http://www.w3.org/Protocols/HTTP/Performance/#Compression">Compression and Performance</a></li>
</ul>
<hr/>
<p>		<a name="cgicode"></a></p>
<h3>Some sample CGI code</h3>
<p>
		So, without further ado, here is some sample CGI code that will transmit compressed HTML to gzip capable browsers.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#! /path/to/python -u</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">string</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">gzip</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cStringIO</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> compressBuf<span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>:
    zbuf = <span style="color: #dc143c;">cStringIO</span>.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    zfile = <span style="color: #dc143c;">gzip</span>.<span style="color: black;">GzipFile</span><span style="color: black;">&#40;</span>mode = <span style="color: #483d8b;">'wb'</span>,  fileobj = zbuf, compresslevel = <span style="color: #ff4500;">6</span><span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">write</span><span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> zbuf.<span style="color: black;">getvalue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> testAcceptsGzip<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    acceptsGzip = <span style="color: #ff4500;">0</span>
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">string</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;HTTP_ACCEPT_ENCODING&quot;</span><span style="color: black;">&#93;</span>, <span style="color: #483d8b;">&quot;gzip&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span>:
            acceptsGzip = <span style="color: #ff4500;">1</span>
    <span style="color: #ff7700;font-weight:bold;">except</span>:
        <span style="color: #ff7700;font-weight:bold;">pass</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> acceptsGzip
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> sendHtml<span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Content-type: text/html<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> testAcceptsGzip<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        zbuf = compressBuf<span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Content-Encoding: gzip<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Content-Length: %d<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>zbuf<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>zbuf<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>
&nbsp;
myHtml = <span style="color: #483d8b;">&quot;&quot;&quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;hello compressed world!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;&quot;&quot;</span>
sendHtml<span style="color: black;">&#40;</span>myHtml<span style="color: black;">&#41;</span></pre></div></div>

<hr/>
<p>		<a name="modpython"></a></p>
<h3>Some sample mod python code</h3>
<p>
		And here is some sample mod python code that will transmit compressed HTML to gzip capable browsers.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">string</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">gzip</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">cStringIO</span>
<span style="color: #ff7700;font-weight:bold;">from</span>   mod_python <span style="color: #ff7700;font-weight:bold;">import</span> apache
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> compressBuf<span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>:
    zbuf = <span style="color: #dc143c;">cStringIO</span>.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    zfile = <span style="color: #dc143c;">gzip</span>.<span style="color: black;">GzipFile</span><span style="color: black;">&#40;</span>mode = <span style="color: #483d8b;">'wb'</span>,  fileobj = zbuf, compresslevel = <span style="color: #ff4500;">6</span><span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">write</span><span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> zbuf.<span style="color: black;">getvalue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> testAcceptsGzip<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> req.<span style="color: black;">headers_in</span>.<span style="color: black;">has_key</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'accept-encoding'</span><span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">encodings</span> = req.<span style="color: black;">headers_in</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'accept-encoding'</span><span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">encodings</span>, <span style="color: #483d8b;">&quot;gzip&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> handler<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
    req.<span style="color: black;">content_type</span> = <span style="color: #483d8b;">&quot;text/html&quot;</span>
    myHtml = <span style="color: #483d8b;">&quot;&quot;&quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;hello compressed world!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> testAcceptsGzip<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
        zbuf = compressBuf<span style="color: black;">&#40;</span>myHtml<span style="color: black;">&#41;</span>
        req.<span style="color: black;">headers_out</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Content-Encoding'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'gzip'</span>
        req.<span style="color: black;">headers_out</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Content-Length'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'%d'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>zbuf<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        req.<span style="color: black;">send_http_header</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        req.<span style="color: black;">write</span><span style="color: black;">&#40;</span>zbuf<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        req.<span style="color: black;">send_http_header</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        req.<span style="color: black;">write</span><span style="color: black;">&#40;</span>myHtml<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> apache.<span style="color: black;">OK</span></pre></div></div>

<hr/>
<p>		<a name="jython"></a></p>
<h3>Some sample jython servlet code</h3>
<p>
		And here is some sample jython servlet code that will transmit compressed HTML to gzip capable browsers.
		</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span>  javax.<span style="color: black;">servlet</span>.<span style="color: black;">http</span>.<span style="color: black;">HttpServlet</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span>  <span style="color: #dc143c;">cStringIO</span>
<span style="color: #ff7700;font-weight:bold;">import</span>  <span style="color: #dc143c;">gzip</span>
<span style="color: #ff7700;font-weight:bold;">import</span>  <span style="color: #dc143c;">string</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> compressBuf<span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>:
    zbuf = <span style="color: #dc143c;">cStringIO</span>.<span style="color: #dc143c;">StringIO</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    zfile = <span style="color: #dc143c;">gzip</span>.<span style="color: black;">GzipFile</span><span style="color: black;">&#40;</span>mode = <span style="color: #483d8b;">'wb'</span>,  fileobj = zbuf, compresslevel = <span style="color: #ff4500;">6</span><span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">write</span><span style="color: black;">&#40;</span>buf<span style="color: black;">&#41;</span>
    zfile.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> zbuf.<span style="color: black;">getvalue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> acceptsGzip<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">encodings</span> = req.<span style="color: black;">getHeader</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'accept-encoding'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">encodings</span> <span style="color: #66cc66;">!</span>= <span style="color: #008000;">None</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">string</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">encodings</span>, <span style="color: #483d8b;">&quot;gzip&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= -<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff4500;">0</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> compressor<span style="color: black;">&#40;</span>javax.<span style="color: black;">servlet</span>.<span style="color: black;">http</span>.<span style="color: black;">HttpServlet</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> service<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, req, resp<span style="color: black;">&#41;</span>:
        resp.<span style="color: black;">setContentType</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'text/html'</span><span style="color: black;">&#41;</span>
        myHtml = <span style="color: #483d8b;">&quot;&quot;&quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;hello compressed world!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> acceptsGzip<span style="color: black;">&#40;</span>req<span style="color: black;">&#41;</span>:
            binarychan = resp.<span style="color: black;">getOutputStream</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            zbuf = compressBuf<span style="color: black;">&#40;</span>myHtml<span style="color: black;">&#41;</span>
            resp.<span style="color: black;">setHeader</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Content-Encoding'</span>, <span style="color: #483d8b;">'gzip'</span><span style="color: black;">&#41;</span>
            resp.<span style="color: black;">setHeader</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Content-Length'</span>, <span style="color: #483d8b;">'%d'</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>zbuf<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            binarychan.<span style="color: black;">write</span><span style="color: black;">&#40;</span>zbuf<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            textchan = resp.<span style="color: black;">getWriter</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            textchan.<span style="color: black;">write</span><span style="color: black;">&#40;</span>myHtml<span style="color: black;">&#41;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://jython.xhaus.com/http-compression-in-python-and-jython/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
