diff --git a/NEW b/NEW index cffa73c..0191ccd 100644 --- a/NEW +++ b/NEW @@ -2,6 +2,9 @@ What's New 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: return values are consistent when reading from closed sockets; * Fixed: case sensitivity in headers of multipart messages in diff --git a/TODO b/TODO index 07814a5..a07ebe4 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ +replace \r\n with \0xD\0xA in everything New mime support - - ftp send should return server replies? make sure there are no object files in the distribution tarball http handling of 100-continue, see DB patch diff --git a/doc/index.html b/doc/index.html index 1605af1..57a7907 100644 --- a/doc/index.html +++ b/doc/index.html @@ -124,7 +124,7 @@ Special thanks go to 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. 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!

@@ -137,6 +137,9 @@ has been helping a lot too! Thanks to you all!

diff --git a/gem/TODO b/gem/TODO deleted file mode 100644 index bdbe84e..0000000 --- a/gem/TODO +++ /dev/null @@ -1,2 +0,0 @@ -Talk a bout Wim -Move thanks into the acknowledgement section. diff --git a/gem/ltn012.tex b/gem/ltn012.tex index 8eccd46..8027ecc 100644 --- a/gem/ltn012.tex +++ b/gem/ltn012.tex @@ -61,7 +61,7 @@ sinks, and pumps, which we introduce below. \emph{Filters} are functions that can be repeatedly invoked 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 result of applying the filter to the concatenation of all 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. The initial and final nodes of the network are \emph{sources} and \emph{sinks}, respectively. Less -abstractly, a source is a function that produces new data -every time it is invoked. Conversely, sinks are functions -that give a final destination to the data they receive. -Naturally, sources and sinks can also be chained with -filters to produce filtered sources and sinks. +abstractly, a source is a function that produces new chunks +of data every time it is invoked. Conversely, sinks are +functions that give a final destination to the chunks of +data they receive in sucessive calls. Naturally, sources +and sinks can also be chained with filters to produce +filtered sources and sinks. Finally, filters, chains, sources, and sinks are all passive 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 interface, which we later refine. The evolution we present -is not contrived: it recreates the steps we followed -ourselves as we consolidated our understanding of these +is not contrived: it recreates the steps we ourselves +followed as we consolidated our understanding of these concepts within our application domain. \subsection{A simple example} @@ -290,8 +291,8 @@ static int eol(lua_State *L) { \end{C} \end{quote} -When designing your own filters, the challenging part is to -decide what will be in the context. For line breaking, for +When designing filters, the challenging part is usually +deciding what to store in the context. For line breaking, for instance, it could be the number of bytes that still fit in the current line. For Base64 encoding, it could be a string 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 functions that get their input data from a source (such as the pumps in our examples). By chaining a source with one or -more filters, the function can be transparently provided -with filtered data, with no need to change its interface. +more filters, such functions can be transparently provided +with filtered data, with no need to change their interfaces. Here is a factory that does the job: \begin{quote} \begin{lua} @@ -434,11 +435,11 @@ end \subsection{Sinks} -Just as we defined an interface for source of data, -we can also define an interface for a data destination. -We call any function respecting this -interface a \emph{sink}. In our first example, we used a -file sink connected to the standard output. +Just as we defined an interface for a source of data, we can +also define an interface for a data destination. We call +any function respecting this interface a sink. In our first +example, we used a file sink connected to the standard +output. Sinks receive consecutive chunks of data, until the end of 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 assembled in memory. Everything is produced on demand, 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. \section{Conclusions} @@ -685,11 +686,10 @@ components. Pumps simply push the data through. The concepts described in this text are the result of long discussions with David Burgess. A version of this text has been released on-line as the Lua Technical Note 012, hence -the name of the corresponding LuaSocket module, -\texttt{ltn12}. Wim Couwenberg contributed to the -implementation of the module, and Adrian Sietsma was the -first to notice the correspondence between sources and Lua -iterators. +the name of the corresponding LuaSocket module, LTN12. Wim +Couwenberg contributed to the implementation of the module, +and Adrian Sietsma was the first to notice the +correspondence between sources and Lua iterators. \end{document} diff --git a/makefile.dist b/makefile.dist index 58ae5b3..876cf18 100644 --- a/makefile.dist +++ b/makefile.dist @@ -86,7 +86,7 @@ MAKE = \ DOC = \ doc/dns.html \ doc/ftp.html \ - doc/home.html \ + doc/index.html \ doc/http.html \ doc/installation.html \ doc/introduction.html \ diff --git a/src/http.lua b/src/http.lua index 9d739a4..3a386a6 100644 --- a/src/http.lua +++ b/src/http.lua @@ -142,7 +142,12 @@ function metat.__index:sendbody(headers, source, step) end 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)")) return self.try(base.tonumber(code), status) end @@ -163,6 +168,12 @@ function metat.__index:receivebody(headers, sink, step) sink, step)) 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() return self.c:close() end @@ -271,6 +282,7 @@ function tredirect(reqt, location) create = reqt.create } -- pass location header back as a hint we redirected + headers = headers or {} headers.location = headers.location or location return result, code, headers, status end @@ -283,17 +295,23 @@ function trequest(reqt) -- send request line and headers h:sendrequestline(nreqt.method, nreqt.uri) h:sendheaders(nreqt.headers) - local code = 100 - local headers, status - -- if there is a body, check for server status + -- if there is a body, send it if nreqt.source then h:sendbody(nreqt.headers, nreqt.source, nreqt.step) 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 while code == 100 do - code, status = h:receivestatusline() headers = h:receiveheaders() + code, status = h:receivestatusline() end + headers = h:receiveheaders() -- 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 if shouldredirect(nreqt, code, headers) and not nreqt.source then diff --git a/src/usocket.c b/src/usocket.c index ef275b4..2c30b9a 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -359,7 +359,7 @@ const char *socket_strerror(int err) { case ECONNREFUSED: return "connection refused"; case ECONNABORTED: return "closed"; case ECONNRESET: return "closed"; - case ETIMEDOUT: return "timedout"; + case ETIMEDOUT: return "timeout"; default: return strerror(errno); } }