Re: Collating follow-up on the future of WSGI
Graham Dumpleton <[email protected]> Wed, 20 Jan 2016 23:03:19 +1100
| Newsgroups | gmane.comp.python.web |
|---|---|
| Message-ID | <[email protected]> |
--===============2377637489335467340== Content-Type: multipart/alternative; boundary="Apple-Mail=_52DF0C1B-3EE4-4EA1-A688-A9EFC393628E" --Apple-Mail=_52DF0C1B-3EE4-4EA1-A688-A9EFC393628E Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On 20 Jan 2016, at 10:25 PM, Andr=C3=A9 Malo <nd-qeD/[email protected]> wrote: >=20 > * Cory Benfield wrote: >=20 >>> On 20 Jan 2016, at 06:04, Graham Dumpleton = <[email protected]> >>> wrote: >>>=20 >>> For response content, if a WSGI application currently doesn=E2=80=99t = set a >>> Content-Length on response, A HTTP/1.1 web server is at liberty to = chunk >>> the response. >>>=20 >>> So I am not sure what is missing. >>=20 >> My specific concern is the distinction between =E2=80=9Cat liberty = to=E2=80=9D and >> =E2=80=9Crequired to=E2=80=9D. Certain behaviours that make sense = with chunked transfer >> encoding do not make sense without it: for example, streaming API = endpoints >> that return events as they arrive. Bidirectional HTTP is effectively a no go. CGI, SCGI and FASTCGI implementations, mod_wsgi daemon mode and many = HTTP proxies will often not actually start reading a response until they = have managed to send the full content of the request. There are also = various issues around buffering, especially with intermediaries. So if your expectation is that that you can send a bit of a request, = have client wait for a response for that bit, then send more request, = wait for more response for that part of the request and so on, it = isn=E2=80=99t going to work for most implementations. This problem/issue and the lack of support for both way streaming has = been the subjects of some RFCs. I can=E2=80=99t remember if this is the = exact one I remember seeing before, but does appear relevant: https://www.ietf.org/rfc/rfc6202.txt = <https://www.ietf.org/rfc/rfc6202.txt> Anyway, the end result as I saw it was no one could be bothered = supporting proper bidirectional HTTP as getting proxies/caches changed = was going to be too hard. The solution was to give up on it for HTTP/1.X and instead do it in = HTTP/2 as upgrading a HTTP connection to something else generally had = the effect of bypassing any intermediaries behaviour which would cause = issues as then it would switch to streaming properly in both directions. = So I think it is a lost cause to try and do it in HTTP/1.X and WSGI. >> Sending this kind of response with a >> HTTP/1.0-style content-length absent response (framed by connection >> termination) is utterly confusing, especially as some APIs consider = the >> chunk framing to be semantic. >=20 > Those APIs are just broken then. The HTTP RFCs state very clearly [1], = that=20 > any hop may modify the transfer encoding. In other words: the transfer=20= > encoding is transparent to the representation layer. Yep. If framing was required you could never rely on the HTTP chunking. = Framing had to be done in the actual data. >> This can and does bite people, because while all major production = WSGI >> servers use chunked transfer encoding in this situation, not all WSGI >> implementations do: in fact, wsgiref does not. This means that if an >> application has a production design requirement to use chunked = transfer >> encoding in its responses it cannot rely on the server actually = providing >> it. >>=20 >> I see two solutions to this problem: we could mandate that HTTP/1.1 >> responses that have no content length must be chunked, rather than = falling >> back to HTTP/1.0 style connection-termination-framed responses, or we = could >> have servers stuff something in the environ dictionary that can be = checked >> by applications. Or, I suppose, we can conclude that this problem is = not >> large enough, and that it=E2=80=99s =E2=80=9Ccaveat developer=E2=80=9D.= >=20 > WSGI is a gateway working with the representation layer. I think, it = should=20 > not concern itself with underlying transport issues that much. >=20 > Regarding chunked requests - in my own WSGI implementation I went the = most=20 > pragmatic way and simply provided a CONTENT_LENGTH of -1 for unknown = request=20 > sizes (it maps very well to file.read(size)). Something like this = would be my=20 > suggestion for a future WSGI spec. I am assuming here you mean that -1 means return whatever you have = available, or block until you have something. Problem with that is that some implementations will use -1 as a default = value to mean no argument supplied and so read all input. So that could well conflict with some implementations. Also, if it is going to block, how is it really different to reading = with a block size. The whole think with chunking as noted above is that = intermediates can change the chunking and so using framing of your own = in the data where you know the size of each message at application layer = is only way to reliability do it. So can=E2=80=99t see any benefit of -1 = meaning give me whatever you have. In general this is where you would be better to have a proper ASYNC API. > Cheers, > nd >=20 > [1] https://tools.ietf.org/html/rfc7230#section-3.3.1 = <https://tools.ietf.org/html/rfc7230#section-3.3.1> > --=20 > If God intended people to be naked, they would be born that way. > -- Oscar Wilde > _______________________________________________ > Web-SIG mailing list > [email protected] <mailto:[email protected]> > Web SIG: http://www.python.org/sigs/web-sig = <http://www.python.org/sigs/web-sig> > Unsubscribe: = https://mail.python.org/mailman/options/web-sig/graham.dumpleton%40gmail.c= om = <https://mail.python.org/mailman/options/web-sig/graham.dumpleton%40gmail.= com> --Apple-Mail=_52DF0C1B-3EE4-4EA1-A688-A9EFC393628E Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8 <html><head><meta http-equiv=3D"Content-Type" content=3D"text/html = charset=3Dutf-8"></head><body style=3D"word-wrap: break-word; = -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" = class=3D""><br class=3D""><div><blockquote type=3D"cite" class=3D""><div = class=3D"">On 20 Jan 2016, at 10:25 PM, Andr=C3=A9 Malo <<a = href=3D"mailto:nd-qeD/[email protected]" class=3D"">nd-qeD/[email protected]</a>> = wrote:</div><br class=3D"Apple-interchange-newline"><div class=3D""><span = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px; float: none; display: inline = !important;" class=3D"">* Cory Benfield wrote:</span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><br style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""><blockquote type=3D"cite" style=3D"font-family: Helvetica; = font-size: 16px; font-style: normal; font-variant: normal; font-weight: = normal; letter-spacing: normal; orphans: auto; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; widows: = auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""><blockquote type=3D"cite" class=3D"">On 20 Jan 2016, at = 06:04, Graham Dumpleton <<a href=3D"mailto:[email protected]" = class=3D"">[email protected]</a>><br class=3D"">wrote:<br = class=3D""><br class=3D"">For response content, if a WSGI application = currently doesn=E2=80=99t set a<br class=3D"">Content-Length on = response, A HTTP/1.1 web server is at liberty to chunk<br class=3D"">the = response.<br class=3D""><br class=3D"">So I am not sure what is = missing.<br class=3D""></blockquote><br class=3D"">My specific concern = is the distinction between =E2=80=9Cat liberty to=E2=80=9D and<br = class=3D"">=E2=80=9Crequired to=E2=80=9D. Certain behaviours that make = sense with chunked transfer<br class=3D"">encoding do not make sense = without it: for example, streaming API endpoints<br class=3D"">that = return events as they arrive.</blockquote></div></blockquote><div><br = class=3D""></div><div>Bidirectional HTTP is effectively a no = go.</div><div><br class=3D""></div><div>CGI, SCGI and FASTCGI = implementations, mod_wsgi daemon mode and many HTTP proxies will often = not actually start reading a response until they have managed to send = the full content of the request. There are also various issues around = buffering, especially with intermediaries.</div><div><br = class=3D""></div><div>So if your expectation is that that you can send a = bit of a request, have client wait for a response for that bit, then = send more request, wait for more response for that part of the request = and so on, it isn=E2=80=99t going to work for most = implementations.</div><div><br class=3D""></div><div>This problem/issue = and the lack of support for both way streaming has been the subjects of = some RFCs. I can=E2=80=99t remember if this is the exact one I remember = seeing before, but does appear relevant:</div><div><br = class=3D""></div><div> <a = href=3D"https://www.ietf.org/rfc/rfc6202.txt" = class=3D"">https://www.ietf.org/rfc/rfc6202.txt</a></div><div><br = class=3D""></div><div>Anyway, the end result as I saw it was no one = could be bothered supporting proper bidirectional HTTP as getting = proxies/caches changed was going to be too hard.</div><div><br = class=3D""></div><div>The solution was to give up on it for HTTP/1.X and = instead do it in HTTP/2 as upgrading a HTTP connection to something else = generally had the effect of bypassing any intermediaries behaviour which = would cause issues as then it would switch to streaming properly in both = directions. So I think it is a lost cause to try and do it in HTTP/1.X = and WSGI.</div><br class=3D""><blockquote type=3D"cite" class=3D""><div = class=3D""><blockquote type=3D"cite" style=3D"font-family: Helvetica; = font-size: 16px; font-style: normal; font-variant: normal; font-weight: = normal; letter-spacing: normal; orphans: auto; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; widows: = auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D"">Sending this kind of response with a<br = class=3D"">HTTP/1.0-style content-length absent response (framed by = connection<br class=3D"">termination) is utterly confusing, especially = as some APIs consider the<br class=3D"">chunk framing to be semantic.<br = class=3D""></blockquote><br style=3D"font-family: Helvetica; font-size: = 16px; font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=3D""><span = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px; float: none; display: inline = !important;" class=3D"">Those APIs are just broken then. The HTTP RFCs = state very clearly [1], that<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">any hop may modify the = transfer encoding. In other words: the transfer<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">encoding is transparent to = the representation layer.</span><br style=3D"font-family: Helvetica; = font-size: 16px; font-style: normal; font-variant: normal; font-weight: = normal; letter-spacing: normal; orphans: auto; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; widows: = auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""></div></blockquote><div><br class=3D""></div><div>Yep. If = framing was required you could never rely on the HTTP chunking. Framing = had to be done in the actual data.</div><br class=3D""><blockquote = type=3D"cite" class=3D""><div class=3D""><blockquote type=3D"cite" = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D"">This can and does bite = people, because while all major production WSGI<br class=3D"">servers = use chunked transfer encoding in this situation, not all WSGI<br = class=3D"">implementations do: in fact, wsgiref does not. This means = that if an<br class=3D"">application has a production design requirement = to use chunked transfer<br class=3D"">encoding in its responses it = cannot rely on the server actually providing<br class=3D"">it.<br = class=3D""><br class=3D"">I see two solutions to this problem: we could = mandate that HTTP/1.1<br class=3D"">responses that have no content = length must be chunked, rather than falling<br class=3D"">back to = HTTP/1.0 style connection-termination-framed responses, or we could<br = class=3D"">have servers stuff something in the environ dictionary that = can be checked<br class=3D"">by applications. Or, I suppose, we can = conclude that this problem is not<br class=3D"">large enough, and that = it=E2=80=99s =E2=80=9Ccaveat developer=E2=80=9D.<br = class=3D""></blockquote><br style=3D"font-family: Helvetica; font-size: = 16px; font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=3D""><span = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px; float: none; display: inline = !important;" class=3D"">WSGI is a gateway working with the = representation layer. I think, it should<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">not concern itself with = underlying transport issues that much.</span><br style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""><br style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=3D""><span = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px; float: none; display: inline = !important;" class=3D"">Regarding chunked requests - in my own WSGI = implementation I went the most<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">pragmatic way and simply = provided a CONTENT_LENGTH of -1 for unknown request<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">sizes (it maps very well = to file.read(size)). Something like this would be my<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">suggestion for a future = WSGI spec.</span><br style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""></div></blockquote><div><br class=3D""></div><div>I am = assuming here you mean that -1 means return whatever you have available, = or block until you have something.</div><div><br = class=3D""></div><div>Problem with that is that some implementations = will use -1 as a default value to mean no argument supplied and so read = all input.</div><div><br class=3D""></div><div>So that could well = conflict with some implementations.</div><div><br = class=3D""></div><div>Also, if it is going to block, how is it really = different to reading with a block size. The whole think with chunking as = noted above is that intermediates can change the chunking and so using = framing of your own in the data where you know the size of each message = at application layer is only way to reliability do it. So can=E2=80=99t = see any benefit of -1 meaning give me whatever you have.</div><div><br = class=3D""></div><div>In general this is where you would be better to = have a proper ASYNC API.</div><br class=3D""><blockquote type=3D"cite" = class=3D""><div class=3D""><span style=3D"font-family: Helvetica; = font-size: 16px; font-style: normal; font-variant: normal; font-weight: = normal; letter-spacing: normal; orphans: auto; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; widows: = auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; = display: inline !important;" class=3D"">Cheers,</span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">nd</span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><br style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""><span style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = inline !important;" class=3D"">[1]<span = class=3D"Apple-converted-space"> </span></span><a = href=3D"https://tools.ietf.org/html/rfc7230#section-3.3.1" = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" = class=3D"">https://tools.ietf.org/html/rfc7230#section-3.3.1</a><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">--<span = class=3D"Apple-converted-space"> </span></span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">If God intended people to = be naked, they would be born that way.</span><br style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""><span style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = inline !important;" class=3D""> -- Oscar Wilde</span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" = class=3D"">_______________________________________________</span><br = style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px;" class=3D""><span style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: = none; display: inline !important;" class=3D"">Web-SIG mailing = list</span><br style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=3D""><a = href=3D"mailto:[email protected]" style=3D"font-family: Helvetica; = font-size: 16px; font-style: normal; font-variant: normal; font-weight: = normal; letter-spacing: normal; orphans: auto; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; widows: = auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D"">[email protected]</a><br style=3D"font-family: Helvetica; = font-size: 16px; font-style: normal; font-variant: normal; font-weight: = normal; letter-spacing: normal; orphans: auto; text-align: start; = text-indent: 0px; text-transform: none; white-space: normal; widows: = auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=3D""><span= style=3D"font-family: Helvetica; font-size: 16px; font-style: normal; = font-variant: normal; font-weight: normal; letter-spacing: normal; = orphans: auto; text-align: start; text-indent: 0px; text-transform: = none; white-space: normal; widows: auto; word-spacing: 0px; = -webkit-text-stroke-width: 0px; float: none; display: inline = !important;" class=3D"">Web SIG:<span = class=3D"Apple-converted-space"> </span></span><a = href=3D"http://www.python.org/sigs/web-sig" style=3D"font-family: = Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D"">http://www.python.org/sigs/web-sig</a><br style=3D"font-family:= Helvetica; font-size: 16px; font-style: normal; font-variant: normal; = font-weight: normal; letter-spacing: normal; orphans: auto; text-align: = start; text-indent: 0px; text-transform: none; white-space: normal; = widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D""><span style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: = inline !important;" class=3D"">Unsubscribe:<span = class=3D"Apple-converted-space"> </span></span><a = href=3D"https://mail.python.org/mailman/options/web-sig/graham.dumpleton%4= 0gmail.com" style=3D"font-family: Helvetica; font-size: 16px; = font-style: normal; font-variant: normal; font-weight: normal; = letter-spacing: normal; orphans: auto; text-align: start; text-indent: = 0px; text-transform: none; white-space: normal; widows: auto; = word-spacing: 0px; -webkit-text-stroke-width: 0px;" = class=3D"">https://mail.python.org/mailman/options/web-sig/graham.dumpleto= n%40gmail.com</a></div></blockquote></div><br class=3D""></body></html>= --Apple-Mail=_52DF0C1B-3EE4-4EA1-A688-A9EFC393628E-- --===============2377637489335467340== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Web-SIG mailing list [email protected] Web SIG: http://www.python.org/sigs/web-sig Unsubscribe: https://mail.python.org/mailman/options/web-sig/gcpw-web-sig%40m.gmane.org --===============2377637489335467340==--