Как вы храните байты в переменной от al oop, чтобы веб-ответ мог быть распакован? - PullRequest
0 голосов
/ 11 января 2020

Я строю свой собственный прокси-сервер HTTP / 1.0, используя HTTPWebRequest / HTTPWebResponse. Часть исходного кода передавала ответ от удаленного сервера напрямую клиенту следующим образом:

if (response != null)
{
    List<Tuple<String, String>> responseHeaders = ProcessResponse(response);
    StreamWriter myResponseWriter = new StreamWriter(outStream);
    Stream responseStream = response.GetResponseStream();
    HttpStatusCode statusCode = response.StatusCode;
    string statusDesc = response.StatusDescription;

    Byte[] buffer;
    if (response.ContentLength > 0)
    {
        buffer = new Byte[response.ContentLength];
    }
    else
    {
        buffer = new Byte[BUFFER_SIZE];
    }

    int bytesRead;

    //send the response status and response headers
    WriteResponseStatus(statusCode, statusDesc, myResponseWriter);
    WriteResponseHeaders(myResponseWriter, responseHeaders);

    while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        // this is the response body being streamed directly to the client browser
        outStream.Write(buffer, 0, bytesRead);
    }
}

Я пытался перехватить тело ответа, чтобы я мог изменить содержимое, но прежде чем я смог сделать это мне нужно, чтобы распаковать содержимое, если оно было gzip / br / deflate удаленным сервером. Это то, что я придумал до сих пор, но, как вы можете видеть из моих комментариев, я просто не могу понять, как сохранить поток байтов в одну переменную, чтобы я мог затем отправить его для распаковки:

Byte[] buffer;
if (response.ContentLength > 0)
    buffer = new Byte[response.ContentLength];
else
    buffer = new Byte[BUFFER_SIZE];

int bytesRead;
var res = "";

// if the url and content type matches the criteria, then we want to edit it
if (hostPathMatch.Count > 0 && contentTypeMatch.Count > 0)
{
    while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
    {   
        // how to we send this response stream to a var so that the entire contents can be sent to decompress

        //res += UTF8Encoding.UTF8.GetString(buffer, 0, bytesRead); // this doesnt work as it mangles gzipped contents
    }

    //was the page compressed? check the content-encoding header.
    if (responseHeaders.Any(p => p.Item1.ToLower() == "content-encoding" && p.Item2.ToLower() == "gzip"))
    {
        Output._Log.Output_Log("CONTENT IS GZIPPED");
        res = Tools.Unzip(res); // expects byte[], returns UTF8
    }

    // THIS IS WHERE WE WILL MODIFY THE BODY CONTENTS
    res = res.Replace("Foo", "Bar Bar");

    // then we will re-compress

    // update the response headers with the correct content length after modification
    responseHeaders.RemoveAll(p => p.Item1 == "Content-Length");
    responseHeaders.Add(new Tuple<string, string>("Content-Length", res.Length));

    //send the response status and response headers
    WriteResponseStatus(statusCode, statusDesc, myResponseWriter); 
    WriteResponseHeaders(myResponseWriter, responseHeaders);
}
else // we didnt want to modify this file, so just stream it out directly to the browser
{
    //send the response status and response headers
    WriteResponseStatus(statusCode, statusDesc, myResponseWriter);
    WriteResponseHeaders(myResponseWriter, responseHeaders);

    while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        outStream.Write(buffer, 0, bytesRead);
    }
}

1 Ответ

1 голос
/ 12 января 2020

Для случая, когда вы не знаете общий размер заранее, вы можете сделать что-то вроде следующего:

[...]

List<byte> data = new List<byte>();
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
    for(int i = 0; i < bytesRead; ++i)
        data.Add(buffer[i]);
}

var bytes = data.ToArray();

[...]

Если вы знаете это заранее, вы можете использовать что-то вроде

[...]

int offset = 0;
byte[] data = new byte[TOTAL_SIZE];
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
    buffer.CopyTo(data, offset);
    offset += bytesRead;
}

[...]

Обратите внимание, что ни один из приведенных выше фрагментов не был проверен, и некоторые проверки должны быть добавлены (например, вне диапазона и т. Д. c.). Кроме того, в зависимости от случаев использования он может не соответствовать вашим потребностям (например, для больших данных).

PS: НЕ ЗАБУДЬТЕ утилизировать / очистить все IDisposable s.

...