/// <summary> /// <para>Creates an array of commands, that will be sent to the server</para> /// </summary> protected override PipelineEntry[] BuildCommandsList(WebRequest req) { bool resetLoggedInState = false; FtpWebRequest request = (FtpWebRequest)req; if (NetEventSource.IsEnabled) { NetEventSource.Info(this); } _responseUri = request.RequestUri; ArrayList commandList = new ArrayList(); if (request.EnableSsl && !UsingSecureStream) { commandList.Add(new PipelineEntry(FormatFtpCommand("AUTH", "TLS"))); // According to RFC we need to re-authorize with USER/PASS after we re-authenticate. resetLoggedInState = true; } if (resetLoggedInState) { _loginDirectory = null; _establishedServerDirectory = null; _requestedServerDirectory = null; _currentTypeSetting = string.Empty; if (_loginState == FtpLoginState.LoggedIn) { _loginState = FtpLoginState.LoggedInButNeedsRelogin; } } if (_loginState != FtpLoginState.LoggedIn) { Credentials = request.Credentials.GetCredential(request.RequestUri, "basic"); _welcomeMessage = new StringBuilder(); _exitMessage = new StringBuilder(); string domainUserName = string.Empty; string password = string.Empty; if (Credentials != null) { domainUserName = Credentials.UserName; string domain = Credentials.Domain; if (!string.IsNullOrEmpty(domain)) { domainUserName = domain + "\\" + domainUserName; } password = Credentials.Password; } if (domainUserName.Length == 0 && password.Length == 0) { domainUserName = "******"; password = "******"; } commandList.Add(new PipelineEntry(FormatFtpCommand("USER", domainUserName))); commandList.Add(new PipelineEntry(FormatFtpCommand("PASS", password), PipelineEntryFlags.DontLogParameter)); // If SSL, always configure data channel encryption after authentication to maximum RFC compatibility. The RFC allows for // PBSZ/PROT commands to come either before or after the USER/PASS, but some servers require USER/PASS immediately after // the AUTH TLS command. if (request.EnableSsl && !UsingSecureStream) { commandList.Add(new PipelineEntry(FormatFtpCommand("PBSZ", "0"))); commandList.Add(new PipelineEntry(FormatFtpCommand("PROT", "P"))); } commandList.Add(new PipelineEntry(FormatFtpCommand("OPTS", "utf8 on"))); commandList.Add(new PipelineEntry(FormatFtpCommand("PWD", null))); } GetPathOption getPathOption = GetPathOption.Normal; if (request.MethodInfo.HasFlag(FtpMethodFlags.DoesNotTakeParameter)) { getPathOption = GetPathOption.AssumeNoFilename; } else if (request.MethodInfo.HasFlag(FtpMethodFlags.ParameterIsDirectory)) { getPathOption = GetPathOption.AssumeFilename; } string requestPath; string requestDirectory; string requestFilename; GetPathInfo(getPathOption, request.RequestUri, out requestPath, out requestDirectory, out requestFilename); if (requestFilename.Length == 0 && request.MethodInfo.HasFlag(FtpMethodFlags.TakesParameter)) { throw new WebException(SR.net_ftp_invalid_uri); } // We optimize for having the current working directory staying at the login directory. This ensure that // our relative paths work right and reduces unnecessary CWD commands. // Usually, we don't change the working directory except for some FTP commands. If necessary, // we need to reset our working directory back to the login directory. if (_establishedServerDirectory != null && _loginDirectory != null && _establishedServerDirectory != _loginDirectory) { commandList.Add(new PipelineEntry(FormatFtpCommand("CWD", _loginDirectory), PipelineEntryFlags.UserCommand)); _requestedServerDirectory = _loginDirectory; } // For most commands, we don't need to navigate to the directory since we pass in the full // path as part of the FTP protocol command. However, some commands require it. if (request.MethodInfo.HasFlag(FtpMethodFlags.MustChangeWorkingDirectoryToPath) && requestDirectory.Length > 0) { commandList.Add(new PipelineEntry(FormatFtpCommand("CWD", requestDirectory), PipelineEntryFlags.UserCommand)); _requestedServerDirectory = requestDirectory; } if (!request.MethodInfo.IsCommandOnly) { string requestedTypeSetting = request.UseBinary ? "I" : "A"; if (_currentTypeSetting != requestedTypeSetting) { commandList.Add(new PipelineEntry(FormatFtpCommand("TYPE", requestedTypeSetting))); _currentTypeSetting = requestedTypeSetting; } if (request.UsePassive) { string passiveCommand = (ServerAddress.AddressFamily == AddressFamily.InterNetwork) ? "PASV" : "EPSV"; commandList.Add(new PipelineEntry(FormatFtpCommand(passiveCommand, null), PipelineEntryFlags.CreateDataConnection)); } else { string portCommand = (ServerAddress.AddressFamily == AddressFamily.InterNetwork) ? "PORT" : "EPRT"; CreateFtpListenerSocket(request); commandList.Add(new PipelineEntry(FormatFtpCommand(portCommand, GetPortCommandLine(request)))); } if (request.ContentOffset > 0) { // REST command must always be the last sent before the main file command is sent. commandList.Add(new PipelineEntry(FormatFtpCommand("REST", request.ContentOffset.ToString(CultureInfo.InvariantCulture)))); } } PipelineEntryFlags flags = PipelineEntryFlags.UserCommand; if (!request.MethodInfo.IsCommandOnly) { flags |= PipelineEntryFlags.GiveDataStream; if (!request.UsePassive) { flags |= PipelineEntryFlags.CreateDataConnection; } } if (request.MethodInfo.Operation == FtpOperation.Rename) { string baseDir = (requestDirectory == string.Empty) ? string.Empty : requestDirectory + "/"; commandList.Add(new PipelineEntry(FormatFtpCommand("RNFR", baseDir + requestFilename), flags)); string renameTo; if (!string.IsNullOrEmpty(request.RenameTo) && request.RenameTo.StartsWith("/", StringComparison.OrdinalIgnoreCase)) { renameTo = request.RenameTo; // Absolute path } else { renameTo = baseDir + request.RenameTo; // Relative path } commandList.Add(new PipelineEntry(FormatFtpCommand("RNTO", renameTo), flags)); } else if (request.MethodInfo.HasFlag(FtpMethodFlags.DoesNotTakeParameter)) { commandList.Add(new PipelineEntry(FormatFtpCommand(request.Method, string.Empty), flags)); } else if (request.MethodInfo.HasFlag(FtpMethodFlags.MustChangeWorkingDirectoryToPath)) { commandList.Add(new PipelineEntry(FormatFtpCommand(request.Method, requestFilename), flags)); } else { commandList.Add(new PipelineEntry(FormatFtpCommand(request.Method, requestPath), flags)); } commandList.Add(new PipelineEntry(FormatFtpCommand("QUIT", null))); return((PipelineEntry[])commandList.ToArray(typeof(PipelineEntry))); }
internal bool HasFlag(PipelineEntryFlags flags) { return((Flags & flags) != 0); }
internal bool HasFlag(PipelineEntryFlags flags) { return (Flags & flags) != 0; }
internal PipelineEntry(string command, PipelineEntryFlags flags) { Command = command; Flags = flags; }
internal PipelineEntry(string command, PipelineEntryFlags flags) { Command = command; Flags = flags; }