Strange HTTP module behavior

Hello, I am trying to send a simple SOAP message to an Apache server. I got the HTTP library from the XML-RPC library and thought this would make an easy client. However, I'm having two problems. First, even though I am sending an accurate Content-Length header with my POST message, the server is timing out and returning a 500 Internal Server Error document. Second, after reading that error document, Network.HTTP is generating an error of its own. Here's an strace illustrating it: recvfrom(3, "ssResponse> \n", 1000, 0, NULL, N ULL) = 47 recvfrom(3, "", 1000, 0, NULL, NULL) = 0 shutdown(3, 1 /* send */) = 0 shutdown(3, 0 /* receive */) = 0 close(3) = 0 ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0 fcntl(2, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE|0x800 0) write(2, "\nFail: ", 7) = 7 write(2, "Network.Socket.recv: end of file (end of file)\n", 47) = 47 write(2, "\n", 1) = 1 I *think* that what's happening is that ghc threw an exception for the empty recvfrom response, then the exception handler closed the conection, and then the exception was prnited to stderr. Oh, tcpdump verified that both client and server are sending Connection: close headers. Any ideas? -- John

On 2005-02-18, John Goerzen
First, even though I am sending an accurate Content-Length header with my POST message, the server is timing out and returning a 500 Internal Server Error document.
Looks like that was a server bug.
Second, after reading that error document, Network.HTTP is generating an error of its own. Here's an strace illustrating it:
This one was a bug in HTTP. Actually, I am stunned that nobody found it before, because it looks to me that it would cause an exception to be raised on every single HTTP hit. It turns out that Network.Socket.recv raises an EOF error when it gets back 0 bytes of data. HTTP is expecting it to return an empty list for some reason. The below patch fixed it for me. --- orig/http/Network/HTTP.hs +++ mod/http/Network/HTTP.hs @@ -147,6 +147,7 @@ import Text.ParserCombinators.ReadP import Text.Read.Lex import System.IO +import qualified System.IO.Error import Foreign.C.Error @@ -651,7 +652,7 @@ instance Stream Socket where readBlock sk n = (liftM Right $ fn n) `Exception.catch` (handleSocketError sk) where - fn x = do { str <- recv sk x + fn x = do { str <- myrecv sk x ; let len = length str ; if len < x then ( fn (x-len) >>= \more -> return (str++more) ) @@ -665,7 +666,7 @@ readLine sk = (liftM Right $ fn "") `Exception.catch` (handleSocketError sk) where fn str = - do { c <- recv sk 1 -- like eating through a straw. + do { c <- myrecv sk 1 -- like eating through a straw. ; if null c || c == "\n" then return (reverse str++c) else fn (head c:str) @@ -706,7 +707,7 @@ ConnClosed -> return (Left ErrorClosed) (MkConn sk addr bfr _) | null bfr -> {- read in buffer -} - do { str <- recv sk 1000 -- DON'T use "readBlock sk 1000" !! + do { str <- myrecv sk 1000 -- DON'T use "readBlock sk 1000" !! -- ... since that call will loop. ; let len = length str ; if len == 0 {- indicates a closed connection -} @@ -1274,3 +1275,7 @@ urlEncodeVars [] = [] +myrecv :: Socket -> Int -> IO String +myrecv sock len = + let handler e = if isEOFError e then return [] else ioError e + in System.IO.catch (recv sock len) handler \ No newline at end of file

John Goerzen wrote:
It turns out that Network.Socket.recv raises an EOF error when it gets back 0 bytes of data.
As it should... recv(2) returns zero bytes precisely when it reaches EOF; this is the standard sockets-API EOF indicator. See any sockets tutorial.
HTTP is expecting it to return an empty list for some reason.
That is odd; HTTP must be broken. --KW 8-)

HI Guys, i'm trying to use parsec to do some data creation for me. was reading the online user documentation and all seems well. however, i can't dig how i can use the result of the parsing. any ideas/resources you can point out would be of very big help. just in case you're interested. i'm trying to implement a YAML parser. that is: 1) read a YAML file containing data (say a list of names) 2) parse the YAML file (this is where parsec comes in) 3) come out with a list (int haskell) after parsing the YAML source. kind regards, eyan -- http://www.eyan.org Object-oriented programming offers a sustainable way to write spaghetti code.

On Mon, 21 Feb 2005, Edwin Eyan Moragas wrote:
however, i can't dig how i can use the result of the parsing.
There's a group of functions runParser, parse, parseFromFile and parseTest all of which 'run' Parsec parsers on input given by one of their parameters and return the result of parsing. -- flippa@flippac.org Performance anxiety leads to premature optimisation

On Mon, 21 Feb 2005 14:36:34 +0000 (GMT Standard Time), Philippa
Cowderoy
On Mon, 21 Feb 2005, Edwin Eyan Moragas wrote:
however, i can't dig how i can use the result of the parsing.
There's a group of functions runParser, parse, parseFromFile and parseTest all of which 'run' Parsec parsers on input given by one of their parameters and return the result of parsing.
thanks for this. will get back you when i've got some running code. -- http://www.eyan.org Object-oriented programming offers a sustainable way to write spaghetti code.

There's a very simple example of using Parsec, complete with some test cases, here: http://www.ninebynine.org/Software/HaskellUtils/RegexParser.hs #g -- At 22:07 21/02/05 +0800, Edwin Eyan Moragas wrote:
HI Guys,
i'm trying to use parsec to do some data creation for me. was reading the online user documentation and all seems well.
however, i can't dig how i can use the result of the parsing.
any ideas/resources you can point out would be of very big help.
just in case you're interested. i'm trying to implement a YAML parser. that is: 1) read a YAML file containing data (say a list of names) 2) parse the YAML file (this is where parsec comes in) 3) come out with a list (int haskell) after parsing the YAML source.
kind regards, eyan
Object-oriented programming offers a sustainable way to write spaghetti code. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

On Mon, Feb 21, 2005 at 10:43:33AM +0000, Keith Wansbrough wrote:
John Goerzen wrote:
It turns out that Network.Socket.recv raises an EOF error when it gets back 0 bytes of data.
As it should... recv(2) returns zero bytes precisely when it reaches EOF; this is the standard sockets-API EOF indicator. See any sockets tutorial.
Of course. That's why I'm saying the exception is unexpected. recv() doesn't return -1 (indicating an error); it just returns an empty list. For what seems like a direct binding to a low-level call, this action is surprising. If it were documented in the fptools haddock docs, it probably wouldn't surprise me. But as someone that is used to the C API, that behavior is surprising.
HTTP is expecting it to return an empty list for some reason.
That is odd; HTTP must be broken.
participants (5)
-
Edwin Eyan Moragas
-
Graham Klyne
-
John Goerzen
-
Keith Wansbrough
-
Philippa Cowderoy