Documentation Coverage Report
Current view: top level - Cqrs.WebApi/Formatters/FormMultipart/Converters - HttpContentToFormDataConverter.cs Hit Total Coverage
Version: 2.2 Artefacts: 3 3 100.0 %
Date: 2018-08-07 15:04:50

          Line data    Source code
       1             : #region Copyright
       2             : // // -----------------------------------------------------------------------
       3             : // // <copyright company="Chinchilla Software Limited">
       4             : // //   Copyright Chinchilla Software Limited. All rights reserved.
       5             : // // </copyright>
       6             : // // -----------------------------------------------------------------------
       7             : #endregion
       8             : 
       9             : using System;
      10             : using System.IO;
      11             : using System.Linq;
      12             : using System.Net.Http;
      13             : using System.Net.Http.Headers;
      14             : using System.Threading;
      15             : using System.Threading.Tasks;
      16             : using Cqrs.WebApi.Formatters.FormMultipart.Infrastructure;
      17             : 
      18             : namespace Cqrs.WebApi.Formatters.FormMultipart.Converters
      19             : {
      20             :         /// <summary>
      21             :         /// Converts content in a <see cref="HttpContent"/> to <see cref="FormData"/>.
      22             :         /// </summary>
      23             :         public class HttpContentToFormDataConverter
      24           1 :         {
      25             :                 /// <summary>
      26             :                 /// Converts the provided <paramref name="content"/> to multi-part form-data.
      27             :                 /// </summary>
      28           1 :                 public async Task<FormData> Convert(HttpContent content)
      29             :                 {
      30             :                         if(content == null)
      31             :                                 throw new ArgumentNullException("content");
      32             : 
      33             :                         //commented to provide more details about incorrectly formatted data from ReadAsMultipartAsync method
      34             :                         /*if (!content.IsMimeMultipartContent())
      35             :                         {
      36             :                                 throw new Exception("Unsupported Media Type");
      37             :                         }*/
      38             : 
      39             :                         //http://stackoverflow.com/questions/15201255/request-content-readasmultipartasync-never-returns
      40             :                         MultipartMemoryStreamProvider multipartProvider = null;
      41             : 
      42             :                         await Task.Factory
      43             :                                 .StartNewSafely(() =>
      44             :                                         {
      45             :                                                 try
      46             :                                                 {
      47             :                                                         multipartProvider = content.ReadAsMultipartAsync().Result;
      48             :                                                 }
      49             :                                                 catch (AggregateException aggregateException)
      50             :                                                 {
      51             :                                                         if (aggregateException.InnerExceptions.Count != 1)
      52             :                                                                 throw;
      53             :                                                         var exception = aggregateException.InnerExceptions.Single() as IOException;
      54             :                                                         if (exception == null || exception.Message != @"Unexpected end of MIME multipart stream. MIME multipart message is not complete.")
      55             :                                                                 throw;
      56             : 
      57             :                                                         Stream reqStream = content.ReadAsStreamAsync().Result;
      58             :                                                         MemoryStream tempStream = new MemoryStream();
      59             :                                                         reqStream.CopyTo(tempStream);
      60             : 
      61             :                                                         tempStream.Seek(0, SeekOrigin.End);
      62             :                                                         StreamWriter writer = new StreamWriter(tempStream);
      63             :                                                         writer.WriteLine();
      64             :                                                         writer.Flush();
      65             :                                                         tempStream.Position = 0;
      66             : 
      67             : 
      68             :                                                         StreamContent streamContent = new StreamContent(tempStream);
      69             :                                                         foreach (var header in content.Headers)
      70             :                                                                 streamContent.Headers.Add(header.Key, header.Value);
      71             : 
      72             :                                                         // Read the form data and return an async task.
      73             :                                                         multipartProvider = streamContent.ReadAsMultipartAsync().Result;
      74             :                                                 }
      75             :                                         },
      76             :                                         CancellationToken.None,
      77             :                                         TaskCreationOptions.LongRunning, // guarantees separate thread
      78             :                                         TaskScheduler.Default);
      79             : 
      80             :                         var multipartFormData = await Convert(multipartProvider);
      81             :                         return multipartFormData;
      82             :                 }
      83             : 
      84             :                 /// <summary>
      85             :                 /// Converts the <see cref="MultipartStreamProvider.Contents"/> of the provided <paramref name="multipartProvider"/> to multi-part form-data.
      86             :                 /// </summary>
      87           1 :                 public async Task<FormData> Convert(MultipartMemoryStreamProvider multipartProvider)
      88             :                 {
      89             :                         var multipartFormData = new FormData();
      90             : 
      91             :                         foreach (var file in multipartProvider.Contents.Where(x => IsFile(x.Headers.ContentDisposition)))
      92             :                         {
      93             :                                 var name = UnquoteToken(file.Headers.ContentDisposition.Name);
      94             :                                 string fileName = FixFilename(file.Headers.ContentDisposition.FileName);
      95             :                                 string mediaType = file.Headers.ContentType.MediaType;
      96             : 
      97             :                                 using (var stream = await file.ReadAsStreamAsync())
      98             :                                 {
      99             :                                         byte[] buffer = ReadAllBytes(stream);
     100             :                                         if (buffer.Length > 0)
     101             :                                         {
     102             :                                                 multipartFormData.Add(name, new HttpFile(fileName, mediaType, buffer));
     103             :                                         }
     104             :                                 }
     105             :                         }
     106             : 
     107             :                         foreach (var part in multipartProvider.Contents.Where(x => x.Headers.ContentDisposition.DispositionType == "form-data"
     108             :                                                                                                                                   && !IsFile(x.Headers.ContentDisposition)))
     109             :                         {
     110             :                                 var name = UnquoteToken(part.Headers.ContentDisposition.Name);
     111             :                                 var data = await part.ReadAsStringAsync();
     112             :                                 multipartFormData.Add(name, data);
     113             :                         }
     114             : 
     115             :                         return multipartFormData;
     116             :                 } 
     117             : 
     118             :                 private bool IsFile(ContentDispositionHeaderValue disposition)
     119             :                 {
     120             :                         return !string.IsNullOrEmpty(disposition.FileName);
     121             :                 }
     122             : 
     123             :                 /// <summary>
     124             :                 /// Remove bounding quotes on a token if present
     125             :                 /// </summary>
     126             :                 private static string UnquoteToken(string token)
     127             :                 {
     128             :                         if (String.IsNullOrWhiteSpace(token))
     129             :                         {
     130             :                                 return token;
     131             :                         }
     132             : 
     133             :                         if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
     134             :                         {
     135             :                                 return token.Substring(1, token.Length - 2);
     136             :                         }
     137             : 
     138             :                         return token;
     139             :                 }
     140             : 
     141             :                 /// <summary>
     142             :                 /// Amend filenames to remove surrounding quotes and remove path from IE
     143             :                 /// </summary>
     144             :                 private static string FixFilename(string originalFileName)
     145             :                 {
     146             :                         if (string.IsNullOrWhiteSpace(originalFileName))
     147             :                                 return string.Empty;
     148             : 
     149             :                         var result = originalFileName.Trim();
     150             :                         
     151             :                         // remove leading and trailing quotes
     152             :                         result = result.Trim('"');
     153             : 
     154             :                         // remove full path versions
     155             :                         if (result.Contains("\\"))
     156             :                                 result = Path.GetFileName(result);
     157             : 
     158             :                         return result;
     159             :                 }
     160             : 
     161             :                 private byte[] ReadAllBytes(Stream input)
     162             :                 {
     163             :                         using (var stream = new MemoryStream())
     164             :                         {
     165             :                                 input.CopyTo(stream);
     166             :                                 return stream.ToArray();
     167             :                         }
     168             :                 }
     169             :         }
     170             : }

Generated by: LCOV version 1.12