New release.

This commit is contained in:
Diego Nehab 2007-10-13 23:55:20 +00:00
parent 52ac60af81
commit d1a72435d5
9 changed files with 59 additions and 37 deletions

3
NEW
View File

@ -2,6 +2,9 @@ What's New
This is just a bug-fix/update release. This is just a bug-fix/update release.
* Improved: http.request() now supports deprecated HTTP/0.9
servers (Florian Berger)
* Fixed: could return "timedout" instead of "timeout" (Leo Leo)
* Fixed: crash when reading '*a' on closed socket (Paul Ducklin); * Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
* Fixed: return values are consistent when reading from closed sockets; * Fixed: return values are consistent when reading from closed sockets;
* Fixed: case sensitivity in headers of multipart messages in * Fixed: case sensitivity in headers of multipart messages in

3
TODO
View File

@ -1,7 +1,6 @@
replace \r\n with \0xD\0xA in everything
New mime support New mime support
ftp send should return server replies? ftp send should return server replies?
make sure there are no object files in the distribution tarball make sure there are no object files in the distribution tarball
http handling of 100-continue, see DB patch http handling of 100-continue, see DB patch

View File

@ -124,7 +124,7 @@ Special thanks go to
David Burgess, who has helped push the library to a new level of quality and David Burgess, who has helped push the library to a new level of quality and
from whom I have learned a lot of stuff that doesn't show up in RFCs. from whom I have learned a lot of stuff that doesn't show up in RFCs.
Special thanks also to Carlos Cassino, who played a big part in the Special thanks also to Carlos Cassino, who played a big part in the
extensible design seen in the C core of LuaSocket 2.0. Recently, Mike Pall extensible design seen in the C core of LuaSocket 2.0. Mike Pall
has been helping a lot too! Thanks to you all! has been helping a lot too! Thanks to you all!
</p> </p>
@ -137,6 +137,9 @@ has been helping a lot too! Thanks to you all!
</p> </p>
<ul> <ul>
<li> Improved: http.request() now supports deprecated
HTTP/0.9 servers (Florian Berger);
<li> Fixed: could return "timedout" instead of "timeout" (Leo Leo);
<li> Fixed: crash when reading '*a' on closed socket (Paul Ducklin); <li> Fixed: crash when reading '*a' on closed socket (Paul Ducklin);
<li> Fixed: return values are consistent when reading from closed sockets; <li> Fixed: return values are consistent when reading from closed sockets;
<li> Fixed: case sensitivity in headers of multipart <li> Fixed: case sensitivity in headers of multipart
@ -195,7 +198,7 @@ still available for those that have compatibility issues.
<p> <p>
<small> <small>
Last modified by Diego Nehab on <br> Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:23 EDT 2006 Wed Oct 3 02:07:59 BRT 2007
</small> </small>
</p> </p>
</center> </center>

View File

@ -284,7 +284,8 @@ closed. No end-of-line translation is performed;
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is <li> '<tt>*l</tt>': reads a line of text from the socket. The line is
terminated by a LF character (ASCII&nbsp;10), optionally preceded by a terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
CR character (ASCII&nbsp;13). The CR and LF characters are not included in CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. This is the default pattern; the returned line. In fact, <em>all</em> CR characters are
ignored by the pattern. This is the default pattern;
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt> <li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket. of bytes from the socket.
</ul> </ul>

View File

@ -1,2 +0,0 @@
Talk a bout Wim
Move thanks into the acknowledgement section.

View File

@ -61,7 +61,7 @@ sinks, and pumps, which we introduce below.
\emph{Filters} are functions that can be repeatedly invoked \emph{Filters} are functions that can be repeatedly invoked
with chunks of input, successively returning processed with chunks of input, successively returning processed
chunks of output. More importantly, the result of chunks of output. Naturally, the result of
concatenating all the output chunks must be the same as the concatenating all the output chunks must be the same as the
result of applying the filter to the concatenation of all result of applying the filter to the concatenation of all
input chunks. In fancier language, filters \emph{commute} input chunks. In fancier language, filters \emph{commute}
@ -81,11 +81,12 @@ which data will flow, potentially being transformed many
times along the way. Chains connect these nodes together. times along the way. Chains connect these nodes together.
The initial and final nodes of the network are The initial and final nodes of the network are
\emph{sources} and \emph{sinks}, respectively. Less \emph{sources} and \emph{sinks}, respectively. Less
abstractly, a source is a function that produces new data abstractly, a source is a function that produces new chunks
every time it is invoked. Conversely, sinks are functions of data every time it is invoked. Conversely, sinks are
that give a final destination to the data they receive. functions that give a final destination to the chunks of
Naturally, sources and sinks can also be chained with data they receive in sucessive calls. Naturally, sources
filters to produce filtered sources and sinks. and sinks can also be chained with filters to produce
filtered sources and sinks.
Finally, filters, chains, sources, and sinks are all passive Finally, filters, chains, sources, and sinks are all passive
entities: they must be repeatedly invoked in order for entities: they must be repeatedly invoked in order for
@ -95,8 +96,8 @@ sink, and indirectly through all intervening filters.
In the following sections, we start with a simplified In the following sections, we start with a simplified
interface, which we later refine. The evolution we present interface, which we later refine. The evolution we present
is not contrived: it recreates the steps we followed is not contrived: it recreates the steps we ourselves
ourselves as we consolidated our understanding of these followed as we consolidated our understanding of these
concepts within our application domain. concepts within our application domain.
\subsection{A simple example} \subsection{A simple example}
@ -290,8 +291,8 @@ static int eol(lua_State *L) {
\end{C} \end{C}
\end{quote} \end{quote}
When designing your own filters, the challenging part is to When designing filters, the challenging part is usually
decide what will be in the context. For line breaking, for deciding what to store in the context. For line breaking, for
instance, it could be the number of bytes that still fit in the instance, it could be the number of bytes that still fit in the
current line. For Base64 encoding, it could be a string current line. For Base64 encoding, it could be a string
with the bytes that remain after the division of the input with the bytes that remain after the division of the input
@ -408,8 +409,8 @@ associated filter before returning it to the caller.
Filtered sources are useful when working with Filtered sources are useful when working with
functions that get their input data from a source (such as functions that get their input data from a source (such as
the pumps in our examples). By chaining a source with one or the pumps in our examples). By chaining a source with one or
more filters, the function can be transparently provided more filters, such functions can be transparently provided
with filtered data, with no need to change its interface. with filtered data, with no need to change their interfaces.
Here is a factory that does the job: Here is a factory that does the job:
\begin{quote} \begin{quote}
\begin{lua} \begin{lua}
@ -434,11 +435,11 @@ end
\subsection{Sinks} \subsection{Sinks}
Just as we defined an interface for source of data, Just as we defined an interface for a source of data, we can
we can also define an interface for a data destination. also define an interface for a data destination. We call
We call any function respecting this any function respecting this interface a sink. In our first
interface a \emph{sink}. In our first example, we used a example, we used a file sink connected to the standard
file sink connected to the standard output. output.
Sinks receive consecutive chunks of data, until the end of Sinks receive consecutive chunks of data, until the end of
data is signaled by a \nil\ input chunk. A sink can be data is signaled by a \nil\ input chunk. A sink can be
@ -665,7 +666,7 @@ SMTP dot-stuffing filter, connects a socket sink
with the server, and simply pumps the data. The message is never with the server, and simply pumps the data. The message is never
assembled in memory. Everything is produced on demand, assembled in memory. Everything is produced on demand,
transformed in small pieces, and sent to the server in chunks, transformed in small pieces, and sent to the server in chunks,
including the file attachment that is loaded from disk and including the file attachment which is loaded from disk and
encoded on the fly. It just works. encoded on the fly. It just works.
\section{Conclusions} \section{Conclusions}
@ -685,11 +686,10 @@ components. Pumps simply push the data through.
The concepts described in this text are the result of long The concepts described in this text are the result of long
discussions with David Burgess. A version of this text has discussions with David Burgess. A version of this text has
been released on-line as the Lua Technical Note 012, hence been released on-line as the Lua Technical Note 012, hence
the name of the corresponding LuaSocket module, the name of the corresponding LuaSocket module, LTN12. Wim
\texttt{ltn12}. Wim Couwenberg contributed to the Couwenberg contributed to the implementation of the module,
implementation of the module, and Adrian Sietsma was the and Adrian Sietsma was the first to notice the
first to notice the correspondence between sources and Lua correspondence between sources and Lua iterators.
iterators.
\end{document} \end{document}

View File

@ -86,7 +86,7 @@ MAKE = \
DOC = \ DOC = \
doc/dns.html \ doc/dns.html \
doc/ftp.html \ doc/ftp.html \
doc/home.html \ doc/index.html \
doc/http.html \ doc/http.html \
doc/installation.html \ doc/installation.html \
doc/introduction.html \ doc/introduction.html \

View File

@ -142,7 +142,12 @@ function metat.__index:sendbody(headers, source, step)
end end
function metat.__index:receivestatusline() function metat.__index:receivestatusline()
local status = self.try(self.c:receive()) local status = self.try(self.c:receive(5))
-- identify HTTP/0.9 responses, which do not contain a status line
-- this is just a heuristic, but is what the RFC recommends
if status ~= "HTTP/" then return nil, status end
-- otherwise proceed reading a status line
status = self.try(self.c:receive("*l", status))
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
return self.try(base.tonumber(code), status) return self.try(base.tonumber(code), status)
end end
@ -163,6 +168,12 @@ function metat.__index:receivebody(headers, sink, step)
sink, step)) sink, step))
end end
function metat.__index:receive09body(status, sink, step)
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
source(status)
return self.try(ltn12.pump.all(source, sink, step))
end
function metat.__index:close() function metat.__index:close()
return self.c:close() return self.c:close()
end end
@ -271,6 +282,7 @@ function tredirect(reqt, location)
create = reqt.create create = reqt.create
} }
-- pass location header back as a hint we redirected -- pass location header back as a hint we redirected
headers = headers or {}
headers.location = headers.location or location headers.location = headers.location or location
return result, code, headers, status return result, code, headers, status
end end
@ -283,17 +295,23 @@ function trequest(reqt)
-- send request line and headers -- send request line and headers
h:sendrequestline(nreqt.method, nreqt.uri) h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers) h:sendheaders(nreqt.headers)
local code = 100 -- if there is a body, send it
local headers, status
-- if there is a body, check for server status
if nreqt.source then if nreqt.source then
h:sendbody(nreqt.headers, nreqt.source, nreqt.step) h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
end end
local code, status = h:receivestatusline()
-- if it is an HTTP/0.9 server, simply get the body and we are done
if not code then
h:receive09body(status, nreqt.sink, nreqt.step)
return 1, 200
end
local headers
-- ignore any 100-continue messages -- ignore any 100-continue messages
while code == 100 do while code == 100 do
code, status = h:receivestatusline()
headers = h:receiveheaders() headers = h:receiveheaders()
code, status = h:receivestatusline()
end end
headers = h:receiveheaders()
-- at this point we should have a honest reply from the server -- at this point we should have a honest reply from the server
-- we can't redirect if we already used the source, so we report the error -- we can't redirect if we already used the source, so we report the error
if shouldredirect(nreqt, code, headers) and not nreqt.source then if shouldredirect(nreqt, code, headers) and not nreqt.source then

View File

@ -359,7 +359,7 @@ const char *socket_strerror(int err) {
case ECONNREFUSED: return "connection refused"; case ECONNREFUSED: return "connection refused";
case ECONNABORTED: return "closed"; case ECONNABORTED: return "closed";
case ECONNRESET: return "closed"; case ECONNRESET: return "closed";
case ETIMEDOUT: return "timedout"; case ETIMEDOUT: return "timeout";
default: return strerror(errno); default: return strerror(errno);
} }
} }