Ejemplo n.º 1
0
        /// <summary>
        /// Reads query string from header and form - file data from content, sets values to request's QueryString, Form and Files properties
        /// </summary>
        internal static void ReadContent(HttpRequest request)
        {
            request.QueryString = !string.IsNullOrEmpty(request.QueryStringData)
                                      ? EncodedFormDataReader.Read(request.QueryStringData)
                                      : new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase);

            if (string.IsNullOrEmpty(request.ContentType))
            {
                return;
            }

            if (request.ContentType.Equals(HttpHeaders.MULTIPART_FORM_DATA, StringComparison.InvariantCultureIgnoreCase))
            {
                if (request.ContentLength > 0)
                {
                    List <FormDataItem> data = MultipartFormDataReader.Read(request.Boundary, request.ContentStream);

                    request.Form = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase);
                    foreach (FormDataItem item in data.Where(x => !x.IsFile))
                    {
                        string value = Encoding.UTF8.GetString(item.Stream.ToArray());
                        if (request.Form.ContainsKey(item.Name))
                        {
                            request.Form[item.Name] += "," + value;
                        }
                        else
                        {
                            request.Form.Add(item.Name, value);
                        }
                    }

                    request.Files = data.Where(x => x.IsFile).Select(x => new FormFile
                    {
                        Filename    = x.Filename,
                        Name        = x.Name,
                        Size        = Convert.ToInt32(x.Stream.Length),
                        Stream      = x.Stream,
                        ContentType = x.ContentType
                    });
                }
                else
                {
                    request.Form  = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase);
                    request.Files = new IFormFile[0];
                }
            }
            else if (request.ContentType.Equals(HttpHeaders.APPLICATION_FORM_URLENCODED, StringComparison.InvariantCultureIgnoreCase))
            {
                request.Form = request.ContentLength > 0
                                   ? EncodedFormDataReader.Read(request.ContentStream)
                                   : new Dictionary <string, string>();
            }
        }
Ejemplo n.º 2
0
        private async Task HandleUpload(HttpConnection p, string path)
        {
            bool   responseListPage = p.ParseUrlQstr()["infoonly"] != "1";
            string info             = null;

            if (!(allow_create | allow_edit))
            {
                info = $"{strMissingPermission("create")} and {strMissingPermission("edit")}.";
                goto FAIL;
            }
            var    reader       = new MultipartFormDataReader(p);
            int    count        = 0;
            string saveFileName = null;
            string encoding     = "utf-8";

            while (await reader.ReadNextPartHeader())
            {
                if (reader.CurrentPartName == "file")
                {
                    var fileName = reader.CurrentPartFileName;
                    if (!CheckPathForWriting(path, fileName, out info, out var realPath))
                    {
                        goto FAIL;
                    }
                    if (!TryOpenFile(path, fileName + ".uploading", out var fs, out info, out var tempPath))
                    {
                        goto FAIL;
                    }
                    try {
                        using (fs) {
                            await NaiveUtils.StreamCopyAsync(reader, fs);
                        }
                        MoveOrReplace(tempPath, realPath);
                    } catch (Exception e) {
                        Logger.exception(e, Logging.Level.Warning, $"receiving file '{fileName}' from {p.myStream}.");
                        File.Delete(realPath);
                        if (e is DisconnectedException)
                        {
                            return;
                        }
                        info = $"IO error on '{saveFileName}'";
                        goto FAIL;
                    }
                    Logger.info($"uploaded '{fileName}' by {p.myStream}.");
                    count++;
                }
                else if (reader.CurrentPartName.Is("textFileName").Or("fileName"))
                {
                    saveFileName = await reader.ReadAllTextAsync();
                }
                else if (reader.CurrentPartName == "textFileEncoding")
                {
                    encoding = await reader.ReadAllTextAsync();
                }
                else if (reader.CurrentPartName == "textContent")
                {
                    if (!CheckPathForWriting(path, saveFileName, out info, out var realPath))
                    {
                        goto FAIL;
                    }
                    if (!TryOpenFile(path, saveFileName + ".uploading", out var fs, out info, out var tempPath))
                    {
                        goto FAIL;
                    }
                    try {
                        using (fs) {
                            if (encoding == "utf-8")
                            {
                                await NaiveUtils.StreamCopyAsync(reader, fs, bs : 8 * 1024);
                            }
                            else
                            {
                                using (var sr = new StreamReader(reader)) {
                                    using (var sw = new StreamWriter(fs, Encoding.GetEncoding(encoding))) {
                                        const int bufLen = 8 * 1024;
                                        var       buf    = new char[bufLen];
                                        var       read   = await sr.ReadAsync(buf, 0, bufLen);

                                        await sw.WriteAsync(buf, 0, read);
                                    }
                                }
                            }
                        }
                        MoveOrReplace(tempPath, realPath);
                    } catch (Exception e) {
                        Logger.exception(e, Logging.Level.Warning, $"receiving text file '{saveFileName}' from {p.myStream}.");
                        File.Delete(tempPath);
                        if (e is DisconnectedException)
                        {
                            return;
                        }
                        info = $"IO error on '{saveFileName}'";
                        goto FAIL;
                    }
                    Logger.info($"uploaded text '{saveFileName}' by {p.myStream}.");
                    count++;
                }
                else if (reader.CurrentPartName == "mkdir")
                {
                    var dirName = await reader.ReadAllTextAsync();

                    if (!CheckPathForWriting(path, dirName, out info, out var realPath))
                    {
                        goto FAIL;
                    }
                    try {
                        Directory.CreateDirectory(realPath);
                    } catch (Exception) {
                        info = $"Failed to create directory '{dirName}'";
                        goto FAIL;
                    }
                    Logger.info($"created dir '{dirName}' by {p.myStream}.");
                    count++;
                }
                else if (reader.CurrentPartName == "rm")
                {
                    var delFile = await reader.ReadAllTextAsync();

                    if (!CheckPathForWriting(path, delFile, out info, out var realPath, out var r))
                    {
                        goto FAIL;
                    }
                    try {
                        if (r == WebSvrHelper.PathResult.Directory)
                        {
                            Directory.Delete(realPath);
                        }
                        else if (r == WebSvrHelper.PathResult.File)
                        {
                            File.Delete(realPath);
                        }
                        else
                        {
                            info = $"Failed to delete '{delFile}' (not found).";
                            goto FAIL;
                        }
                    } catch (Exception) {
                        info = $"Failed to delete '{delFile}'";
                        goto FAIL;
                    }
                    Logger.info($"deleted '{delFile}' by {p.myStream}.");
                    count++;
                }
                else if (reader.CurrentPartName == "netdl")
                {
                    if (!allow_netdl)
                    {
                        info = $"{strMissingPermission("netdl")}.";
                        goto FAIL;
                    }
                    var unparsed = await reader.ReadAllTextAsync();

                    var    args = Naive.Console.Command.SplitArguments(unparsed);
                    string url, name;
                    if (args.Length == 0 || args.Length > 2)
                    {
                        info = $"wrong arguments.";
                        goto FAIL;
                    }
                    url = args[0];
                    if (args.Length == 2)
                    {
                        name = args[1];
                    }
                    else
                    {
                        int startIndex = url.LastIndexOf('/');
                        if (startIndex < 0)
                        {
                            info = "can not determine a filename from the given url, please specify one.";
                            goto FAIL;
                        }
                        name = url.Substring(startIndex);
                    }
                    if (!CheckPathForWriting(path, name, out info, out var realPath, out var r))
                    {
                        goto FAIL;
                    }
                    if (r == WebSvrHelper.PathResult.Directory)
                    {
                        name = Path.Combine(url.Substring(url.LastIndexOf('/')), name);
                        if (!CheckPathForWriting(path, name, out info, out realPath))
                        {
                            goto FAIL;
                        }
                    }
                    if (!CheckPathForWriting(path, name + ".downloading", out info, out var realDlPath))
                    {
                        goto FAIL;
                    }

                    var dlTask = new DownloadTask(url, realDlPath);

                    // double checked locking, add the new task into the dict if no task already exist.
                    downloadTasksLock.EnterReadLock();
                    var taskExists = downloadTasks.TryGetValue(realDlPath, out var oldTask);
                    downloadTasksLock.ExitReadLock();

                    if (!taskExists)
                    {
                        downloadTasksLock.EnterWriteLock();
                        taskExists = downloadTasks.TryGetValue(realDlPath, out oldTask);
                        if (!taskExists)
                        {
                            downloadTasks.Add(realDlPath, dlTask);
                        }
                        downloadTasksLock.ExitWriteLock();
                    }

                    if (taskExists)
                    {
                        if (oldTask.State <= DownloadTask.States.running)
                        {
                            info = "a task is already running on this path.";
                            goto FAIL;
                        }
                        else
                        {
                            info = $"override a '{oldTask.State}' task.\n";
                            downloadTasksLock.EnterWriteLock();
                            downloadTasks[realDlPath] = dlTask;
                            downloadTasksLock.ExitWriteLock();
                        }
                    }

                    try {
                        var t = NaiveUtils.RunAsyncTask(async() => {
                            try {
                                await dlTask.Start();
                                MoveOrReplace(realDlPath, realPath);
                            } finally {
                                // Whether success or not, remove the task from list after 5 minutes.
                                AsyncHelper.SetTimeout(5 * 60 * 1000, () => {
                                    downloadTasksLock.EnterWriteLock();
                                    downloadTasks.Remove(realDlPath);
                                    downloadTasksLock.ExitWriteLock();
                                });
                            }
                        });
                        if (await t.WithTimeout(200))
                        {
                            info += "downloading task is started.";
                        }
                        else
                        {
                            await t;
                            info += "downloaded.";
                        }
                    } catch (Exception e) {
                        Logger.exception(e, Logging.Level.Warning, $"downloading from '{url}' to '{realDlPath}'");
                        info += "downloading failed.";
                        goto FAIL;
                    }
                    count++;
                }
                else if (reader.CurrentPartName.Is("mv").Or("cp"))
                {
                    var unparsed = await reader.ReadAllTextAsync();

                    var args = Naive.Console.Command.SplitArguments(unparsed);
                    if (args.Length < 2)
                    {
                        info = $"too few arguments";
                        goto FAIL;
                    }
                    string to = args[args.Length - 1];
                    if (!CheckPathForWriting(path, to, out info, out var toPath, out var toType))
                    {
                        goto FAIL;
                    }
                    bool multipleFrom = args.Length > 2;
                    if (multipleFrom && toType != WebSvrHelper.PathResult.Directory)
                    {
                        info = "multiple 'from' when 'to' is not a directory!";
                        goto FAIL;
                    }
                    for (int i = 0; i < args.Length - 1; i++)
                    {
                        string from = args[i];
                        if (!CheckPathForWriting(path, from, out info, out var fromPath))
                        {
                            goto FAIL;
                        }
                        string toFilePath = toType == WebSvrHelper.PathResult.Directory
                            ? Path.Combine(toPath, Path.GetFileName(from))
                            : toPath;
                        // TODO: refine directory moving/copying
                        try {
                            if (reader.CurrentPartName == "mv")
                            {
                                MoveOrReplace(fromPath, toFilePath);
                            }
                            else
                            {
                                File.Copy(fromPath, toFilePath, true);
                            }
                        } catch (Exception e) {
                            Logger.exception(e, Logging.Level.Warning, $"file mv/cp from  '{fromPath}' to '{toFilePath}' by {p.myStream}.");
                            info = "error occurred during file operation at " + from;
                            goto FAIL;
                        }
                        count++;
                    }
                }
                else if (reader.CurrentPartName == "rmm")
                {
                    var unparsed = await reader.ReadAllTextAsync();

                    var args = Naive.Console.Command.SplitArguments(unparsed);
                    if (args.Length == 0)
                    {
                        info = "no arguments.";
                        goto FAIL;
                    }
                    foreach (var delFile in args)
                    {
                        if (!CheckPathForWriting(path, delFile, out info, out var realPath, out var r))
                        {
                            goto FAIL;
                        }
                        try {
                            if (r == WebSvrHelper.PathResult.Directory)
                            {
                                Directory.Delete(realPath);
                            }
                            else if (r == WebSvrHelper.PathResult.File)
                            {
                                File.Delete(realPath);
                            }
                            else
                            {
                                info = $"Failed to delete '{delFile}' (not found)";
                                goto FAIL;
                            }
                        } catch (Exception) {
                            info = $"Failed to delete '{delFile}'";
                            goto FAIL;
                        }
                        Logger.info($"deleted '{delFile}' by {p.myStream}.");
                        count++;
                    }
                }
                else if (reader.CurrentPartName.Is("infoonly").Or("isajax"))
                {
                    responseListPage = false;
                }
                else
                {
                    info = $"Unknown part name '{reader.CurrentPartName}'";
                    goto FAIL;
                }
            }
            if (info == null || count > 1)
            {
                info = $"Finished {count} operation{(count > 1 ? "s" : null)}.";
            }
FAIL:
            if (responseListPage)
            {
                await HandleDirList(p, path, info);
            }
            else
            {
                p.Handled = true;
                p.setContentTypeTextPlain();
                await p.writeLineAsync(info);
            }
        }