Exemple #1
0
        public async Task <ParseBodyAndSavePacketsResult> ParseBodyAndSavePackets(MessageHeaders messageHeaders, HttpRequest request)
        {
            var cancellationToken = request.HttpContext.RequestAborted;

            cancellationToken.ThrowIfCancellationRequested();

            var    format   = messageHeaders.Format ?? TransportConstants.RequestFormDataFormat;
            string boundary = null;

            if (format == TransportConstants.RequestFormDataFormat)
            {
                int fileSectionBufferSize = 81920;

                // если данные formdata упорядочены в потоке запроса (бинарные данные должны идти после большинства метаданных о пакете)
                if (messageHeaders.Hints?.Contains(MessageHints.OrderedFormData) == true)
                {
                    var indexToPacketDataItem    = new Dictionary <int, PacketFormDataItem>();
                    var indexToPacketBytes       = new Dictionary <int, byte[]>();
                    var indexToConfigurationItem = new Dictionary <int, ConfigurationRequestDataItem>();

                    if (MediaTypeHeaderValue.TryParse(request.ContentType, out var contentType))
                    {
                        boundary = HeaderUtilities.GetBoundary(contentType, 70);
                    }

                    var multipartReader = new MultipartReader(boundary, request.Body)
                    {
                        //ValueCountLimit = _options.ValueCountLimit,
                        //KeyLengthLimit = _options.KeyLengthLimit,
                        //ValueLengthLimit = _options.ValueLengthLimit,

                        HeadersCountLimit  = int.MaxValue,
                        HeadersLengthLimit = int.MaxValue,
                        BodyLengthLimit    = long.MaxValue,
                    };

                    //PacketFormDataItem current = null;
                    //byte[] currentBytes = null;
                    var agentId = messageHeaders.GetAgentIdData();
                    var section = await multipartReader.ReadNextSectionAsync(cancellationToken);

                    while (section != null)
                    {
                        // Parse the content disposition here and pass it further to avoid reparsings
                        if (!ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition))
                        {
                            throw new InvalidDataException("Form section has invalid Content-Disposition value: " + section.ContentDisposition);
                        }

                        if (contentDisposition.IsFileDisposition())
                        {
                            var fileSection = new FileMultipartSection(section, contentDisposition);

                            var name     = fileSection.Name;
                            var fileName = fileSection.FileName;
                            var packetId = fileSection.FileName;
                            var result   = GetFormPathDataFromEntry(name);
                            if (result != null && result.Parts.Count == 3 && result.Parts[0] == TransportConstants.FormDataPacketsProp)
                            {
                                if (int.TryParse(result.Parts[1], out var index))
                                {
                                    var item        = indexToPacketDataItem[index];
                                    var providerKey = item.ProviderKey;

                                    var packetItem = indexToPacketDataItem[index];
                                    if (packetItem.PacketId != packetId)
                                    {
                                        throw new InvalidDataException($"Incorrect format for form-data message. Section {name} has invalid FileName.");
                                    }

                                    var bytes = await ReadToEnd(fileSection.FileStream, fileSectionBufferSize, cancellationToken);

                                    indexToPacketBytes.Add(index, bytes);
                                }
                                else
                                {
                                    throw new InvalidDataException($"Incorrect format for form-data message. Section {name} does not have index suffix.");
                                }
                            }
                            else
                            {
                                throw new InvalidDataException($"Incorrect format for form-data message. Section {name} incorrect.");
                            }
                        }
                        else if (contentDisposition.IsFormDisposition())
                        {
                            var formDataSection = new FormMultipartSection(section, contentDisposition);

                            // Content-Disposition: form-data; name="key"
                            //
                            // value

                            // Do not limit the key name length here because the multipart headers length limit is already in effect.
                            var key   = formDataSection.Name;
                            var value = await formDataSection.GetValueAsync();

                            var result = GetFormPathDataFromEntry(key);
                            if (result != null && result.Parts.Count == 3 && result.Parts[0] == TransportConstants.FormDataPacketsProp)
                            {
                                if (int.TryParse(result.Parts[1], out var index))
                                {
                                    if (!indexToPacketDataItem.TryGetValue(index, out var dataItem))
                                    {
                                        //// сохраняем предыдущий
                                        //if (current != null)
                                        //{
                                        //    await this.packetsStore.AddIfNotExistsPacketPartAsync(agentId, this.CreateAddPacketRequest(current, currentBytes));
                                        //}

                                        dataItem = new PacketFormDataItem();
                                        indexToPacketDataItem.Add(index, dataItem);
                                    }

                                    if (!dataItem.FillProperty(result.Parts[2], value))
                                    {
                                        throw new InvalidDataException($"Incorrect format for form-data message. Section {key} incorrect.");
                                    }
                                }
                                else
                                {
                                    throw new InvalidDataException($"Incorrect format for form-data message. Section {key} does not have index suffix.");
                                }
                            }
                            else if (result != null && result.Parts.Count == 3 && result.Parts[0] == TransportConstants.FormDataConfigurationProp)
                            {
                                if (int.TryParse(result.Parts[1], out var index))
                                {
                                    if (!indexToConfigurationItem.TryGetValue(index, out var dataItem))
                                    {
                                        dataItem = new ConfigurationRequestDataItem();
                                        indexToConfigurationItem.Add(index, dataItem);
                                    }

                                    if (!dataItem.FillProperty(result.Parts[2], value))
                                    {
                                        throw new InvalidDataException($"Incorrect format for form-data message. Section {key} incorrect.");
                                    }
                                }
                                else
                                {
                                    throw new InvalidDataException($"Incorrect format for form-data message. Section {key} does not have index suffix.");
                                }
                            }
                            else
                            {
                                // ignore or throw?
                            }

                            //if (formAccumulator.ValueCount > _options.ValueCountLimit)
                            //{
                            //    throw new InvalidDataException($"Form value count limit {_options.ValueCountLimit} exceeded.");
                            //}
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(false, "Unrecognized content-disposition for this section: " + section.ContentDisposition);
                        }

                        section = await multipartReader.ReadNextSectionAsync(cancellationToken);
                    }

                    // сохраняем все
                    var addResult = indexToPacketDataItem.Any()
                                ? await this.packetsStore.AddIfNotExistsPacketsPartsAsync(agentId, indexToPacketDataItem.Select(x =>
                    {
                        var bytes = indexToPacketBytes[x.Key];
                        return(this.CreateAddPacketRequest(agentId, x.Value, bytes));
                    }).ToList())
                                : AddAddPacketsPartsResult.EmptyResult();

                    return(new ParseBodyAndSavePacketsResult
                    {
                        TransferedPackets = indexToPacketDataItem.Values
                                            .Select(x => {
                            return new TransferedPacketResponse
                            {
                                PacketId = x.PacketId,
                                ProviderKey = x.ProviderKey,
                                //AgentIdData = agentId,
                                Result = addResult.Results.Single(r => r.Request.PacketId == x.PacketId).Success
                                                ? TransferedProcessingResult.Saved
                                                : TransferedProcessingResult.Error,
                            };
                        }).ToList(),
                        ConfigurationsStats = indexToConfigurationItem.Values,
                    });
                }
                else
                {
                    var indexToPacketDataItem    = new Dictionary <string, PacketFormDataItem>();
                    var indexToPacketBytes       = new Dictionary <string, byte[]>();
                    var indexToConfigurationItem = new Dictionary <string, ConfigurationRequestDataItem>();
                    var agentId = messageHeaders.GetAgentIdData();

                    foreach (var item in request.Form)
                    {
                        var key   = item.Key;
                        var value = item.Value;

                        var result = GetFormPathDataFromEntry(key);
                        if (result != null && result.Parts.Count == 3 && result.Parts[0] == TransportConstants.FormDataPacketsProp)
                        {
                            var index = result.Parts[1];
                            if (!indexToPacketDataItem.TryGetValue(index, out var dataItem))
                            {
                                dataItem = new PacketFormDataItem();
                                indexToPacketDataItem.Add(index, dataItem);
                            }

                            if (!dataItem.FillProperty(result.Parts[2], value))
                            {
                                throw new InvalidDataException($"Incorrect format for form-data message. Section {key} incorrect.");
                            }
                        }

                        if (result != null && result.Parts.Count == 3 && result.Parts[0] == TransportConstants.FormDataConfigurationProp)
                        {
                            var index = result.Parts[1];
                            if (!indexToConfigurationItem.TryGetValue(index, out var dataItem))
                            {
                                dataItem = new ConfigurationRequestDataItem();
                                indexToConfigurationItem.Add(index, dataItem);
                            }

                            if (!dataItem.FillProperty(result.Parts[2], value))
                            {
                                throw new InvalidDataException($"Incorrect format for form-data message. Section {key} incorrect.");
                            }
                        }
                    }

                    foreach (var file in request.Form.Files)
                    {
                        var pair = indexToPacketDataItem
                                   .FirstOrDefault(x => x.Value.PacketId == file.FileName);

                        if (default(KeyValuePair <string, PacketFormDataItem>).Equals(pair))
                        {
                            var item        = pair.Value;
                            var providerKey = item.ProviderKey;
                            var packetId    = item.PacketId;

                            using (var fileStream = file.OpenReadStream())
                            {
                                var currentBytes = await ReadToEnd(fileStream, fileSectionBufferSize, cancellationToken);

                                indexToPacketBytes.Add(pair.Key, currentBytes);
                            }
                        }
                    }

                    // сохраняем все
                    var addResult = indexToPacketDataItem.Any()
                                ? await this.packetsStore.AddIfNotExistsPacketsPartsAsync(agentId, indexToPacketDataItem.Select(x =>
                    {
                        var bytes = indexToPacketBytes[x.Key];
                        return(this.CreateAddPacketRequest(agentId, x.Value, bytes));
                    }).ToList())
                                : AddAddPacketsPartsResult.EmptyResult();

                    return(new ParseBodyAndSavePacketsResult
                    {
                        TransferedPackets = indexToPacketDataItem.Values
                                            .Select(x =>
                        {
                            return new TransferedPacketResponse
                            {
                                PacketId = x.PacketId,
                                ProviderKey = x.ProviderKey,
                                //AgentIdData = agentId,
                                Result = addResult.Results
                                         .Single(r => r.Request.PacketId == x.PacketId)
                                         .Success
                                                                    ? TransferedProcessingResult.Saved
                                                                    : TransferedProcessingResult.Error,
                            };
                        }).ToList(),
                        ConfigurationsStats = indexToConfigurationItem.Values,
                    });
                }
            }
            else
            {
                throw new NotSupportedException($"format {format} is not supported");
            }
        }