kio Library API Documentation

httpfilter.cc

00001 /*
00002    This file is part of the KDE libraries
00003    Copyright (c) 2002 Waldo Bastian <bastian@kde.org>
00004    
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008    
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013    
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include <kio/global.h>
00021 
00022 #include <klocale.h>
00023 
00024 #include "httpfilter.h"
00025 
00026 HTTPFilterBase::HTTPFilterBase()
00027  : last(0)
00028 {
00029 }
00030 
00031 HTTPFilterBase::~HTTPFilterBase()
00032 {
00033    delete last;
00034 }
00035 
00036 void
00037 HTTPFilterBase::chain(HTTPFilterBase *previous)
00038 {
00039    last = previous;
00040    connect(last, SIGNAL(output(const QByteArray &)),
00041            this, SLOT(slotInput(const QByteArray &)));
00042 }
00043 
00044 HTTPFilterChain::HTTPFilterChain()
00045  : first(0)
00046 {
00047 }
00048 
00049 void
00050 HTTPFilterChain::addFilter(HTTPFilterBase *filter)
00051 {
00052    if (!last)
00053    {
00054       first = filter;
00055    }
00056    else
00057    {
00058       disconnect(last, SIGNAL(output(const QByteArray &)), 0, 0);
00059       filter->chain(last);
00060    }
00061    last = filter;
00062    connect(filter, SIGNAL(output(const QByteArray &)),
00063            this, SIGNAL(output(const QByteArray &)));
00064    connect(filter, SIGNAL(error(int, const QString &)),
00065            this, SIGNAL(error(int, const QString &)));
00066 }
00067 
00068 void
00069 HTTPFilterChain::slotInput(const QByteArray &d)
00070 {
00071    if (first)
00072       first->slotInput(d);
00073    else
00074       emit output(d);      
00075 }
00076 
00077 HTTPFilterMD5::HTTPFilterMD5()
00078 {
00079 }
00080 
00081 QString 
00082 HTTPFilterMD5::md5()
00083 {
00084    return QString::fromLatin1(context.base64Digest());
00085 }
00086 
00087 void 
00088 HTTPFilterMD5::slotInput(const QByteArray &d)
00089 {
00090    context.update(d);
00091    emit output(d);
00092 }
00093 
00094 
00095 HTTPFilterGZip::HTTPFilterGZip()
00096 {
00097 #ifdef DO_GZIP
00098   bHasHeader = false;
00099   bHasFinished = false;
00100   bPlainText = false;
00101   bEatTrailer = false;
00102   bEof = false;
00103   zstr.next_in = (Bytef *) Z_NULL;
00104   zstr.avail_in = 0;
00105   zstr.zalloc = Z_NULL;
00106   zstr.zfree = Z_NULL;
00107   zstr.opaque = Z_NULL;
00108   inflateInit2(&zstr, -MAX_WBITS);
00109   iTrailer = 8;
00110 #endif
00111 }
00112 
00113 HTTPFilterGZip::~HTTPFilterGZip()
00114 {
00115 #ifdef DO_GZIP
00116   inflateEnd(&zstr);
00117 #endif
00118   
00119 }
00120 
00121 /* The get_byte() and checkHeader() functions are modified version from */
00122 /* the correpsonding functions that can be found in zlib, the following */
00123 /* copyright notice applies to these functions:                         */
00124 
00125 /* zlib.h -- interface of the 'zlib' general purpose compression library
00126   version 1.1.3, July 9th, 1998
00127 
00128   Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
00129 
00130   This software is provided 'as-is', without any express or implied
00131   warranty.  In no event will the authors be held liable for any damages
00132   arising from the use of this software.
00133 
00134   Permission is granted to anyone to use this software for any purpose,
00135   including commercial applications, and to alter it and redistribute it
00136   freely, subject to the following restrictions:
00137 
00138   1. The origin of this software must not be misrepresented; you must not
00139      claim that you wrote the original software. If you use this software
00140      in a product, an acknowledgment in the product documentation would be
00141      appreciated but is not required.
00142   2. Altered source versions must be plainly marked as such, and must not be
00143      misrepresented as being the original software.
00144   3. This notice may not be removed or altered from any source distribution.
00145 
00146   Jean-loup Gailly        Mark Adler
00147   jloup@gzip.org          madler@alumni.caltech.edu
00148 
00149 
00150   The data format used by the zlib library is described by RFCs (Request for
00151   Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
00152   (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
00153 */
00154 
00155 int
00156 HTTPFilterGZip::get_byte()
00157 {
00158 #ifdef DO_GZIP
00159     if (bEof) return EOF;
00160     if (zstr.avail_in == 0)
00161     {
00162         bEof = true;
00163         return EOF;
00164     }
00165     zstr.avail_in--;
00166     zstr.total_in++;
00167     return *(zstr.next_in)++;
00168 #else 
00169     return 0;
00170 #endif
00171 }
00172 
00173 #ifdef DO_GZIP
00174 
00175 static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
00176 
00177 /* gzip flag byte */
00178 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
00179 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
00180 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
00181 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
00182 #define COMMENT      0x10 /* bit 4 set: file comment present */
00183 #define RESERVED     0xE0 /* bits 5..7: reserved */
00184 #endif
00185 
00186 // 0 : ok
00187 // 1 : not gzip
00188 // 2 : no header
00189 int
00190 HTTPFilterGZip::checkHeader()
00191 {
00192 #ifdef DO_GZIP
00193     uInt len;
00194     int c;
00195 
00196     /* Check the gzip magic header */
00197     for (len = 0; len < 2; len++) {
00198     c = get_byte();
00199     if (c != gz_magic[len]) {
00200         if (len != 0) 
00201         {
00202            zstr.avail_in++;
00203            zstr.next_in--;
00204         }
00205         if (c != EOF) {
00206         zstr.avail_in++;
00207         zstr.next_in--;
00208         return 1;
00209         }
00210         return 2;
00211     }
00212     }
00213     int method = get_byte(); /* method byte */
00214     int flags = get_byte(); /* flags byte */
00215 
00216     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
00217     return bEof ? 2 : 1;
00218     }
00219 
00220     /* Discard time, xflags and OS code: */
00221     for (len = 0; len < 6; len++) (void)get_byte();
00222 
00223     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
00224     len  =  (uInt)get_byte();
00225     len += ((uInt)get_byte())<<8;
00226     /* len is garbage if EOF but the loop below will quit anyway */
00227     while (len-- != 0 && get_byte() != EOF) ;
00228     }
00229     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
00230     while ((c = get_byte()) != 0 && c != EOF) ;
00231     }
00232     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
00233     while ((c = get_byte()) != 0 && c != EOF) ;
00234     }
00235     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
00236     for (len = 0; len < 2; len++) (void)get_byte();
00237     }
00238     
00239     return bEof ? 2 : 0;
00240 #else
00241     return 0;
00242 #endif
00243 } 
00244 
00245 void 
00246 HTTPFilterGZip::slotInput(const QByteArray &d)
00247 {
00248 #ifdef DO_GZIP
00249   if (bPlainText)
00250   {
00251      emit output(d);
00252      return;
00253   }
00254   if (d.size() == 0)
00255   {
00256      if (bEatTrailer)
00257         bHasFinished = true;
00258      if (!bHasFinished)
00259      {
00260         // Make sure we get the last bytes still in the pipe.
00261         // Needed with "deflate".
00262         QByteArray flush(4);
00263         flush.fill(0);
00264         slotInput(flush);
00265         if (!bHasFinished && !bHasHeader)
00266         {
00267            // Send as-is
00268            emit output(headerData);
00269            bHasFinished = true;
00270            // End of data
00271            emit output(QByteArray());
00272         }
00273      }
00274      if (!bHasFinished)
00275         emit error( KIO::ERR_SLAVE_DEFINED, i18n("Unexpected end of data, some information may be lost."));
00276      return;
00277   }
00278   if (bHasFinished)
00279      return;
00280 
00281   if (bEatTrailer)
00282   {
00283      iTrailer -= d.size();
00284      if (iTrailer <= 0)
00285      {
00286         bHasFinished = true;
00287         // End of data
00288         emit output(QByteArray());
00289      }
00290      return;
00291   }
00292 
00293   if (!bHasHeader)
00294   {
00295      bEof = false;
00296 
00297      // Add data to header.
00298      int orig_size = headerData.size();
00299      headerData.resize(orig_size+d.size());
00300      memcpy(headerData.data()+orig_size, d.data(), d.size());
00301 
00302      zstr.avail_in = headerData.size();
00303      zstr.next_in = (Bytef *) headerData.data();     
00304 
00305      int result = checkHeader();
00306      if (result == 1)
00307      {
00308         bPlainText = true;
00309         output(headerData);
00310         return;
00311      }
00312 
00313      if (result != 0)
00314         return; // next time better
00315 
00316      bHasHeader = true;
00317   }
00318   else
00319   {
00320      zstr.avail_in = d.size();
00321      zstr.next_in = (Bytef *) d.data();
00322   }
00323 
00324   while( zstr.avail_in )
00325   {
00326      char buf[8192];
00327      zstr.next_out = (Bytef *) buf;
00328      zstr.avail_out = 8192;
00329      int result = inflate( &zstr, Z_NO_FLUSH );
00330      if ((result != Z_OK) && (result != Z_STREAM_END))
00331      {
00332         emit error( KIO::ERR_SLAVE_DEFINED, i18n("Receiving corrupt data."));
00333         break;
00334      }
00335      int bytesOut = 8192 - zstr.avail_out;
00336      if (bytesOut)
00337      {
00338         QByteArray d;
00339         d.setRawData( buf, bytesOut );
00340         emit output(d);
00341         d.resetRawData( buf, bytesOut );
00342      }
00343      if (result == Z_STREAM_END)
00344      {
00345         if (iTrailer)
00346         {
00347            bEatTrailer = true;
00348         }
00349         else
00350         {
00351            bHasFinished = true;
00352            // End of data
00353            emit output(QByteArray());
00354         }
00355         return;
00356      }
00357   }  
00358 #endif
00359 }
00360 
00361 HTTPFilterDeflate::HTTPFilterDeflate()
00362 {
00363 #ifdef DO_GZIP
00364   bHasHeader = true;
00365   iTrailer = 0;
00366 #endif
00367 }
00368 
00369 #include "httpfilter.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:20:36 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003