Как удалить информацию заголовка, используя HttpModule для загрузки файла? - PullRequest
0 голосов
/ 06 июня 2009

Я создал HttpModule в ASP.NET, чтобы пользователи могли загружать большие файлы. В Интернете я нашел пример кода, который смог адаптировать под свои нужды. Я беру файл, если он состоит из нескольких частей, а затем разбиваю байты на части и записываю их на диск.

Проблема в том, что файл всегда поврежден. После некоторых исследований выясняется, что по какой-то причине есть теги заголовка HTTP или тела сообщения, примененные к первой части байтов, которые я получаю. Я не могу понять, как разобрать эти байты, чтобы я получил только файл.

Дополнительные данные / ненужные файлы добавляются в начало файла, например:

-----------------------8cbb435d6837a3f
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: application/octet-stream

Этот тип информации заголовка, конечно, портит файл, который я получаю, поэтому мне нужно избавиться от него, прежде чем я запишу байты.

Вот код, который я написал для обработки загрузки:

public class FileUploadManager : IHttpModule
{
    public int BUFFER_SIZE = 1024;

    protected void app_BeginRequest(object sender, EventArgs e)
    {
        // get the context we are working under
        HttpContext context = ((HttpApplication)sender).Context;

        // make sure this is multi-part data
        if (context.Request.ContentType.IndexOf("multipart/form-data") == -1)
        {
            return;
        }

        IServiceProvider provider = (IServiceProvider)context;
        HttpWorkerRequest wr = 
        (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));

        // only process this file if it has a body and is not already preloaded
        if (wr.HasEntityBody() && !wr.IsEntireEntityBodyIsPreloaded())
        {
            // get the total length of the body
            int iRequestLength = wr.GetTotalEntityBodyLength();

            // get the initial bytes loaded
            int iReceivedBytes = wr.GetPreloadedEntityBodyLength();

            // open file stream to write bytes to
            using (System.IO.FileStream fs = 
            new System.IO.FileStream(
               @"C:\tempfiles\test.txt", 
               System.IO.FileMode.CreateNew))
            {
                // *** NOTE: This is where I think I need to filter the bytes 
                // received to get rid of the junk data but I am unsure how to 
                // do this?

                int bytesRead = BUFFER_SIZE;
                // Create an input buffer to store the incomming data 
                byte[] byteBuffer = new byte[BUFFER_SIZE];
                while ((iRequestLength - iReceivedBytes) >= bytesRead)
                {
                    // read the next chunk of the file
                    bytesRead = wr.ReadEntityBody(byteBuffer, byteBuffer.Length);
                    fs.Write(byteBuffer, 0, byteBuffer.Length);
                    iReceivedBytes += bytesRead;

                    // write bytes so far of file to disk
                    fs.Flush();
                }
            }
        }
    }
}

Как бы я обнаружил и проанализировал эту ненужную информацию заголовка, чтобы изолировать только биты файла?

Ответы [ 2 ]

1 голос
/ 22 сентября 2013

используйте класс InputSteramEntity следующим образом:

 InputStreamEntity reqEntity = new InputStreamEntity(new FileInputStream(filePath), -1);
 reqEntity.setContentType("binary/octet-stream");
 httppost.setEntity(reqEntity);
 HttpResponse response = httpclient.execute(httppost);

Если вы используете, как указано выше, он не будет добавлять токен в заголовок и трейлер и расположение контента, тип контента на сервере

----------------------- 8cbb435d6837a3f Content-Disposition: форма-данные; Name = "файл"; имя файла = "test.txt" Тип контента: приложение / октет-поток

----------------------- 8cbb435d6837a3f

0 голосов
/ 06 июня 2009

То, с чем вы сталкиваетесь, - это граница, используемая для разделения различных частей HTTP-запроса. В начале запроса должен быть заголовок Content-type, а внутри этого заголовка есть оператор границы, например:

Content-Type: multipart/mixed;boundary=gc0p4Jq0M2Yt08jU534c0p

Как только вы найдете эту границу, просто разделите ваш запрос на границе с двумя дефисами (-), добавленными к нему. Другими словами, разделите ваш контент на:

"--"+Headers.Get("Content-Type").Split("boundary=")[1]

Сорт псевдокода есть, но он должен понять смысл. Это должно разделить данные составной формы на соответствующие разделы.

Для получения дополнительной информации см. RFC1341

Стоит отметить, что, очевидно, к конечной границе добавляются два дефиса и к концу границы.

РЕДАКТИРОВАТЬ: Хорошо, проблема в том, что вы не разбиваете данные формы на необходимые компоненты. Разделы запроса multipart / form-data могут быть обработаны по отдельности как отдельные запросы (то есть они могут содержать заголовки). Что вы, вероятно, должны сделать, это прочитать байты в строку:

string formData = Encoding.ASCII.GetString(byteBuffer);

разбить на несколько строк на основе границы:

string boundary = "\r\n"+context.Request.ContentType.Split("boundary=")[1];
string[] parts = Regex.Split( formData, boundary );

перебирает каждую строку, отделяя заголовки от содержимого. Поскольку вам действительно нужно значение байта содержимого, следите за смещением данных, поскольку преобразование из ASCII обратно в байт может работать неправильно (я могу ошибаться, но я параноик):

int dataOffset = 0;
for( int i=0; i < parts.Length; i++ ){
    string header = part.Substring( 0, part.IndexOf( "\r\n\r\n" ) );
    dataOffset += boundary.Length + header.Length + 4;
    string asciiBody = part.Substring( part.IndexOf( "\r\n\r\n" ) + 4 );
    byte[] body = new byte[ asciiBody.Length ];

    for( int j=dataOffset,k=0; j < asciiBody.Length; j++ ){
        body[k++] = byteBuffer[j];
    }

    // body now contains your binary data
}

ПРИМЕЧАНИЕ. Это не проверено, поэтому может потребоваться некоторая настройка.

...