I have ported a consoleApp to a Docker container with the mcr.microsoft.com/dotnet/sdk:6.0. Now I noticed that the code inside the container behaves differently. Outside the container, an exception is generated when the connection is lost but Not inside the container! What can be the reason?
Many thanks for your help.
public static async Task FtpUploadAsync(string hostname, string username, string password, string[] uploadfiles)
{
try
{
var token = new CancellationToken();
using (AsyncFtpClient client = new AsyncFtpClient())
{
client.Host = hostname;
client.Port = 21;
client.Credentials.UserName = username;
client.Credentials.Password = password;
client.Config.EncryptionMode = FtpEncryptionMode.None;
client.Config.InternetProtocolVersions = FtpIpVersion.IPv4;
client.Config.ValidateAnyCertificate = true;
client.Config.ConnectTimeout = 15000;
await client.AutoConnect(token);
Console.WriteLine("Connectetd!");
foreach (var varFilePath in uploadfiles)
{
Console.WriteLine("Uploading File: " + varFilePath.GetFtpFileName());
await client.UploadFile(varFilePath, "/" + varFilePath.GetFtpFileName(), FtpRemoteExists.Overwrite, true, token: token);
File.Delete(varFilePath);
WriteLogFile.WriteLog("File Uploaded", varFilePath.GetFtpFileName());
}
}
}
catch (Exception ex)
{
WriteLogFile.WriteLog("catch", "Ftp-Uploader " + ex);
Console.WriteLine("Ftp-Uploader " + ex);
}
}
Hello, how do I include the code to write a debug log! Unfortunately I can't get it! Sorry....
using FluentFTP; // from NuGet package FluentFTP
using FluentFTP.Logging; // from NuGet package FluentFTP.Logging
var builder = WebApplication.CreateBuilder(args);
var logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File("logs/Net6Tester.txt", rollingInterval:
RollingInterval.Day)
.CreateLogger();
client.Logger = new FtpLogAdapter(logger);
here are the logs! when i run the coed on a windows system then it disposes after a disconnection.
If I run it in the container, then it immediately wants to continue with the next file in the array!!
Log -- Windows System
######################
# AutoConnect()
# AutoDetect(True, False)
# Connect(False)
Status: FluentFTP 44.0.1.0
Status: Connecting to IP #1= ***:21
Status: Waiting for a response
Response: 220 Xlight FTP Server 3.9 ready... [738548,429d]
Status: Detected FTP server: XLight
Command: AUTH TLS
Status: Waiting for response to: AUTH TLS
Response: 431 No security resource for TLS/SSL encryption,
probably there is no selected SSL certificate [370ms]
Command: USER ***
Status: Waiting for response to: USER ***
Response: 331 Password required for *** [394ms]
Command: PASS ***
Status: Waiting for response to: PASS ***
Response: 230 Login OK [297ms]
Command: FEAT
Status: Waiting for response to: FEAT
Response: 211-Features supported
Response: REST STREAM
Response: EPRT
Response: EPSV
Response: SIZE
Response: MDTM
Response: MFMT
Response: AUTH
Response: PBSZ
Response: PROT
Response: MLST type*;size*;modify*;
Response: MLSD
Response: 211 End [72ms]
Status: Text encoding:
System.Text.UTF8Encoding+UTF8EncodingSealed
Command: OPTS UTF8 ON
Status: Waiting for response to: OPTS UTF8 ON
Response: 502 This function is disabled [35ms]
Command: SYST
Status: Waiting for response to: SYST
Response: 215 UNIX Type: L8 [18ms]
Status: Listing parser set to: Machine
Command: PWD
Status: Waiting for response to: PWD
Response: 257 "/" [6ms]
Connectetd!
Uploading File: test-big.opus
[11:18:28 INF] Uploading file test-big.opus
# UploadFile("C:\temp\ftpUpload\test-big.opus", "/test-big.opus",
Overwrite, True, None)
# FileExists("/test-big.opus")
Command: SIZE /test-big.opus
Status: Waiting for response to: SIZE /test-big.opus
Response: 550 Can't find file "test-big.opus". [70ms]
# DirectoryExists("/")
# OpenWrite("/test-big.opus", Binary)
Command: TYPE I
Status: Waiting for response to: TYPE I
Response: 200 Type set to I. [23ms]
# OpenDataStreamAsync("STOR /test-big.opus", 0)
# OpenPassiveDataStreamAsync(PASV, "STOR /test-big.opus", 0)
Command: PASV
Status: Waiting for response to: PASV
Response: 227 Entering Passive Mode (192,168,178,30,195,196)
[14ms]
Status: Connecting to IP #1= ***:50116
Command: STOR /test-big.opus
Status: Waiting for response to: STOR /test-big.opus
Response: 150 Opening BINARY mode data connection for test-
big.opus. [8ms]
Status: Closing/Disposing FtpSocketStream(data connection)
Status: Attempting upload resume at position 1048576
# OpenAppend("/test-big.opus", Binary)
# GetFileSize("/test-big.opus", -1)
Command: SIZE /test-big.opus
Status: Waiting for response to: SIZE /test-big.opus
Status: Closing/Disposing FtpSocketStream(data connection)
# Dispose()
Status: Disposing FtpClient object...
Status: Closing/Disposing FtpSocketStream(control connection)
Status: Closing/Disposing FtpSocketStream(control connection)
###############################################################
Log-File Docker Container
#########################
# AutoConnect()
# AutoDetect(True, False)
# Connect(False)
Status: FluentFTP 44.0.1.0
Status: Connecting to IP #1= ***:21
Status: Waiting for a response
Response: 220 Xlight FTP Server 3.9 ready... [738548.43d]
Status: Detected FTP server: XLight
Command: AUTH TLS
Status: Waiting for response to: AUTH TLS
Response: 431 No security resource for TLS/SSL encryption,
probably there is no selected SSL certificate [390ms]
Command: USER ***
Status: Waiting for response to: USER ***
Response: 331 Password required for *** [398ms]
Command: PASS ***
Status: Waiting for response to: PASS ***
Response: 230 Login OK [299ms]
Command: FEAT
Response: 211-Features supported
Response: REST STREAM
Response: EPRT
Response: EPSV
Response: SIZE
Response: MDTM
Response: MFMT
Response: AUTH
Response: PBSZ
Response: PROT
Response: MLST type*;size*;modify*;
Response: MLSD
Response: 211 End [73ms]
Status: Text encoding:
System.Text.UTF8Encoding+UTF8EncodingSealed
Command: OPTS UTF8 ON
Status: Waiting for response to: OPTS UTF8 ON
Response: 502 This function is disabled [16ms]
Command: SYST
Status: Waiting for response to: SYST
Response: 215 UNIX Type: L8 [17ms]
Status: Listing parser set to: Machine
Command: PWD
Status: Waiting for response to: PWD
Response: 257 "/" [6ms]
Connectetd!
Uploading File: test-big.opus
[10:18:36 INF] Uploading file test-big.opus
# UploadFile("/var/lib/ftp-uploader/input/test-big.opus",
"/test-
big.opus", Overwrite, True, None)
# FileExists("/test-big.opus")
Command: SIZE /test-big.opus
Status: Waiting for response to: SIZE /test-big.opus
Response: 213 926600 [58ms]
# DeleteFile("/test-big.opus")
Command: DELE /test-big.opus
Status: Waiting for response to: DELE /test-big.opus
Response: 250 Deleted file "test-big.opus". [35ms]
# OpenWrite("/test-big.opus", Binary)
Command: TYPE I
Status: Waiting for response to: TYPE I
Response: 200 Type set to I. [14ms]
# OpenDataStreamAsync("STOR /test-big.opus", 0)
# OpenPassiveDataStreamAsync(PASV, "STOR /test-big.opus", 0)
Command: PASV
Status: Waiting for response to: PASV
Response: 227 Entering Passive Mode (192,168,178,30,195,206)
[11ms]
Status: Connecting to IP #1= ***:50126
Command: STOR /test-big.opus
Status: Waiting for response to: STOR /test-big.opus
Response: 150 Opening BINARY mode data connection for test-
big.opus. [1ms]
Status: Closing/Disposing FtpSocketStream(data connection)
Status: IOException for file /var/lib/ftp-
uploader/input/test-big.opus : Unable to write data to the
transport connection: Broken pipe.
Status: Failed to upload file.
Uploading File: test-small.opus
[10:18:45 INF] Uploading file test-small.opus
# UploadFile("/var/lib/ftp-uploader/input/test-small.opus",
"/test-small.opus", Overwrite, True, None)
# FileExists("/test-small.opus")
Command: SIZE /test-small.opus
Status: Waiting for response to: SIZE /test-small.opus
To configure logging from FTP client you can use the following:
According to FluentFTP Logging page you can setup logging via Serilog. Add the following NuGet packages:
Serilog
Serilog.Extensions.Logging
Serilog.Sinks.File
(optionally, to log to console also) Serilog.Sinks.Console
On the start of program configure logging:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.File("logs/Net6Tester.txt", rollingInterval: RollingInterval.Day,
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
Then when you create AsyncFtpClient configure it to log to Serilog:
using (AsyncFtpClient client = new AsyncFtpClient())
{
var logger = LoggerFactory.Create(builder => builder.AddSerilog())
.CreateLogger<UploadClient>();
client.Logger = new FtpLogAdapter(logger);
You can also log yourself with something like this:
Log.Logger.Information("Uploading file {0}", varFilePath.GetFtpFileName());
Please first make sure it's logging as expected on your host machine. Then try to get the logs from Docker container.
Related
I try to upload files and wrote the following code with the help of FluentFTP:
clientFluentFTP = new FtpClient(hostname,
username,
password);
clientFluentFTP.LoadProfile(new FtpProfile
{
Host = hostname,
Credentials = new NetworkCredential(username, password),
Encryption = FtpEncryptionMode.Explicit,
Protocols = SslProtocols.Tls12,
DataConnection = FtpDataConnectionType.PASV,
Encoding = Encoding.UTF8,
}) ;
clientFluentFTP.ValidateAnyCertificate = true;
clientFluentFTP.Connect();
clientFluentFTP.UploadFile(localfile, requestname, FtpRemoteExists.Overwrite,false,FtpVerify.Throw);
I test with my first file (UTF8 encoded) and the result is a zero byte file.
No exception is thrown so I assume it is able to verify the transfer. Apparently the transfer is not closed off correctly. And yes, with commandline FTP clients I can transfer the file without problems. No message, no error. Just a zero byte file.
What do I do wrong?
The Log from the code is below.
# Connect()
Status: Connecting to 46.235.40.106:21
Response: 220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
Response: 220-You are user number 3 of 50 allowed.
Response: 220-Local time is now 11:54. Server port: 21.
Response: 220-This is a private system - No anonymous login
Response: 220-IPv6 connections are also welcome on this server.
Response: 220 You will be disconnected after 15 minutes of inactivity.
Status: Detected FTP server: PureFTPd
Command: AUTH TLS
Response: 234 AUTH TLS OK.
Status: FTPS Authentication Successful
Status: Time to activate encryption: 0h 0m 0s. Total Seconds: 0,1315097.
Command: USER ***
Response: 331 User ftp_meteo_wagenborgen.nl OK. Password required
Command: PASS ***
Response: 230-Your bandwidth usage is restricted
Response: 230 OK. Current restricted directory is /
Command: PBSZ 0
Response: 200 PBSZ=0
Command: PROT P
Response: 200 Data protection level set to "private"
Command: FEAT
Response: 211-Extensions supported:
Response: EPRT
Response: IDLE
Response: MDTM
Response: SIZE
Response: MFMT
Response: REST STREAM
Response: MLST type*;size*;sizd*;modify*;UNIX.mode*;UNIX.uid*;UNIX.gid*;unique*;
Response: MLSD
Response: AUTH TLS
Response: PBSZ
Response: PROT
Response: UTF8
Response: ESTA
Response: PASV
Response: EPSV
Response: SPSV
Response: ESTP
Response: 211 End.
Status: Text encoding: System.Text.UTF8Encoding
Command: OPTS UTF8 ON
Response: 200 OK, UTF-8 enabled
Command: SYST
Response: 215 UNIX Type: L8
# UploadFile("utils/systeminfoTable.txt", "/web/systeminfoTable.txt", Overwrite, False, Throw)
# FileExists("/web/systeminfoTable.txt")
Command: SIZE /web/systeminfoTable.txt
Response: 213 1467
# DeleteFile("/web/systeminfoTable.txt")
Command: DELE /web/systeminfoTable.txt
Response: 250 Deleted /web/systeminfoTable.txt
# OpenWrite("/web/systeminfoTable.txt", Binary)
Command: TYPE I
Response: 200 TYPE is now 8-bit binary
# OpenPassiveDataStream(PASV, "STOR /web/systeminfoTable.txt", 0)
Command: PASV
Response: 227 Entering Passive Mode (46,235,40,106,168,24)
Status: Connecting to 46.235.40.106:43032
Command: STOR /web/systeminfoTable.txt
Response: 150 Accepted data connection
Status: FTPS Authentication Successful
Status: Time to activate encryption: 0h 0m 0s. Total Seconds: 0,1381567.
Status: Disposing FtpSocketStream...
Status: File Verification: PASS
# Dispose()
Status: Disposing FtpClient object...
Command: QUIT
Status: Disposing FtpSocketStream...
Status: Disposing FtpSocketStream...
Ah... The default setting is binary and should be ascii.
So I added:
clientFluentFTP.UploadDataType = FtpDataType.ASCII;
Problem solved.See my comment under the problem description
It had nothing to do with coding.
I changed provider because of a configuration issue and the problem was gone.
I am using a .net console application written in C# to download certain files from an ftp server routinely, it used to work properly until there was a file with Hebrew characters, named something like that:
1234--אבג.jpeg
so I've tried to download the same file using both chrome and FileZilla - and encountered no problems, with neither plain nor URL encoded version of the filename.
My problem is how to download the same file with my C# application
I have tried:
to escape the name as URL-encoded, worked for chrome but not my APP
to convert the string to utf-8
both System.Net.WebRequest and HttpClient
finding and taking the name from response of directory listing and pasting into the request, hoping it will have the proper format.
here is my code :
public static string attachmentToFile(string name, string filename)
{
try
{
string ftpConnection = ConfigurationManager.AppSettings["FtpServer"].ToString();
string ftpUser = ConfigurationManager.AppSettings["FtpUser"].ToString();
string ftpPassword = ConfigurationManager.AppSettings["FtpPassword"].ToString();
string attachmentPath = ConfigurationManager.AppSettings["attachmentFolder"].ToString();
Directory.CreateDirectory(attachmentPath);
attachmentPath += '\\' + name + Path.GetExtension(filename);
FtpWebRequest attachmentRequest = (FtpWebRequest)WebRequest.Create(
new Uri(ftpConnection + "/files_directory/" + filename)
);
attachmentRequest.Credentials = new NetworkCredential(ftpUser, ftpPassword);
attachmentRequest.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse)attachmentRequest.GetResponse();
var stream = response.GetResponseStream();
FileStream saveStream = new FileStream(attachmentPath, FileMode.OpenOrCreate);
//stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(saveStream);
saveStream.Close();
return attachmentPath;
}
catch (Exception ex)
{
Logger.LogError(MethodBase.GetCurrentMethod(), ex, "failed downloading file from server: " + filename);
return null;
}
}
the error is
The remote server returned an error: (550) File unavailable (e.g., file not found, no access).
while in Filezilla it's successful
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 0
Status: Connecting to 11.111.111.11:1111...
Status: Connection established, waiting for welcome message...
Trace: CFtpControlSocket::OnReceive()
Response: 220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
Response: 220-You are user number 3 of 50 allowed. Response: 220-Local time is now 09:16. Server port: 1111.
Response: 220-This is a private system - No anonymous login Response: 220 You will be disconnected after 15 minutes of inactivity.
Trace: CFtpLogonOpData::ParseResponse() in state 1
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 2
Command: AUTH TLS
Trace: CFtpControlSocket::OnReceive()
Response: 234 AUTH TLS OK.
Trace: CFtpLogonOpData::ParseResponse() in state 2
Status: Initializing TLS...
Trace: tls_layer_impl::client_handshake()
Trace: tls_layer_impl::continue_handshake()
Trace: tls_layer_impl::continue_handshake()
Trace: tls_layer_impl::continue_handshake()
Trace: tls_layer_impl::continue_handshake()
Trace: tls_layer_impl::continue_handshake()
Trace: TLS Handshake successful
Trace: Protocol: TLS1.2, Key exchange: ECDHE-RSA, Cipher: AES-256-GCM, MAC: AEAD
Trace: tls_layer_impl::verify_certificate()
Status: Verifying certificate...
Trace: CFtpControlSocket::SetAsyncRequestReply
Status: TLS connection established.
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 6
Command: USER files#domain.co.il
Trace: CFtpControlSocket::OnReceive()
Trace: CFtpControlSocket::OnReceive()
Response: 331 User files#domain.co.il OK. Password required
Trace: CFtpLogonOpData::ParseResponse() in state 6
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 6
Command: PASS ****************
Trace: CFtpControlSocket::OnReceive()
Response: 230 OK. Current restricted directory is /
Trace: CFtpLogonOpData::ParseResponse() in state 6
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 10
Command: OPTS UTF8 ON
Trace: CFtpControlSocket::OnReceive()
Response: 504 Unknown command
Trace: CFtpLogonOpData::ParseResponse() in state 10
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 11
Command: PBSZ 0
Trace: CFtpControlSocket::OnReceive()
Response: 200 PBSZ=0
Trace: CFtpLogonOpData::ParseResponse() in state 11
Trace: CControlSocket::SendNextCommand()
Trace: CFtpLogonOpData::Send() in state 12
Command: PROT P
Trace: CFtpControlSocket::OnReceive()
Response: 200 Data protection level set to "private"
Trace: CFtpLogonOpData::ParseResponse() in state 12
Status: Logged in
Trace: Measured latency of 16 ms
Trace: CFtpControlSocket::ResetOperation(0)
Trace: CControlSocket::ResetOperation(0)
Trace: CFtpLogonOpData::Reset(0) in state 15
Trace: CFtpControlSocket::FileTransfer()
Trace: CControlSocket::SendNextCommand()
Trace: CFtpFileTransferOpData::Send() in state 0
Status: Starting download of /files_directory/1234--אבג.jpeg
Trace: CFtpChangeDirOpData::Send() in state 0
Trace: CFtpChangeDirOpData::Send() in state 2
Command: CWD /files_directory
Trace: CFtpControlSocket::OnReceive()
Response: 250 OK. Current directory is /files_directory
Trace: CFtpChangeDirOpData::ParseResponse() in state 2
Trace: CFtpControlSocket::ResetOperation(0)
Trace: CControlSocket::ResetOperation(0)
Trace: CFtpChangeDirOpData::Reset(0) in state 2
Trace: CFtpFileTransferOpData::SubcommandResult(0) in state 1
Trace: CFtpControlSocket::SetAsyncRequestReply
Trace: CControlSocket::SendNextCommand()
Trace: CFtpFileTransferOpData::Send() in state 5
Trace: CFtpRawTransferOpData::Send() in state 1
Command: TYPE I
Trace: CFtpControlSocket::OnReceive()
Response: 200 TYPE is now 8-bit binary
Trace: CFtpRawTransferOpData::ParseResponse() in state 1
Trace: CControlSocket::SendNextCommand()
Trace: CFtpRawTransferOpData::Send() in state 2
Command: PASV
Trace: CFtpControlSocket::OnReceive()
Response: 227 Entering Passive Mode (11,111,111,11,111,11)
Trace: CFtpRawTransferOpData::ParseResponse() in state 2
Trace: CControlSocket::SendNextCommand()
Trace: CFtpRawTransferOpData::Send() in state 4
Trace: Binding data connection source IP to control connection source IP 10.0.0.13
Trace: tls_layer_impl::client_handshake()
Trace: Trying to resume existing TLS session.
Command: RETR 1234--אבג.jpeg
Trace: tls_layer_impl::continue_handshake()
Trace: CFtpControlSocket::OnReceive()
Response: 150-Accepted data connection
Response: 150 206.6 kbytes to download
Trace: CFtpRawTransferOpData::ParseResponse() in state 4
Trace: CControlSocket::SendNextCommand()
Trace: CFtpRawTransferOpData::Send() in state 5
Trace: tls_layer_impl::continue_handshake()
Trace: TLS Handshake successful
Trace: TLS Session resumed
Trace: Protocol: TLS1.2, Key exchange: ECDHE-RSA, Cipher: AES-256-GCM, MAC: AEAD
Trace: tls_layer_impl::verify_certificate()
Trace: CTransferSocket::OnConnect
Trace: CFtpControlSocket::OnReceive()
Response: 226-File successfully transferred
Trace: CFtpControlSocket::OnReceive()
Response: 226 0.120 seconds (measured here), 1.68 Mbytes per second
Trace: CFtpRawTransferOpData::ParseResponse() in state 5
Trace: CControlSocket::SendNextCommand()
Trace: CFtpRawTransferOpData::Send() in state 8
Trace: CTransferSocket::TransferEnd(1)
Trace: tls_layer_impl::shutdown()
Trace: tls_layer_impl::continue_shutdown()
Trace: CFtpControlSocket::TransferEnd()
Trace: CFtpControlSocket::ResetOperation(0)
Trace: CControlSocket::ResetOperation(0)
Trace: CFtpRawTransferOpData::Reset(0) in state 8
Trace: CFtpFileTransferOpData::SubcommandResult(0) in state 7
Trace: CFtpControlSocket::ResetOperation(0)
Trace: CControlSocket::ResetOperation(0)
Trace: CFtpFileTransferOpData::Reset(0) in state 7
Status: File transfer successful, transferred 211,556 bytes in 1 second
Status: Disconnected from server
network.log
System.Net Information: 0 : [14564] FtpWebRequest#54024015::.ctor(ftp://files%40domain.co.il#11.111.111.11:1111/files_directory/22222222-IMG-222222-222222.jpg)
System.Net Information: 0 : [14564] FtpWebRequest#54024015::GetResponse(Method=RETR.)
System.Net Information: 0 : [14564] Current OS installation type is 'Client'.
System.Net Information: 0 : [14564] RAS supported: True
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Created connection from 10.0.0.13:11111 to 11.111.111.11:1111.
System.Net Information: 0 : [14564] Associating FtpWebRequest#54024015 with FtpControlStream#13869071
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 3 of 50 allowed.
220-Local time is now 09:44. Server port: 1111.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.]
....
150 119.1 kbytes to download]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [226-File successfully transferred
226 0.052 seconds (measured here), 2.24 Mbytes per second]
....
150 4312.7 kbytes to download]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [226-File successfully transferred
226 1.874 seconds (measured here), 2.25 Mbytes per second]
....
150 1974.2 kbytes to download]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [226-File successfully transferred
226 0.884 seconds (measured here), 2.18 Mbytes per second]
System.Net Information: 0 : [14564] FtpWebRequest#49652976::(Releasing FTP connection#13869071.)
System.Net Information: 0 : [14564] FtpWebRequest#44223604::.ctor(ftp://files%40domain.co.il#11.111.111.11:1111/files_directory/11111111-1111111111.jpg)
System.Net Information: 0 : [14564] FtpWebRequest#44223604::GetResponse(Method=RETR.)
System.Net Information: 0 : [14564] Associating FtpWebRequest#44223604 with FtpControlStream#13869071
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Sending command [PASV]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [227 Entering Passive Mode (11,111,111,11,111,111)]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Sending command [RETR files_directory/11111111-1111111111.jpg]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [150-Accepted data connection
150 1953.3 kbytes to download]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [226-File successfully transferred
226 0.929 seconds (measured here), 2.05 Mbytes per second]
System.Net Information: 0 : [14564] FtpWebRequest#44223604::(Releasing FTP connection#13869071.)
System.Net Information: 0 : [14564] FtpWebRequest#62468121::.ctor(ftp://files%40domain.co.il#11.111.111.11:1111/files_directory/1234--אבג.jpeg)
System.Net Information: 0 : [14564] FtpWebRequest#62468121::GetResponse(Method=RETR.)
System.Net Information: 0 : [14564] Associating FtpWebRequest#62468121 with FtpControlStream#13869071
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Sending command [PASV]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [227 Entering Passive Mode (11,111,111,11,111,111)]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Sending command [RETR files_directory/1234--אבג.jpeg]
System.Net Information: 0 : [14564] FtpControlStream#13869071 - Received response [550 Can't open files_directory/1234--אבג.jpeg: No such file or directory]
System.Net Information: 0 : [14564] FtpWebRequest#62468121::(Releasing FTP connection#13869071.)
System.Net Error: 0 : [14564] Exception in FtpWebRequest#62468121::GetResponse - The remote server returned an error: (550) File unavailable (e.g., file not found, no access)..
at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
at System.Net.FtpWebRequest.RequestCallback(Object obj)
at System.Net.CommandStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
at System.Net.FtpWebRequest.GetResponse()
although I didn't find the exact reason for the error, after printing FileZilla verbose log and FtpWebRequest as suggested in the comments and reading some more I have read that it's hard to change certain configurations using System.Net.WebRequest and HttpClient, so I used a 3d party library (FluentFTP) there were many configurations available but I didn't need to do anything in my case and the problem was solved by the default configurations.
I am experimenting with the REST API for sending batch messages in Firebase Cloud Messaging. I prepared a multipart HTTP request in C#:
using var request = new HttpRequestMessage(HttpMethod.Post, "https://fcm.googleapis.com/batch");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "xxx");
request.Content = new StringContent(multicast);
request.Content.Headers.Remove("Content-Type");
request.Content.Headers.TryAddWithoutValidation("Content-Type", "multipart/mixed; boundary=--subrequest_boundary");
var response = await FcmHttpClient.SendAsync(request);
The string value of the multicast field above is an HTTP content similar the one provided in the Firebase documentation:
--subrequest_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
Authorization: Bearer xxx
POST /v1/projects/myproject/messages:send
Content-Type: application/json
accept: application/json
{
"message":{
"topic":"global",
"notification":{
"title":"FCM Message",
"body":"This is an FCM notification message to device 0!"
}
}
}
--subrequest_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
Authorization: Bearer xxx
POST /v1/projects/myproject/messages:send
Content-Type: application/json
accept: application/json
{
"message":{
"topic":"readers-club",
"notification":{
"title":"Price drop",
"body":"2% off all books"
}
}
}
--subrequest_boundary--
Firebase server returns Bad Request-400 with error message: "Failed to parse batch request, error: 0 items. Received batch body: --subrequest_boundary--" which indicates that Firebase directly handles the content with the terminating --subrequest_boundary--.
What could be the cause of the problem?
yesterday, i need write bash script to send bath FCM notifaction, and see your code #Ugur, thanks.
now its working, u need change
Content-Type", "multipart/mixed; boundary=--subrequest_boundary
to
Content-Type", "multipart/mixed; boundary=subrequest_boundary
the script
#!/bin/bash
curl \
-X POST \
-H "Authorization: Bearer [token_auth]" \
-H "Content-Type: multipart/mixed; boundary=subrequest_boundary" \
--data-binary #test2.txt \
https://fcm.googleapis.com/batch
and test2.txt, example send 2 notification
--subrequest_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
Authorization: Bearer [token_auth]
POST /v1/projects/[project_name_firebase]/messages:send
Content-Type: application/json
accept: application/json
{
"message":{
"token":"[token_device]",
"notification":{
"title":"FCM Message",
"body":"This is an FCM notification message to device 0!",
}
}
}
--subrequest_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
Authorization: Bearer [token_auth]
POST /v1/projects/[project_name_firebase]/messages:send
Content-Type: application/json
accept: application/json
{
"message":{
"token":"[token_device]",
"notification":{
"title":"FCM Message",
"body":"This is an FCM notification message to device 0!",
}
}
}
--subrequest_boundary--
change [project_name_firebase] with name your project in firebase
console example : project_3323.
change [token_device] with token target device.
change [token_auth] with your google auth credentials token.
Notification configuration: https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#AndroidConfig
to get [token_auth]
java :
https://developers.google.com/identity/protocols/oauth2/service-account#java_1
phyton:
https://developers.google.com/identity/protocols/oauth2/service-account#python_2
curl:
https://developers.google.com/identity/protocols/oauth2/service-account#httprest
code for get [token_auth], getToken.sh
#!/bin/bash
client_email="[email_project_firebase]"
service="https://oauth2.googleapis.com/token"
time=3600
scope="https://www.googleapis.com/auth/cloud-platform"
private_key=$(echo -ne "[private_key]")
datenow="$(date +%s)"
expired="$(( datenow + time ))";
header='{"alg": "RS256","typ": "JWT"}'
payload='{"iss": "'$client_email'","scope": "'$scope'","aud": "'$service'","exp": '$expired',"iat": '$datenow'}'
HEADEREnc=$( echo -n "${header}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
PAYLOADEnc=$( echo -n "${payload}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
data="${HEADEREnc}"."${PAYLOADEnc}"
signature=$( openssl dgst -sha256 -sign <(echo -n "${private_key}") <(echo -n "${data}") | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
JWT="${data}"."${signature}"
jsonDataToken=$(curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion='$JWT https://oauth2.googleapis.com/token)
tokenAuth=$(echo -n $jsonDataToken |grep -Po '"access_token":.*?[^\\]"'|cut -d ':' -f2 |sed 's/"//g')
echo $tokenAuth
[email_project_firebase],[private_key] u can get it from file json in "firebase console" -> project name -> project setting or click gear icon -> account services -> click button "create new secret key"
list scope for other service
https://developers.google.com/identity/protocols/oauth2/scopes
Try to change your code
request.Content.Headers.TryAddWithoutValidation("Content-Type", "multipart/mixed; boundary=--subrequest_boundary");
to
request.Content.Headers.TryAddWithoutValidation("Content-Type", "multipart/mixed; boundary=subrequest_boundary");
The devil's in the details of building the Content. You can't simply create a string matching that payload, because certain pieces of it, like the headers and boundaries, are not technically considered part of the body by the HttpClient stack.
If you really need to do this with a raw HttpClient, take a look at how the Google APIs .NET client builds and sends a batch request. But I suspect that once you realize how cumbersome this is, you're going to conclude that you're best off using a higher-level SDK, such as firebase-admin-dotnet, which is mentioned in the same documentation you linked to and utilizes Google's .NET client under the hood.
EDIT: GitHub path to example project is here: https://oobi.visualstudio.com/_git/HttpHost
please excuse my noobish-ness with SSL and secure streams. I've done research to try and get past it on my own, but haven't seen a case like this.
I'm trying to create a portable HTTPS server module (Called HttpHost, because it will also support HTTP once the hard stuff is out of the way) for use in other programs I may have in mind down the road, but for the life of me I cannot get the server to accept connections even though the clients show no issues shaking hands.
My code is rather simple to initialize and start it:
X509Certificate2 inputCert = new X509Certificate2("C:\\matt\\Matthew.pfx"); //self signed cert
HttpHost host = new HttpHost(inputCert);
host.StartSecureListen();
HttpHost when initialized does this:
public HttpHost(X509Certificate cert, int HTTPSport = DEFAULT_HTTPS_PORT) {
// variable validation and some other unrelated junk here...
this._listener = new TcpListener(_localIP, _port);
}
The HttpHost class creates a new thread with a ParameterizedThreadStart for each incoming request, and processes them through this void:
private void ProcessSecureRequest(object arg) {
TcpClient client = arg as TcpClient;
string outputHTTPstatus = HttpStatusCode.OK.ToString();
string outputMimeType = "text/xml";
Console.WriteLine("InboundConnection: Client(" + client.Client.RemoteEndPoint.AddressFamily.ToString() + ")");
Console.WriteLine("DATA: " + ReadMessageFromSecureClient(client));
client.Close();
}
This is where things get interesting
I have a void responsible for taking the TCP client, and reading the data being sent:
private string ReadMessageFromSecureClient(TcpClient client) {
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
SslStream sslStream = new SslStream(client.GetStream(), false);
sslStream.AuthenticateAsServer(_serverCert, false, SslProtocols.Tls, false); // <--- ERROR HERE
byte[] byteBuff = new byte[];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do {
bytes = sslStream.Read(byteBuff , 0, byteBuff.Length);
Decoder dec = Encoding.UTF8.GetDecoder();
char[] chars = new char[dec .GetCharCount(byteBuff, 0, bytes) - 1 + 1];
dec .GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
}
while (bytes != 0);
return messageData.ToString();
}
When navigating to 'https://localhost' from a browser (Edge Dev based off of Chromium) while the program is debugging, an exception is always thrown when attmepting to AuthenticateAsServer. The debugger says:
System.Security.Authentication.AuthenticationException: 'A call to SSPI failed, see inner exception.'
Inner: Win32Exception: An unknown error occurred while processing the certificate
And when using Insomnia (REST/HTTP API Tester) and sending a blank GET request to the server, I get this error:
System.Security.Authentication.AuthenticationException: 'A call to SSPI failed, see inner exception.'
Inner: Win32Exception: The certificate chain was issued by an authority that is not trusted
I've already installed this certificate into the 'Trusted Root Certification Authorities' folder of the local machine.
But, when using OpenSSL to verify the SSL handshake between the client and server (run on a different machine than the debugger), it completes with no errors:
openssl s_client -connect 192.168.0.100:443 -tls1_2
CONNECTED(0000011C)
───
no peer certificate available
───
No client certificate CA names sent
───
SSL handshake has read 1399 bytes and written 201 bytes
Verification: OK
───
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1583735493
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
───
I created this certificate with the powershell "New-SelfSignedCertificate", and I can't seem to find a way to successfully authenticate a SSL connection. I'm sorry this is so long, I wanted to be as detailed as possible.
So here is how I solved this.
Everytime you refer to System.Net.Security.SslStream make sure SslProtocol is forced to System.Security.Authentication.Tls12 not just Tls nor Tls11
A simple fix that did it for me.
My js client was getting, as you stated above :
WebSocket connection to 'wss://localhost' failed: Error in connection establishment: net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH
My C# service was getting:
System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The function requested is not supported
sslStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired: false,
enabledSslProtocols:
System.Security.Authentication.SslProtocols.Tls |
System.Security.Authentication.SslProtocols.Tls11 |
System.Security.Authentication.SslProtocols.Tls12 |
System.Security.Authentication.SslProtocols.Ssl3
, checkCertificateRevocation: true);
I have made a small test application(WinForms C#) to test FTP upload. This works perfectly.
I try to use the exact same method in a Windows Service I'm currently working on, but there I get '(426) Connection closed; transfer aborted.'-message.
I have made sure several times that the parameters to the method are exactly the same. They are! Next thought was the account my service is running under, but I've tried all possibilities, even running the service as 'User', supplying my own credentials. Then it should act like the WinForms app, right? No, it doesn't!
It's running fine until the line using (var requestStream = request.GetRequestStream()) which is the point of failure.
The FTP-server in question only allows active connections, so request.UsePassive is set to false.
Anyone got a clue?
public void UploadToFtp(string url, string filePath, string username, string password, bool mode)
{
var fileName = Path.GetFileName(filePath);
var request = (FtpWebRequest)WebRequest.Create(url + fileName);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = !mode;
request.UseBinary = true;
request.KeepAlive = false;
using (var fileStream = File.OpenRead(filePath))
{
using (var requestStream = request.GetRequestStream())
{
fileStream.CopyTo(requestStream);
requestStream.Close();
}
}
var response = (FtpWebResponse)request.GetResponse();
response.Close();
}
Adding trace logs of both scenarios:
Using a Windows application:
WebRequest::Create(ftp://someurl/somefile.txt)
FtpWebRequest#63289421::.ctor(ftp://someurl/somefile.txt)
Exiting WebRequest::Create() -> FtpWebRequest#63289421
Current OS installation type is 'Client'.
RAS supported: True
ServicePoint#14173886::ServicePoint(someurl:21)
FtpWebRequest#63289421::GetRequestStream()
FtpWebRequest#63289421::GetRequestStream(Method=STOR.)
FtpControlStream#22525719 - Created connection from 10.10.10.103:1865 to nnn.nnn.nnn.nnn:21.
Associating FtpWebRequest#63289421 with FtpControlStream#22525719
FtpControlStream#22525719 - Received response [xxxx
someurl>PROD server
Port21>Use active mode>
xxxx]
Sending command [USER myusername]
Received response [331 Enter password]
Sending command [PASS ********]
Received response [230-User logged in
Hi,I'am datagear PROD.
230 User logged in]
Sending command [OPTS utf8 on]
Received response [200 Command OPTS succeed]
Sending command [PWD]
Received response [257 "/CitData" is current directory]
Sending command [TYPE I]
Received response [200 Transfer mode set to BINARY]
Sending command [PORT 10,10,10,103,7,74]
Received response [200 Command PORT succeed]
Sending command [STOR somefile.txt]
Received response [150 Uploading in BINARY file somefile.txt]
Exiting FtpWebRequest#63289421::GetRequestStream()
Received response [226 Transfer completed]
Sending command [QUIT]
Received response [221-bye
Bye-Bye,see you again.
Using a Windows Service:
WebRequest::Create(ftp://someurl/somefile.txt)
FtpWebRequest#63289421::.ctor(ftp://someurl/somefile.txt)
Exiting WebRequest::Create() -> FtpWebRequest#25425822
Current OS installation type is 'Client'.
ServicePoint#31665793::ServicePoint(someurl:21)
FtpWebRequest#25425822::GetRequestStream()
FtpWebRequest#25425822::GetRequestStream(Method=STOR.)
FtpControlStream#51484875 - Created connection from 10.10.10.103:1759 to nnn.nnn.nnn.nnn:21.
Associating FtpWebRequest#25425822 with FtpControlStream#51484875
FtpControlStream#51484875 - Received response [xxxx
someurl>PROD server
Port21>Use active mode>
xxxx]
Sending command [USER myusername]
Received response [331 Enter password]
Sending command [PASS ********]
Received response [230-User logged in
Hi,I'am datagear PROD.
230 User logged in]
Sending command [OPTS utf8 on]
Received response [200 Command OPTS succeed]
Sending command [PWD]
Received response [257 "/CitData" is current directory]
Sending command [TYPE I]
Received response [200 Transfer mode set to BINARY]
Sending command [PORT 10,10,10,103,6,224]
Received response [200 Command PORT succeed]
Sending command [STOR somefile.txt]
Received response [426 Transfer failed]
(Releasing FTP connection#51484875.)
GetRequestStream - The remote server returned an error: (426) Connection closed; transfer aborted..
at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
at System.Net.CommandStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
at System.Net.FtpWebRequest.GetRequestStream()
Exiting FtpWebRequest#25425822::GetRequestStream()
The one that works has a line saying 'RAS Supported'. Maybe interesting, don't know.
The Windows Firewall caused the problem. When running from a WinService I had to open the firewall for this service. When running from VS environment it seems that the firewall is already open for VS (although the list of pass-through applications in WinFirewall don't show it) and therefore all seems to run well.