From 32ec7f2f5fb3e777fcb9730571c34633bfa5bcfb Mon Sep 17 00:00:00 2001 From: Luca Date: Fri, 26 Jun 2015 09:18:40 +0200 Subject: [PATCH 01/10] Allow AsyncFtpClient and ftpclient to check 220 messages As many ftp servers can answer with multiple 220 messages these two libraries have to handle multiline 220 messages before send user and pass messages. --- lib/pure/asyncftpclient.nim | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index daf69d59f5..c3545ada8c 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -79,7 +79,13 @@ proc connect*(ftp: AsyncFtpClient) {.async.} = # 120 Service ready in nnn minutes. # We wait until we receive 220. reply = await ftp.expectReply() - assertReply(reply, "220") + + # Handle 220 messages from the server + if reply.startsWith("220"): + assertReply(reply, "220") + while reply.continuesWith("-", 3): # handle multiline 220 message + assertReply(reply, "220") + reply = await ftp.expectReply() if ftp.user != "": assertReply(await(ftp.send("USER " & ftp.user)), "230", "331") From c687e2b9d2fefa362990f6f608c59c92a2575a3d Mon Sep 17 00:00:00 2001 From: Luca Date: Fri, 26 Jun 2015 09:24:58 +0200 Subject: [PATCH 02/10] Allow ftp client to handle 220 multiline messages --- lib/pure/ftpclient.nim | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index dd141eb017..7ede6b4795 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -263,8 +263,18 @@ proc connect*[T](ftp: FtpBase[T]) = else: {.fatal: "Incorrect socket instantiation".} - # TODO: Handle 120? or let user handle it. - assertReply ftp.expectReply(), "220" + var reply = ftp.expectReply() + if reply.startsWith("120"): + # 120 Service ready in nnn minutes. + # We wait until we receive 220. + reply = ftp.expectReply() + + # Handle 220 messages from the server + if reply.startsWith("220"): + assertReply(reply, "220") + while reply.continuesWith("-", 3): # handle multiline 220 message + assertReply(reply, "220") + reply = await ftp.expectReply() if ftp.user != "": assertReply(ftp.send("USER " & ftp.user), "230", "331") From 96e5c7c3b960fd617428cea3e64236dc8f430547 Mon Sep 17 00:00:00 2001 From: Luca Date: Fri, 26 Jun 2015 09:26:51 +0200 Subject: [PATCH 03/10] Fix remove async call --- lib/pure/ftpclient.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 7ede6b4795..522f42cf82 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -274,7 +274,7 @@ proc connect*[T](ftp: FtpBase[T]) = assertReply(reply, "220") while reply.continuesWith("-", 3): # handle multiline 220 message assertReply(reply, "220") - reply = await ftp.expectReply() + reply = ftp.expectReply() if ftp.user != "": assertReply(ftp.send("USER " & ftp.user), "230", "331") From 04f64fde855c83671fa0a36271253f66121cb2e6 Mon Sep 17 00:00:00 2001 From: Luca Date: Fri, 26 Jun 2015 09:35:35 +0200 Subject: [PATCH 04/10] Fix no async code --- lib/pure/ftpclient.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 522f42cf82..eaa8c82b2d 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -271,9 +271,9 @@ proc connect*[T](ftp: FtpBase[T]) = # Handle 220 messages from the server if reply.startsWith("220"): - assertReply(reply, "220") + assertReply ftp.expectReply(), "220" while reply.continuesWith("-", 3): # handle multiline 220 message - assertReply(reply, "220") + assertReply ftp.expectReply(), "220" reply = ftp.expectReply() if ftp.user != "": From 40a4a393740e3cf72dd37a243d5b72d7cde7f721 Mon Sep 17 00:00:00 2001 From: Luca Date: Sat, 27 Jun 2015 14:40:12 +0200 Subject: [PATCH 05/10] Remove redundant 220 check --- lib/pure/ftpclient.nim | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index eaa8c82b2d..301ca227a3 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -270,11 +270,10 @@ proc connect*[T](ftp: FtpBase[T]) = reply = ftp.expectReply() # Handle 220 messages from the server - if reply.startsWith("220"): + assertReply ftp.expectReply(), "220" + while reply.continuesWith("-", 3): # handle multiline 220 message assertReply ftp.expectReply(), "220" - while reply.continuesWith("-", 3): # handle multiline 220 message - assertReply ftp.expectReply(), "220" - reply = ftp.expectReply() + reply = ftp.expectReply() if ftp.user != "": assertReply(ftp.send("USER " & ftp.user), "230", "331") From 88ae4c18593c61ed1c67d074cee373226c41ab32 Mon Sep 17 00:00:00 2001 From: Luca Date: Sat, 27 Jun 2015 14:40:44 +0200 Subject: [PATCH 06/10] Remove redundant 220 check --- lib/pure/asyncftpclient.nim | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index c3545ada8c..979b0d6498 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -81,11 +81,10 @@ proc connect*(ftp: AsyncFtpClient) {.async.} = reply = await ftp.expectReply() # Handle 220 messages from the server - if reply.startsWith("220"): + assertReply(reply, "220") + while reply.continuesWith("-", 3): # handle multiline 220 message assertReply(reply, "220") - while reply.continuesWith("-", 3): # handle multiline 220 message - assertReply(reply, "220") - reply = await ftp.expectReply() + reply = await ftp.expectReply() if ftp.user != "": assertReply(await(ftp.send("USER " & ftp.user)), "230", "331") From 110d84a9167ad077bb8ca983c43c8febc5780cc6 Mon Sep 17 00:00:00 2001 From: Luca Date: Sat, 27 Jun 2015 17:06:11 +0200 Subject: [PATCH 07/10] remove unnecessary function --- lib/pure/asyncftpclient.nim | 2 +- lib/pure/ftpclient.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 979b0d6498..ff98d94c1d 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -82,7 +82,7 @@ proc connect*(ftp: AsyncFtpClient) {.async.} = # Handle 220 messages from the server assertReply(reply, "220") - while reply.continuesWith("-", 3): # handle multiline 220 message + while reply[3] == "-": # handle multiline 220 message assertReply(reply, "220") reply = await ftp.expectReply() diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 301ca227a3..2644fc0100 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -271,7 +271,7 @@ proc connect*[T](ftp: FtpBase[T]) = # Handle 220 messages from the server assertReply ftp.expectReply(), "220" - while reply.continuesWith("-", 3): # handle multiline 220 message + while reply[3] == "-": # handle multiline 220 message assertReply ftp.expectReply(), "220" reply = ftp.expectReply() From cb5d090cdb0318542804df7f122475b7de5410a6 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 1 Jul 2015 21:05:45 +0100 Subject: [PATCH 08/10] Moved handling of multi-line FTP replies to `expectReply`. --- lib/pure/asyncftpclient.nim | 19 ++++++++++++++----- lib/pure/ftpclient.nim | 19 ++++++++++++++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index ff98d94c1d..fe4577ed90 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -37,12 +37,24 @@ type proc (total, progress: BiggestInt, speed: float): Future[void] {.closure, gcsafe.} -proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] = - result = ftp.csock.recvLine() +const multiLineLimit = 10000 + +proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = + result = await ftp.csock.recvLine() + var count = 0 + while result[3] == '-': + ## Multi-line reply. + let line = await ftp.csock.recvLine() + result.add("\n" & line) + count.inc() + if count >= multiLineLimit: + raise newException(ReplyError, "Reached maximum multi-line reply count.") proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} = ## Send a message to the server, and wait for a primary reply. ## ``\c\L`` is added for you. + ## + ## **Note:** The server may return multiple lines of coded replies. await ftp.csock.send(m & "\c\L") return await ftp.expectReply() @@ -82,9 +94,6 @@ proc connect*(ftp: AsyncFtpClient) {.async.} = # Handle 220 messages from the server assertReply(reply, "220") - while reply[3] == "-": # handle multiline 220 message - assertReply(reply, "220") - reply = await ftp.expectReply() if ftp.user != "": assertReply(await(ftp.send("USER " & ftp.user)), "230", "331") diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 2644fc0100..778ba6857f 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -107,6 +107,8 @@ type EInvalidReply: ReplyError, EFTP: FTPError ].} +const multiLineLimit = 10000 + proc ftpClient*(address: string, port = Port(21), user, pass = ""): FtpClient = ## Create a ``FtpClient`` object. @@ -135,10 +137,24 @@ proc expectReply[T](ftp: FtpBase[T]): TaintedString = ftp.csock.readLine(result) else: discard ftp.csock.readLine(result) + var count = 0 + while result[3] == '-': + ## Multi-line reply. + var line = TaintedString"" + when T is Socket: + ftp.csock.readLine(line) + else: + discard ftp.csock.readLine(line) + result.add("\n" & line) + count.inc() + if count >= multiLineLimit: + raise newException(ReplyError, "Reached maximum multi-line reply count.") proc send*[T](ftp: FtpBase[T], m: string): TaintedString = ## Send a message to the server, and wait for a primary reply. ## ``\c\L`` is added for you. + ## + ## **Note:** The server may return multiple lines of coded replies. blockingOperation(ftp.csock): ftp.csock.send(m & "\c\L") return ftp.expectReply() @@ -271,9 +287,6 @@ proc connect*[T](ftp: FtpBase[T]) = # Handle 220 messages from the server assertReply ftp.expectReply(), "220" - while reply[3] == "-": # handle multiline 220 message - assertReply ftp.expectReply(), "220" - reply = ftp.expectReply() if ftp.user != "": assertReply(ftp.send("USER " & ftp.user), "230", "331") From 02402d3ffd1027d7f4de40a6cbb80cf1fba3e1c7 Mon Sep 17 00:00:00 2001 From: Bruce Doan Date: Thu, 2 Jul 2015 03:01:21 +0700 Subject: [PATCH 09/10] Implement async `post` request --- lib/pure/httpclient.nim | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 6a29137139..2ca2098b38 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -821,6 +821,24 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} = result = await client.request(redirectTo, httpGET) lastUrl = redirectTo +proc post*(client: AsyncHttpClient, url: string, body = "", multipart: MultipartData = nil): Future[Response] {.async.} = + ## Connects to the hostname specified by the URL and performs a POST request. + ## + ## This procedure will follow redirects up to a maximum number of redirects + ## specified in ``newAsyncHttpClient``. + let (mpHeader, mpBody) = format(multipart) + + template withNewLine(x): expr = + if x.len > 0 and not x.endsWith("\c\L"): + x & "\c\L" + else: + x + var xb = mpBody.withNewLine() & body + client.headers["Content-Type"] = mpHeader.split(": ")[1] + client.headers["Content-Length"] = $len(xb) + + result = await client.request(url, httpPOST, xb) + when not defined(testing) and isMainModule: when true: # Async From ce94d13406e63fc77a72dd286f32bc164e573a70 Mon Sep 17 00:00:00 2001 From: Kazunori Kajihiro Date: Thu, 2 Jul 2015 21:40:52 +0900 Subject: [PATCH 10/10] fixes readme.md typo --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 740296f4f2..277ceb8f30 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ To build from source you will need: If you are on a fairly modern *nix system, the following steps should work: ``` -$ git clone git://github.com/Araq/Nim.git +$ git clone git://github.com/nim-lang/Nim.git $ cd Nim $ git clone --depth 1 git://github.com/nim-lang/csources $ cd csources && sh build.sh