tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsDeflateConverter.cpp (5843B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 */
      5 
      6 #include "StreamFunctions.h"
      7 #include "MainThreadUtils.h"
      8 #include "nsDeflateConverter.h"
      9 #include "nsIThreadRetargetableStreamListener.h"
     10 #include "nsStringStream.h"
     11 #include "nsComponentManagerUtils.h"
     12 #include "nsCRT.h"
     13 #include "plstr.h"
     14 #include "mozilla/UniquePtr.h"
     15 
     16 #define ZLIB_TYPE "deflate"
     17 #define GZIP_TYPE "gzip"
     18 #define X_GZIP_TYPE "x-gzip"
     19 
     20 using namespace mozilla;
     21 
     22 /**
     23 * nsDeflateConverter is a stream converter applies the deflate compression
     24 * method to the data.
     25 */
     26 NS_IMPL_ISUPPORTS(nsDeflateConverter, nsIStreamConverter, nsIStreamListener,
     27                  nsIThreadRetargetableStreamListener, nsIRequestObserver)
     28 
     29 nsresult nsDeflateConverter::Init() {
     30  int zerr;
     31 
     32  mOffset = 0;
     33 
     34  mZstream.zalloc = Z_NULL;
     35  mZstream.zfree = Z_NULL;
     36  mZstream.opaque = Z_NULL;
     37 
     38  int32_t window = MAX_WBITS;
     39  switch (mWrapMode) {
     40    case WRAP_NONE:
     41      window = -window;
     42      break;
     43    case WRAP_GZIP:
     44      window += 16;
     45      break;
     46    default:
     47      break;
     48  }
     49 
     50  zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8,
     51                      Z_DEFAULT_STRATEGY);
     52  if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
     53 
     54  mZstream.next_out = mWriteBuffer;
     55  mZstream.avail_out = sizeof(mWriteBuffer);
     56 
     57  // mark the input buffer as empty.
     58  mZstream.avail_in = 0;
     59  mZstream.next_in = Z_NULL;
     60 
     61  return NS_OK;
     62 }
     63 
     64 NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream* aFromStream,
     65                                          const char* aFromType,
     66                                          const char* aToType,
     67                                          nsISupports* aCtxt,
     68                                          nsIInputStream** _retval) {
     69  return NS_ERROR_NOT_IMPLEMENTED;
     70 }
     71 
     72 NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char* aFromType,
     73                                                   const char* aToType,
     74                                                   nsIStreamListener* aListener,
     75                                                   nsISupports* aCtxt) {
     76  if (mListener) return NS_ERROR_ALREADY_INITIALIZED;
     77 
     78  NS_ENSURE_ARG_POINTER(aListener);
     79 
     80  if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE) - 1)) {
     81    mWrapMode = WRAP_ZLIB;
     82  } else if (!nsCRT::strcasecmp(aToType, GZIP_TYPE) ||
     83             !nsCRT::strcasecmp(aToType, X_GZIP_TYPE)) {
     84    mWrapMode = WRAP_GZIP;
     85  } else {
     86    mWrapMode = WRAP_NONE;
     87  }
     88 
     89  nsresult rv = Init();
     90  NS_ENSURE_SUCCESS(rv, rv);
     91 
     92  mListener = aListener;
     93  mContext = aCtxt;
     94  return rv;
     95 }
     96 
     97 NS_IMETHODIMP
     98 nsDeflateConverter::GetConvertedType(const nsACString& aFromType,
     99                                     nsIChannel* aChannel,
    100                                     nsACString& aToType) {
    101  return NS_ERROR_NOT_IMPLEMENTED;
    102 }
    103 
    104 NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest* aRequest,
    105                                                  nsIInputStream* aInputStream,
    106                                                  uint64_t aOffset,
    107                                                  uint32_t aCount) {
    108  if (!mListener) return NS_ERROR_NOT_INITIALIZED;
    109 
    110  auto buffer = MakeUnique<char[]>(aCount);
    111  NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
    112 
    113  nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount);
    114  NS_ENSURE_SUCCESS(rv, rv);
    115 
    116  // make sure we aren't reading too much
    117  mZstream.avail_in = aCount;
    118  mZstream.next_in = (unsigned char*)buffer.get();
    119 
    120  int zerr = Z_OK;
    121  // deflate loop
    122  while (mZstream.avail_in > 0 && zerr == Z_OK) {
    123    zerr = deflate(&mZstream, Z_NO_FLUSH);
    124 
    125    while (mZstream.avail_out == 0) {
    126      // buffer is full, push the data out to the listener
    127      rv = PushAvailableData(aRequest);
    128      NS_ENSURE_SUCCESS(rv, rv);
    129      zerr = deflate(&mZstream, Z_NO_FLUSH);
    130    }
    131  }
    132 
    133  return NS_OK;
    134 }
    135 
    136 NS_IMETHODIMP
    137 nsDeflateConverter::MaybeRetarget(nsIRequest* request) {
    138  return NS_ERROR_NOT_IMPLEMENTED;
    139 }
    140 
    141 NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest* aRequest) {
    142  if (!mListener) return NS_ERROR_NOT_INITIALIZED;
    143 
    144  return mListener->OnStartRequest(aRequest);
    145 }
    146 
    147 NS_IMETHODIMP
    148 nsDeflateConverter::OnDataFinished(nsresult aStatus) {
    149  nsCOMPtr<nsIThreadRetargetableStreamListener> retargetable =
    150      do_QueryInterface(mListener);
    151 
    152  if (retargetable) {
    153    return retargetable->OnDataFinished(aStatus);
    154  }
    155 
    156  return NS_OK;
    157 }
    158 
    159 NS_IMETHODIMP
    160 nsDeflateConverter::CheckListenerChain() { return NS_ERROR_NO_INTERFACE; }
    161 
    162 NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest* aRequest,
    163                                                nsresult aStatusCode) {
    164  if (!mListener) return NS_ERROR_NOT_INITIALIZED;
    165 
    166  nsresult rv;
    167 
    168  int zerr;
    169  do {
    170    zerr = deflate(&mZstream, Z_FINISH);
    171    rv = PushAvailableData(aRequest);
    172    NS_ENSURE_SUCCESS(rv, rv);
    173  } while (zerr == Z_OK);
    174 
    175  deflateEnd(&mZstream);
    176 
    177  return mListener->OnStopRequest(aRequest, aStatusCode);
    178 }
    179 
    180 nsresult nsDeflateConverter::PushAvailableData(nsIRequest* aRequest) {
    181  uint32_t bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out;
    182  // We don't need to do anything if there isn't any data
    183  if (bytesToWrite == 0) return NS_OK;
    184 
    185  MOZ_ASSERT(bytesToWrite <= INT32_MAX);
    186  nsCOMPtr<nsIInputStream> stream;
    187  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
    188                                      Span((char*)mWriteBuffer, bytesToWrite),
    189                                      NS_ASSIGNMENT_DEPEND);
    190  NS_ENSURE_SUCCESS(rv, rv);
    191 
    192  rv = mListener->OnDataAvailable(aRequest, stream, mOffset, bytesToWrite);
    193 
    194  // now set the state for 'deflate'
    195  mZstream.next_out = mWriteBuffer;
    196  mZstream.avail_out = sizeof(mWriteBuffer);
    197 
    198  mOffset += bytesToWrite;
    199  return rv;
    200 }