[web-devel] Question about the composing order of conduit combination operations

Hiromi ISHII konn.jinro at gmail.com
Thu Apr 5 14:01:08 CEST 2012


Hi,

I'm implementing a tiny SMTP server using conduit-0.4.0 and network-conduit-0.4.0.

I wrote code like below:

> smtpServer src sink = do
>   LC.sourceList [ renderReply $ SMTPReply 220 (Just "localhost") ["hello"]] $$ sink
>   src $$ C.sequence (sinkParser smtpCommand)
>       =$ LC.map (BS.pack . show)
>       =$ sink

Here is the complete (and slightly different) code: https://github.com/konn/haskell-smtp/blob/master/smtp-server/Network/SMTP/Server.hs
(You know, this server is not actually an smtp server; just echoing client's input for now.)

I ran this program and communicated using telnet.
I expected the access log like below (S means server, C means client; new-lines are CRLF) :

> S: 220 localhost hello
> C: EHLO another.example.com
> S: EHLO "another.example.com"
> C: MAIL FROM:<Postmaster at example.com>
> S: MAIL (Path [] (Mailbox {mbLocalPart = "Postmaster", mbDomain = "example.com"})) []
> C: RCPT TO:<foo at example.com>
> S: RCPT (Path [] (Mailbox {mbLocalPart = "foo", mbDomain = "example.com"})) []
> C: DATA
> C: hoge
> C: fuga
> C: oooo
> C: .
> S: DATA "hoge\r\nfuga\r\noooo"
> C: QUIT
> S: QUIT

But I got: 

> S: 220 localhost hello
> C: EHLO another.example.com
> C: MAIL FROM:<Postmaster at example.com>
> C: RCPT TO:<foo at example.com>
> S: EHLO "another.example.com"
> C: DATA
> S: MAIL (Path [] (Mailbox {mbLocalPart = "Postmaster", mbDomain = "example.com"})) []
> C: hoge
> C: fuga
> C: oooo
> C: .
> C: QUIT
> S: RCPT (Path [] (Mailbox {mbLocalPart = "foo", mbDomain = "example.com"})) []

It seems that conduit produces a new SMTPCommand after reading another new command, and processes and convert it into SMTPReply much father later.

By the way, I rewrote the program above just like below and everythings seems to be good:

> smtpServer src sink = do
>   LC.sourceList [ renderReply $ SMTPReply 220 (Just "localhost") ["hello"]] $$ sink
>   src $= C.sequence (sinkParser smtpCommand)
>       $= LC.map (BS.pack . show)
>       $$ sink

If Conduits, Sinks and Sources are the same sings in conduit-0.4, why these two codes above behaves differently?
To summarize, my questions are divided into three:

1. Why the first one doesn't work as I expected?
2. Why the second one works well?
3. Is this difference intended? If so, what are the difference of semantics of ($=), (=$), ($$), (=$=) and their composition?

-- Hiromi ISHII
konn.jinro at gmail.com




More information about the web-devel mailing list