"Warrick Gray" <oinutter@hotmail.com> writes:
I've been tinkering with a client-side HTTP/1.1 implementation for Haskell. [..] In the interests of finding all bugs and giving something for nothing I've made the code available:
Thanks I think it is a nice library.
Significantly missing is any hint of SSL and request pipelining. Suggestions on improvements are welcome.
I tried HTTP.hs and Base64.hs a little and they seem to work well so far.
I think your http library would make a useful addition to the Haskell libraries, at least as a starting point for a standard HTTP library.
I've asked Warrick if he'd like to incorporate his HTTP client implementation into the hierarchical libraries, and maintain it. He's happy to do that. Does anyone have any objections or comments? The HTTP module itself can go in Network.Protocols.HTTP, and Browser maybe in Network.Protocols.HTTP.Browser. Base64 is a little more generic - perhaps FileFormat.Base64? Cheers, Simon
Simon Marlow wrote:
...
The HTTP module itself can go in Network.Protocols.HTTP, and Browser maybe in Network.Protocols.HTTP.Browser. Base64 is a little more generic - perhaps FileFormat.Base64?
How about FileFormat.Encoding.Base64? In the future, FileFormat.Encoding.QuotedPrintable FileFormat.Encoding.Gzipped FileFormat.Encoding.Yenc Text.Encoding.Rot13 Regards, Matt Harden
I think I found an issue with the HTTP.hs library when making a short-lived non-persistent connection to a server from a slower machine (i486). I can also reproduce it by running my program with strace or ltrace on a faster machine (PIII). My program just uses "simpleHTTP" to read a status page from my ADSL router modem. Here a code fragment: getStatus :: String -> String -> IO (Maybe (Status, Maybe PPPAddresses)) getStatus url auth = do resresp <- getStatusPage url auth case resresp of Left err -> print err >> return Nothing Right resp -> return $ Just $ extractStatus $ rspBody resp getStatusPage :: String -> String -> IO (Result Response) getStatusPage url auth = case parseURI url of Just uri -> do let defaultreq = Request uri GET [] "" authval = "Basic " ++ encode auth reqauth = insertHeader HdrAuthorization authval defaultreq simpleHTTP reqauth Nothing -> error $ "getStatusPage: Bad url: " ++ url Below is some ltrace output. I'm using ghc-5.02.3 on Linux. Jens __libc_start_main(0x080c8ff8, 1, 0xbffff794, 0x08049080, 0x080d9090 <unfinished ...> __register_frame_info(0x080e5240, 0x080e548c, 0xbffff738, 0x0804959e, 0x08049080) = 0x080e5240 sysconf(2, 0x4000b0a6, 0x080e5344, 0x08048cbd, 0x4200aef8) = 100 times(0xbffff6d0, 0x4213030c, 0xbffff6d8, 0x420b5fdc, 0x420b5cb4) = 0x05b63152 strrchr("./adslstatus", '/') = "/adslstatus" strcpy(0xbffff8ac, "adslstatus") = 0xbffff8ac getenv("GHCRTS") = NULL malloc(72) = 0x080e58d0 malloc(80) = 0x080e5920 malloc(160) = 0x080e5978 mmap(0x50000000, 0x00100000, 3, 34, -1) = 0x50000000 __gmp_set_memory_functions(0x080ccce0, 0x080ccd08, 0x080ccd48, 64, 0xbffff6d0) = 0x4006e018 sigemptyset(0xbffff654, 0x400134c0, 0x400136d0, 0x40046518, 0x080d7ab4) = 0 sigaction(26, 0xbffff650, 0, 0x40046518, 0x080d7ab4) = 0 gettimeofday(0xbffff6c0, 0, 0, 0, 0) = 0 setitimer(1, 0xbffff6d0, 0, 0, 0) = 0 malloc(8) = 0x080e5a20 sigemptyset(0x080e54c0, 0x080daf01, 0, 20000, 0xbffff794) = 0 sigemptyset(0xbffff654, 0x40046500, 5, 0x08048598, 0x40013870) = 0 sigaction(2, 0xbffff650, 0xbffff5c0, 0x08048598, 0x40013870) = 0 siginterrupt(2, 1, 0xbffff5c0, 0x08048598, 0) = 0 sigemptyset(0xbffff654, 1, 0xbffff5c0, 0x08048598, 0) = 0 sigaction(18, 0xbffff650, 0xbffff5c0, 0x08048598, 0) = 0 sigemptyset(0xbffff654, 0xbffff650, 0xbffff5c0, 0x08048598, 0) = 0 sigaction(8, 0xbffff650, 0xbffff5c0, 0x08048598, 0) = 0 times(0xbffff6c0, 0, 0, 0, 0) = 0x05b63152 malloc(16) = 0x080e5a30 malloc(256) = 0x080e5a48 re_set_syntax(45593, 0x080e56f0, 0x08070613, 0x080e071c, 0) = 0 re_compile_pattern(0x500bc448, 57, 0x500bc48c, 0x080e071c, 0) = 0 malloc(12) = 0x080e5b50 re_match(0x500bc48c, 0x500bc408, 53, 0, 0x080e5b50) = 53 free(0x080e5b60) = <void> free(0x080e5be0) = <void> free(0x080e5b50) = <void> socket(2, 1, 6) = 3 fcntl(3, 3, 6, 0x080df690, 0) = 2 fcntl(3, 4, 2050, 0x080df690, 0) = 0 setsockopt(3, 1, 9, 0x500bb008, 4) = 0 gethostbyname("192.168.1.1") = 0x42132dc0 connect(3, 0x500bb028, 16, 0x080df690, 1) = -1 __errno_location() = 0x42130b60 gettimeofday(0xbffff550, 0, 0, 0, 0) = 0 select(4, 0xbffff600, 0xbffff580, 0, 0xbffff578) = 1 getsockopt(3, 1, 4, 0x500bb040, 0x500bb04c) = 0 getsockopt(3, 1, 4, 0x500bb058, 0x500bb064) = 0 sendto(3, 0x500bb088, 143, 0, 0x500bb070) = 143 recvfrom(3, 0x500bb120, 1000, 0, 0x500bb510) = -1 gettimeofday(0xbffff550, 0, 0xbffff580, 0, 0xbffff578) = 0 select(4, 0xbffff600, 0xbffff580, 0, 0xbffff578) = 1 recvfrom(3, 0x500bb120, 1000, 0, 0x500bb510) = 1000 getpeername(3, 0x500bb534, 0x500bb54c, 0x080de970, 1) = 0 recvfrom(3, 0x500af008, 1000, 0, 0x500af3f8) = 1000 getpeername(3, 0x500af41c, 0x500af434, 0x080dfda0, 1) = 0 recvfrom(3, 0x500af440, 1000, 0, 0x500af830) = 1000 getpeername(3, 0x500af854, 0x500af86c, 0x080dfda0, 1) = 0 recvfrom(3, 0x500a3008, 1000, 0, 0x500a33f8) = 1000 getpeername(3, 0x500a341c, 0x500a3434, 0x080dfda0, 1) = 0 recvfrom(3, 0x500a3440, 1000, 0, 0x500a3830) = 1000 getpeername(3, 0x500a3854, 0x500a386c, 0x080dfda0, 1) = 0 recvfrom(3, 0x500a3878, 1000, 0, 0x500a3c68) = 555 getpeername(3, 0x500a3c8c, 0x500a3ca4, 0x080dfda0, 1) = 0 recvfrom(3, 0x500a2008, 1000, 0, 0x500a23f8) = 0 getpeername(3, 0x500a241c, 0x500a2434, 0x080dfda0, 1) = 0 shutdown(3, 1, 0x0805b85f, 0x080e018c, 1) = 0 recvfrom(3, 0x500a2440, 1000, 0, 0x500a2830) = 0 getpeername(3, 0x500a2854, 0x500a286c, 0x080e018c, 1) = -1 strerror(107) = "Transport endpoint is not connec"... getsockopt(3, 1, 4, 0x500a2878, 0x500a2884) = 0 isatty(1) = 1 fcntl(2, 3, 1215, 35387, 0x7f1c0300) = 32769 write(2, "\nFail: ", 7 Fail: ) = 7 write(2, "invalid argument\nAction: getPeer"..., 81invalid argument Action: getPeerName Reason: Transport endpoint is not connected ) = 81 write(2, "\n", 1 ) = 1 exit(1) = <void> __deregister_frame_info(0x080e5240, 0x4000b0a6, 0x4001386c, 0x40046538, 1) = 0 +++ exited (status 1) +++
participants (3)
-
Jens Petersen -
Matt Harden -
Simon Marlow