Annotation of embedaddon/curl/lib/content_encoding.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
        !             9:  *
        !            10:  * This software is licensed as described in the file COPYING, which
        !            11:  * you should have received as part of this distribution. The terms
        !            12:  * are also available at https://curl.haxx.se/docs/copyright.html.
        !            13:  *
        !            14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            15:  * copies of the Software, and permit persons to whom the Software is
        !            16:  * furnished to do so, under the terms of the COPYING file.
        !            17:  *
        !            18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            19:  * KIND, either express or implied.
        !            20:  *
        !            21:  ***************************************************************************/
        !            22: 
        !            23: #include "curl_setup.h"
        !            24: 
        !            25: #include "urldata.h"
        !            26: #include <curl/curl.h>
        !            27: #include <stddef.h>
        !            28: 
        !            29: #ifdef HAVE_ZLIB_H
        !            30: #include <zlib.h>
        !            31: #ifdef __SYMBIAN32__
        !            32: /* zlib pollutes the namespace with this definition */
        !            33: #undef WIN32
        !            34: #endif
        !            35: #endif
        !            36: 
        !            37: #ifdef HAVE_BROTLI
        !            38: #include <brotli/decode.h>
        !            39: #endif
        !            40: 
        !            41: #include "sendf.h"
        !            42: #include "http.h"
        !            43: #include "content_encoding.h"
        !            44: #include "strdup.h"
        !            45: #include "strcase.h"
        !            46: #include "curl_memory.h"
        !            47: #include "memdebug.h"
        !            48: 
        !            49: #define CONTENT_ENCODING_DEFAULT  "identity"
        !            50: 
        !            51: #ifndef CURL_DISABLE_HTTP
        !            52: 
        !            53: #define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
        !            54: 
        !            55: 
        !            56: #ifdef HAVE_LIBZ
        !            57: 
        !            58: /* Comment this out if zlib is always going to be at least ver. 1.2.0.4
        !            59:    (doing so will reduce code size slightly). */
        !            60: #define OLD_ZLIB_SUPPORT 1
        !            61: 
        !            62: #define GZIP_MAGIC_0 0x1f
        !            63: #define GZIP_MAGIC_1 0x8b
        !            64: 
        !            65: /* gzip flag byte */
        !            66: #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
        !            67: #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
        !            68: #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
        !            69: #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
        !            70: #define COMMENT      0x10 /* bit 4 set: file comment present */
        !            71: #define RESERVED     0xE0 /* bits 5..7: reserved */
        !            72: 
        !            73: typedef enum {
        !            74:   ZLIB_UNINIT,               /* uninitialized */
        !            75:   ZLIB_INIT,                 /* initialized */
        !            76:   ZLIB_INFLATING,            /* inflating started. */
        !            77:   ZLIB_EXTERNAL_TRAILER,     /* reading external trailer */
        !            78:   ZLIB_GZIP_HEADER,          /* reading gzip header */
        !            79:   ZLIB_GZIP_INFLATING,       /* inflating gzip stream */
        !            80:   ZLIB_INIT_GZIP             /* initialized in transparent gzip mode */
        !            81: } zlibInitState;
        !            82: 
        !            83: /* Writer parameters. */
        !            84: typedef struct {
        !            85:   zlibInitState zlib_init;   /* zlib init state */
        !            86:   uInt trailerlen;           /* Remaining trailer byte count. */
        !            87:   z_stream z;                /* State structure for zlib. */
        !            88: }  zlib_params;
        !            89: 
        !            90: 
        !            91: static voidpf
        !            92: zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
        !            93: {
        !            94:   (void) opaque;
        !            95:   /* not a typo, keep it calloc() */
        !            96:   return (voidpf) calloc(items, size);
        !            97: }
        !            98: 
        !            99: static void
        !           100: zfree_cb(voidpf opaque, voidpf ptr)
        !           101: {
        !           102:   (void) opaque;
        !           103:   free(ptr);
        !           104: }
        !           105: 
        !           106: static CURLcode
        !           107: process_zlib_error(struct connectdata *conn, z_stream *z)
        !           108: {
        !           109:   struct Curl_easy *data = conn->data;
        !           110:   if(z->msg)
        !           111:     failf(data, "Error while processing content unencoding: %s",
        !           112:           z->msg);
        !           113:   else
        !           114:     failf(data, "Error while processing content unencoding: "
        !           115:           "Unknown failure within decompression software.");
        !           116: 
        !           117:   return CURLE_BAD_CONTENT_ENCODING;
        !           118: }
        !           119: 
        !           120: static CURLcode
        !           121: exit_zlib(struct connectdata *conn,
        !           122:           z_stream *z, zlibInitState *zlib_init, CURLcode result)
        !           123: {
        !           124:   if(*zlib_init == ZLIB_GZIP_HEADER)
        !           125:     Curl_safefree(z->next_in);
        !           126: 
        !           127:   if(*zlib_init != ZLIB_UNINIT) {
        !           128:     if(inflateEnd(z) != Z_OK && result == CURLE_OK)
        !           129:       result = process_zlib_error(conn, z);
        !           130:     *zlib_init = ZLIB_UNINIT;
        !           131:   }
        !           132: 
        !           133:   return result;
        !           134: }
        !           135: 
        !           136: static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp)
        !           137: {
        !           138:   z_stream *z = &zp->z;
        !           139:   CURLcode result = CURLE_OK;
        !           140:   uInt len = z->avail_in < zp->trailerlen? z->avail_in: zp->trailerlen;
        !           141: 
        !           142:   /* Consume expected trailer bytes. Terminate stream if exhausted.
        !           143:      Issue an error if unexpected bytes follow. */
        !           144: 
        !           145:   zp->trailerlen -= len;
        !           146:   z->avail_in -= len;
        !           147:   z->next_in += len;
        !           148:   if(z->avail_in)
        !           149:     result = CURLE_WRITE_ERROR;
        !           150:   if(result || !zp->trailerlen)
        !           151:     result = exit_zlib(conn, z, &zp->zlib_init, result);
        !           152:   else {
        !           153:     /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
        !           154:     zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
        !           155:   }
        !           156:   return result;
        !           157: }
        !           158: 
        !           159: static CURLcode inflate_stream(struct connectdata *conn,
        !           160:                                contenc_writer *writer, zlibInitState started)
        !           161: {
        !           162:   zlib_params *zp = (zlib_params *) &writer->params;
        !           163:   z_stream *z = &zp->z;         /* zlib state structure */
        !           164:   uInt nread = z->avail_in;
        !           165:   Bytef *orig_in = z->next_in;
        !           166:   bool done = FALSE;
        !           167:   CURLcode result = CURLE_OK;   /* Curl_client_write status */
        !           168:   char *decomp;                 /* Put the decompressed data here. */
        !           169: 
        !           170:   /* Check state. */
        !           171:   if(zp->zlib_init != ZLIB_INIT &&
        !           172:      zp->zlib_init != ZLIB_INFLATING &&
        !           173:      zp->zlib_init != ZLIB_INIT_GZIP &&
        !           174:      zp->zlib_init != ZLIB_GZIP_INFLATING)
        !           175:     return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
        !           176: 
        !           177:   /* Dynamically allocate a buffer for decompression because it's uncommonly
        !           178:      large to hold on the stack */
        !           179:   decomp = malloc(DSIZ);
        !           180:   if(decomp == NULL)
        !           181:     return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
        !           182: 
        !           183:   /* because the buffer size is fixed, iteratively decompress and transfer to
        !           184:      the client via downstream_write function. */
        !           185:   while(!done) {
        !           186:     int status;                   /* zlib status */
        !           187:     done = TRUE;
        !           188: 
        !           189:     /* (re)set buffer for decompressed output for every iteration */
        !           190:     z->next_out = (Bytef *) decomp;
        !           191:     z->avail_out = DSIZ;
        !           192: 
        !           193: #ifdef Z_BLOCK
        !           194:     /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
        !           195:     status = inflate(z, Z_BLOCK);
        !           196: #else
        !           197:     /* fallback for zlib ver. < 1.2.0.5 */
        !           198:     status = inflate(z, Z_SYNC_FLUSH);
        !           199: #endif
        !           200: 
        !           201:     /* Flush output data if some. */
        !           202:     if(z->avail_out != DSIZ) {
        !           203:       if(status == Z_OK || status == Z_STREAM_END) {
        !           204:         zp->zlib_init = started;      /* Data started. */
        !           205:         result = Curl_unencode_write(conn, writer->downstream, decomp,
        !           206:                                      DSIZ - z->avail_out);
        !           207:         if(result) {
        !           208:           exit_zlib(conn, z, &zp->zlib_init, result);
        !           209:           break;
        !           210:         }
        !           211:       }
        !           212:     }
        !           213: 
        !           214:     /* Dispatch by inflate() status. */
        !           215:     switch(status) {
        !           216:     case Z_OK:
        !           217:       /* Always loop: there may be unflushed latched data in zlib state. */
        !           218:       done = FALSE;
        !           219:       break;
        !           220:     case Z_BUF_ERROR:
        !           221:       /* No more data to flush: just exit loop. */
        !           222:       break;
        !           223:     case Z_STREAM_END:
        !           224:       result = process_trailer(conn, zp);
        !           225:       break;
        !           226:     case Z_DATA_ERROR:
        !           227:       /* some servers seem to not generate zlib headers, so this is an attempt
        !           228:          to fix and continue anyway */
        !           229:       if(zp->zlib_init == ZLIB_INIT) {
        !           230:         /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
        !           231:         (void) inflateEnd(z);     /* don't care about the return code */
        !           232:         if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
        !           233:           z->next_in = orig_in;
        !           234:           z->avail_in = nread;
        !           235:           zp->zlib_init = ZLIB_INFLATING;
        !           236:           zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
        !           237:           done = FALSE;
        !           238:           break;
        !           239:         }
        !           240:         zp->zlib_init = ZLIB_UNINIT;    /* inflateEnd() already called. */
        !           241:       }
        !           242:       /* FALLTHROUGH */
        !           243:     default:
        !           244:       result = exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
        !           245:       break;
        !           246:     }
        !           247:   }
        !           248:   free(decomp);
        !           249: 
        !           250:   /* We're about to leave this call so the `nread' data bytes won't be seen
        !           251:      again. If we are in a state that would wrongly allow restart in raw mode
        !           252:      at the next call, assume output has already started. */
        !           253:   if(nread && zp->zlib_init == ZLIB_INIT)
        !           254:     zp->zlib_init = started;      /* Cannot restart anymore. */
        !           255: 
        !           256:   return result;
        !           257: }
        !           258: 
        !           259: 
        !           260: /* Deflate handler. */
        !           261: static CURLcode deflate_init_writer(struct connectdata *conn,
        !           262:                                     contenc_writer *writer)
        !           263: {
        !           264:   zlib_params *zp = (zlib_params *) &writer->params;
        !           265:   z_stream *z = &zp->z;     /* zlib state structure */
        !           266: 
        !           267:   if(!writer->downstream)
        !           268:     return CURLE_WRITE_ERROR;
        !           269: 
        !           270:   /* Initialize zlib */
        !           271:   z->zalloc = (alloc_func) zalloc_cb;
        !           272:   z->zfree = (free_func) zfree_cb;
        !           273: 
        !           274:   if(inflateInit(z) != Z_OK)
        !           275:     return process_zlib_error(conn, z);
        !           276:   zp->zlib_init = ZLIB_INIT;
        !           277:   return CURLE_OK;
        !           278: }
        !           279: 
        !           280: static CURLcode deflate_unencode_write(struct connectdata *conn,
        !           281:                                        contenc_writer *writer,
        !           282:                                        const char *buf, size_t nbytes)
        !           283: {
        !           284:   zlib_params *zp = (zlib_params *) &writer->params;
        !           285:   z_stream *z = &zp->z;     /* zlib state structure */
        !           286: 
        !           287:   /* Set the compressed input when this function is called */
        !           288:   z->next_in = (Bytef *) buf;
        !           289:   z->avail_in = (uInt) nbytes;
        !           290: 
        !           291:   if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
        !           292:     return process_trailer(conn, zp);
        !           293: 
        !           294:   /* Now uncompress the data */
        !           295:   return inflate_stream(conn, writer, ZLIB_INFLATING);
        !           296: }
        !           297: 
        !           298: static void deflate_close_writer(struct connectdata *conn,
        !           299:                                  contenc_writer *writer)
        !           300: {
        !           301:   zlib_params *zp = (zlib_params *) &writer->params;
        !           302:   z_stream *z = &zp->z;     /* zlib state structure */
        !           303: 
        !           304:   exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
        !           305: }
        !           306: 
        !           307: static const content_encoding deflate_encoding = {
        !           308:   "deflate",
        !           309:   NULL,
        !           310:   deflate_init_writer,
        !           311:   deflate_unencode_write,
        !           312:   deflate_close_writer,
        !           313:   sizeof(zlib_params)
        !           314: };
        !           315: 
        !           316: 
        !           317: /* Gzip handler. */
        !           318: static CURLcode gzip_init_writer(struct connectdata *conn,
        !           319:                                  contenc_writer *writer)
        !           320: {
        !           321:   zlib_params *zp = (zlib_params *) &writer->params;
        !           322:   z_stream *z = &zp->z;     /* zlib state structure */
        !           323: 
        !           324:   if(!writer->downstream)
        !           325:     return CURLE_WRITE_ERROR;
        !           326: 
        !           327:   /* Initialize zlib */
        !           328:   z->zalloc = (alloc_func) zalloc_cb;
        !           329:   z->zfree = (free_func) zfree_cb;
        !           330: 
        !           331:   if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
        !           332:     /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
        !           333:     if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
        !           334:       return process_zlib_error(conn, z);
        !           335:     }
        !           336:     zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
        !           337:   }
        !           338:   else {
        !           339:     /* we must parse the gzip header and trailer ourselves */
        !           340:     if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
        !           341:       return process_zlib_error(conn, z);
        !           342:     }
        !           343:     zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
        !           344:     zp->zlib_init = ZLIB_INIT; /* Initial call state */
        !           345:   }
        !           346: 
        !           347:   return CURLE_OK;
        !           348: }
        !           349: 
        !           350: #ifdef OLD_ZLIB_SUPPORT
        !           351: /* Skip over the gzip header */
        !           352: static enum {
        !           353:   GZIP_OK,
        !           354:   GZIP_BAD,
        !           355:   GZIP_UNDERFLOW
        !           356: } check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
        !           357: {
        !           358:   int method, flags;
        !           359:   const ssize_t totallen = len;
        !           360: 
        !           361:   /* The shortest header is 10 bytes */
        !           362:   if(len < 10)
        !           363:     return GZIP_UNDERFLOW;
        !           364: 
        !           365:   if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
        !           366:     return GZIP_BAD;
        !           367: 
        !           368:   method = data[2];
        !           369:   flags = data[3];
        !           370: 
        !           371:   if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
        !           372:     /* Can't handle this compression method or unknown flag */
        !           373:     return GZIP_BAD;
        !           374:   }
        !           375: 
        !           376:   /* Skip over time, xflags, OS code and all previous bytes */
        !           377:   len -= 10;
        !           378:   data += 10;
        !           379: 
        !           380:   if(flags & EXTRA_FIELD) {
        !           381:     ssize_t extra_len;
        !           382: 
        !           383:     if(len < 2)
        !           384:       return GZIP_UNDERFLOW;
        !           385: 
        !           386:     extra_len = (data[1] << 8) | data[0];
        !           387: 
        !           388:     if(len < (extra_len + 2))
        !           389:       return GZIP_UNDERFLOW;
        !           390: 
        !           391:     len -= (extra_len + 2);
        !           392:     data += (extra_len + 2);
        !           393:   }
        !           394: 
        !           395:   if(flags & ORIG_NAME) {
        !           396:     /* Skip over NUL-terminated file name */
        !           397:     while(len && *data) {
        !           398:       --len;
        !           399:       ++data;
        !           400:     }
        !           401:     if(!len || *data)
        !           402:       return GZIP_UNDERFLOW;
        !           403: 
        !           404:     /* Skip over the NUL */
        !           405:     --len;
        !           406:     ++data;
        !           407:   }
        !           408: 
        !           409:   if(flags & COMMENT) {
        !           410:     /* Skip over NUL-terminated comment */
        !           411:     while(len && *data) {
        !           412:       --len;
        !           413:       ++data;
        !           414:     }
        !           415:     if(!len || *data)
        !           416:       return GZIP_UNDERFLOW;
        !           417: 
        !           418:     /* Skip over the NUL */
        !           419:     --len;
        !           420:   }
        !           421: 
        !           422:   if(flags & HEAD_CRC) {
        !           423:     if(len < 2)
        !           424:       return GZIP_UNDERFLOW;
        !           425: 
        !           426:     len -= 2;
        !           427:   }
        !           428: 
        !           429:   *headerlen = totallen - len;
        !           430:   return GZIP_OK;
        !           431: }
        !           432: #endif
        !           433: 
        !           434: static CURLcode gzip_unencode_write(struct connectdata *conn,
        !           435:                                     contenc_writer *writer,
        !           436:                                     const char *buf, size_t nbytes)
        !           437: {
        !           438:   zlib_params *zp = (zlib_params *) &writer->params;
        !           439:   z_stream *z = &zp->z;     /* zlib state structure */
        !           440: 
        !           441:   if(zp->zlib_init == ZLIB_INIT_GZIP) {
        !           442:     /* Let zlib handle the gzip decompression entirely */
        !           443:     z->next_in = (Bytef *) buf;
        !           444:     z->avail_in = (uInt) nbytes;
        !           445:     /* Now uncompress the data */
        !           446:     return inflate_stream(conn, writer, ZLIB_INIT_GZIP);
        !           447:   }
        !           448: 
        !           449: #ifndef OLD_ZLIB_SUPPORT
        !           450:   /* Support for old zlib versions is compiled away and we are running with
        !           451:      an old version, so return an error. */
        !           452:   return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
        !           453: 
        !           454: #else
        !           455:   /* This next mess is to get around the potential case where there isn't
        !           456:    * enough data passed in to skip over the gzip header.  If that happens, we
        !           457:    * malloc a block and copy what we have then wait for the next call.  If
        !           458:    * there still isn't enough (this is definitely a worst-case scenario), we
        !           459:    * make the block bigger, copy the next part in and keep waiting.
        !           460:    *
        !           461:    * This is only required with zlib versions < 1.2.0.4 as newer versions
        !           462:    * can handle the gzip header themselves.
        !           463:    */
        !           464: 
        !           465:   switch(zp->zlib_init) {
        !           466:   /* Skip over gzip header? */
        !           467:   case ZLIB_INIT:
        !           468:   {
        !           469:     /* Initial call state */
        !           470:     ssize_t hlen;
        !           471: 
        !           472:     switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
        !           473:     case GZIP_OK:
        !           474:       z->next_in = (Bytef *) buf + hlen;
        !           475:       z->avail_in = (uInt) (nbytes - hlen);
        !           476:       zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
        !           477:       break;
        !           478: 
        !           479:     case GZIP_UNDERFLOW:
        !           480:       /* We need more data so we can find the end of the gzip header.  It's
        !           481:        * possible that the memory block we malloc here will never be freed if
        !           482:        * the transfer abruptly aborts after this point.  Since it's unlikely
        !           483:        * that circumstances will be right for this code path to be followed in
        !           484:        * the first place, and it's even more unlikely for a transfer to fail
        !           485:        * immediately afterwards, it should seldom be a problem.
        !           486:        */
        !           487:       z->avail_in = (uInt) nbytes;
        !           488:       z->next_in = malloc(z->avail_in);
        !           489:       if(z->next_in == NULL) {
        !           490:         return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
        !           491:       }
        !           492:       memcpy(z->next_in, buf, z->avail_in);
        !           493:       zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
        !           494:       /* We don't have any data to inflate yet */
        !           495:       return CURLE_OK;
        !           496: 
        !           497:     case GZIP_BAD:
        !           498:     default:
        !           499:       return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
        !           500:     }
        !           501: 
        !           502:   }
        !           503:   break;
        !           504: 
        !           505:   case ZLIB_GZIP_HEADER:
        !           506:   {
        !           507:     /* Need more gzip header data state */
        !           508:     ssize_t hlen;
        !           509:     z->avail_in += (uInt) nbytes;
        !           510:     z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
        !           511:     if(z->next_in == NULL) {
        !           512:       return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
        !           513:     }
        !           514:     /* Append the new block of data to the previous one */
        !           515:     memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
        !           516: 
        !           517:     switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
        !           518:     case GZIP_OK:
        !           519:       /* This is the zlib stream data */
        !           520:       free(z->next_in);
        !           521:       /* Don't point into the malloced block since we just freed it */
        !           522:       z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
        !           523:       z->avail_in = (uInt) (z->avail_in - hlen);
        !           524:       zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
        !           525:       break;
        !           526: 
        !           527:     case GZIP_UNDERFLOW:
        !           528:       /* We still don't have any data to inflate! */
        !           529:       return CURLE_OK;
        !           530: 
        !           531:     case GZIP_BAD:
        !           532:     default:
        !           533:       return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
        !           534:     }
        !           535: 
        !           536:   }
        !           537:   break;
        !           538: 
        !           539:   case ZLIB_EXTERNAL_TRAILER:
        !           540:     z->next_in = (Bytef *) buf;
        !           541:     z->avail_in = (uInt) nbytes;
        !           542:     return process_trailer(conn, zp);
        !           543: 
        !           544:   case ZLIB_GZIP_INFLATING:
        !           545:   default:
        !           546:     /* Inflating stream state */
        !           547:     z->next_in = (Bytef *) buf;
        !           548:     z->avail_in = (uInt) nbytes;
        !           549:     break;
        !           550:   }
        !           551: 
        !           552:   if(z->avail_in == 0) {
        !           553:     /* We don't have any data to inflate; wait until next time */
        !           554:     return CURLE_OK;
        !           555:   }
        !           556: 
        !           557:   /* We've parsed the header, now uncompress the data */
        !           558:   return inflate_stream(conn, writer, ZLIB_GZIP_INFLATING);
        !           559: #endif
        !           560: }
        !           561: 
        !           562: static void gzip_close_writer(struct connectdata *conn,
        !           563:                               contenc_writer *writer)
        !           564: {
        !           565:   zlib_params *zp = (zlib_params *) &writer->params;
        !           566:   z_stream *z = &zp->z;     /* zlib state structure */
        !           567: 
        !           568:   exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
        !           569: }
        !           570: 
        !           571: static const content_encoding gzip_encoding = {
        !           572:   "gzip",
        !           573:   "x-gzip",
        !           574:   gzip_init_writer,
        !           575:   gzip_unencode_write,
        !           576:   gzip_close_writer,
        !           577:   sizeof(zlib_params)
        !           578: };
        !           579: 
        !           580: #endif /* HAVE_LIBZ */
        !           581: 
        !           582: 
        !           583: #ifdef HAVE_BROTLI
        !           584: 
        !           585: /* Writer parameters. */
        !           586: typedef struct {
        !           587:   BrotliDecoderState *br;    /* State structure for brotli. */
        !           588: }  brotli_params;
        !           589: 
        !           590: 
        !           591: static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
        !           592: {
        !           593:   switch(be) {
        !           594:   case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:
        !           595:   case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:
        !           596:   case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:
        !           597:   case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:
        !           598:   case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:
        !           599:   case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:
        !           600:   case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:
        !           601:   case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:
        !           602:   case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:
        !           603:   case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:
        !           604:   case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:
        !           605:   case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:
        !           606:   case BROTLI_DECODER_ERROR_FORMAT_PADDING_1:
        !           607:   case BROTLI_DECODER_ERROR_FORMAT_PADDING_2:
        !           608: #ifdef BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY
        !           609:   case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY:
        !           610: #endif
        !           611: #ifdef BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET
        !           612:   case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:
        !           613: #endif
        !           614:   case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:
        !           615:     return CURLE_BAD_CONTENT_ENCODING;
        !           616:   case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:
        !           617:   case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:
        !           618:   case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:
        !           619:   case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:
        !           620:   case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:
        !           621:   case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:
        !           622:     return CURLE_OUT_OF_MEMORY;
        !           623:   default:
        !           624:     break;
        !           625:   }
        !           626:   return CURLE_WRITE_ERROR;
        !           627: }
        !           628: 
        !           629: static CURLcode brotli_init_writer(struct connectdata *conn,
        !           630:                                    contenc_writer *writer)
        !           631: {
        !           632:   brotli_params *bp = (brotli_params *) &writer->params;
        !           633: 
        !           634:   (void) conn;
        !           635: 
        !           636:   if(!writer->downstream)
        !           637:     return CURLE_WRITE_ERROR;
        !           638: 
        !           639:   bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
        !           640:   return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
        !           641: }
        !           642: 
        !           643: static CURLcode brotli_unencode_write(struct connectdata *conn,
        !           644:                                       contenc_writer *writer,
        !           645:                                       const char *buf, size_t nbytes)
        !           646: {
        !           647:   brotli_params *bp = (brotli_params *) &writer->params;
        !           648:   const uint8_t *src = (const uint8_t *) buf;
        !           649:   char *decomp;
        !           650:   uint8_t *dst;
        !           651:   size_t dstleft;
        !           652:   CURLcode result = CURLE_OK;
        !           653:   BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
        !           654: 
        !           655:   if(!bp->br)
        !           656:     return CURLE_WRITE_ERROR;  /* Stream already ended. */
        !           657: 
        !           658:   decomp = malloc(DSIZ);
        !           659:   if(!decomp)
        !           660:     return CURLE_OUT_OF_MEMORY;
        !           661: 
        !           662:   while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
        !           663:         result == CURLE_OK) {
        !           664:     dst = (uint8_t *) decomp;
        !           665:     dstleft = DSIZ;
        !           666:     r = BrotliDecoderDecompressStream(bp->br,
        !           667:                                       &nbytes, &src, &dstleft, &dst, NULL);
        !           668:     result = Curl_unencode_write(conn, writer->downstream,
        !           669:                                  decomp, DSIZ - dstleft);
        !           670:     if(result)
        !           671:       break;
        !           672:     switch(r) {
        !           673:     case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
        !           674:     case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
        !           675:       break;
        !           676:     case BROTLI_DECODER_RESULT_SUCCESS:
        !           677:       BrotliDecoderDestroyInstance(bp->br);
        !           678:       bp->br = NULL;
        !           679:       if(nbytes)
        !           680:         result = CURLE_WRITE_ERROR;
        !           681:       break;
        !           682:     default:
        !           683:       result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br));
        !           684:       break;
        !           685:     }
        !           686:   }
        !           687:   free(decomp);
        !           688:   return result;
        !           689: }
        !           690: 
        !           691: static void brotli_close_writer(struct connectdata *conn,
        !           692:                                 contenc_writer *writer)
        !           693: {
        !           694:   brotli_params *bp = (brotli_params *) &writer->params;
        !           695: 
        !           696:   (void) conn;
        !           697: 
        !           698:   if(bp->br) {
        !           699:     BrotliDecoderDestroyInstance(bp->br);
        !           700:     bp->br = NULL;
        !           701:   }
        !           702: }
        !           703: 
        !           704: static const content_encoding brotli_encoding = {
        !           705:   "br",
        !           706:   NULL,
        !           707:   brotli_init_writer,
        !           708:   brotli_unencode_write,
        !           709:   brotli_close_writer,
        !           710:   sizeof(brotli_params)
        !           711: };
        !           712: #endif
        !           713: 
        !           714: 
        !           715: /* Identity handler. */
        !           716: static CURLcode identity_init_writer(struct connectdata *conn,
        !           717:                                      contenc_writer *writer)
        !           718: {
        !           719:   (void) conn;
        !           720:   return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
        !           721: }
        !           722: 
        !           723: static CURLcode identity_unencode_write(struct connectdata *conn,
        !           724:                                         contenc_writer *writer,
        !           725:                                         const char *buf, size_t nbytes)
        !           726: {
        !           727:   return Curl_unencode_write(conn, writer->downstream, buf, nbytes);
        !           728: }
        !           729: 
        !           730: static void identity_close_writer(struct connectdata *conn,
        !           731:                                   contenc_writer *writer)
        !           732: {
        !           733:   (void) conn;
        !           734:   (void) writer;
        !           735: }
        !           736: 
        !           737: static const content_encoding identity_encoding = {
        !           738:   "identity",
        !           739:   "none",
        !           740:   identity_init_writer,
        !           741:   identity_unencode_write,
        !           742:   identity_close_writer,
        !           743:   0
        !           744: };
        !           745: 
        !           746: 
        !           747: /* supported content encodings table. */
        !           748: static const content_encoding * const encodings[] = {
        !           749:   &identity_encoding,
        !           750: #ifdef HAVE_LIBZ
        !           751:   &deflate_encoding,
        !           752:   &gzip_encoding,
        !           753: #endif
        !           754: #ifdef HAVE_BROTLI
        !           755:   &brotli_encoding,
        !           756: #endif
        !           757:   NULL
        !           758: };
        !           759: 
        !           760: 
        !           761: /* Return a list of comma-separated names of supported encodings. */
        !           762: char *Curl_all_content_encodings(void)
        !           763: {
        !           764:   size_t len = 0;
        !           765:   const content_encoding * const *cep;
        !           766:   const content_encoding *ce;
        !           767:   char *ace;
        !           768: 
        !           769:   for(cep = encodings; *cep; cep++) {
        !           770:     ce = *cep;
        !           771:     if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
        !           772:       len += strlen(ce->name) + 2;
        !           773:   }
        !           774: 
        !           775:   if(!len)
        !           776:     return strdup(CONTENT_ENCODING_DEFAULT);
        !           777: 
        !           778:   ace = malloc(len);
        !           779:   if(ace) {
        !           780:     char *p = ace;
        !           781:     for(cep = encodings; *cep; cep++) {
        !           782:       ce = *cep;
        !           783:       if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
        !           784:         strcpy(p, ce->name);
        !           785:         p += strlen(p);
        !           786:         *p++ = ',';
        !           787:         *p++ = ' ';
        !           788:       }
        !           789:     }
        !           790:     p[-2] = '\0';
        !           791:   }
        !           792: 
        !           793:   return ace;
        !           794: }
        !           795: 
        !           796: 
        !           797: /* Real client writer: no downstream. */
        !           798: static CURLcode client_init_writer(struct connectdata *conn,
        !           799:                                    contenc_writer *writer)
        !           800: {
        !           801:   (void) conn;
        !           802:   return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
        !           803: }
        !           804: 
        !           805: static CURLcode client_unencode_write(struct connectdata *conn,
        !           806:                                       contenc_writer *writer,
        !           807:                                       const char *buf, size_t nbytes)
        !           808: {
        !           809:   struct Curl_easy *data = conn->data;
        !           810:   struct SingleRequest *k = &data->req;
        !           811: 
        !           812:   (void) writer;
        !           813: 
        !           814:   if(!nbytes || k->ignorebody)
        !           815:     return CURLE_OK;
        !           816: 
        !           817:   return Curl_client_write(conn, CLIENTWRITE_BODY, (char *) buf, nbytes);
        !           818: }
        !           819: 
        !           820: static void client_close_writer(struct connectdata *conn,
        !           821:                                 contenc_writer *writer)
        !           822: {
        !           823:   (void) conn;
        !           824:   (void) writer;
        !           825: }
        !           826: 
        !           827: static const content_encoding client_encoding = {
        !           828:   NULL,
        !           829:   NULL,
        !           830:   client_init_writer,
        !           831:   client_unencode_write,
        !           832:   client_close_writer,
        !           833:   0
        !           834: };
        !           835: 
        !           836: 
        !           837: /* Deferred error dummy writer. */
        !           838: static CURLcode error_init_writer(struct connectdata *conn,
        !           839:                                   contenc_writer *writer)
        !           840: {
        !           841:   (void) conn;
        !           842:   return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
        !           843: }
        !           844: 
        !           845: static CURLcode error_unencode_write(struct connectdata *conn,
        !           846:                                      contenc_writer *writer,
        !           847:                                      const char *buf, size_t nbytes)
        !           848: {
        !           849:   char *all = Curl_all_content_encodings();
        !           850: 
        !           851:   (void) writer;
        !           852:   (void) buf;
        !           853:   (void) nbytes;
        !           854: 
        !           855:   if(!all)
        !           856:     return CURLE_OUT_OF_MEMORY;
        !           857:   failf(conn->data, "Unrecognized content encoding type. "
        !           858:                     "libcurl understands %s content encodings.", all);
        !           859:   free(all);
        !           860:   return CURLE_BAD_CONTENT_ENCODING;
        !           861: }
        !           862: 
        !           863: static void error_close_writer(struct connectdata *conn,
        !           864:                                contenc_writer *writer)
        !           865: {
        !           866:   (void) conn;
        !           867:   (void) writer;
        !           868: }
        !           869: 
        !           870: static const content_encoding error_encoding = {
        !           871:   NULL,
        !           872:   NULL,
        !           873:   error_init_writer,
        !           874:   error_unencode_write,
        !           875:   error_close_writer,
        !           876:   0
        !           877: };
        !           878: 
        !           879: /* Create an unencoding writer stage using the given handler. */
        !           880: static contenc_writer *new_unencoding_writer(struct connectdata *conn,
        !           881:                                              const content_encoding *handler,
        !           882:                                              contenc_writer *downstream)
        !           883: {
        !           884:   size_t sz = offsetof(contenc_writer, params) + handler->paramsize;
        !           885:   contenc_writer *writer = (contenc_writer *) calloc(1, sz);
        !           886: 
        !           887:   if(writer) {
        !           888:     writer->handler = handler;
        !           889:     writer->downstream = downstream;
        !           890:     if(handler->init_writer(conn, writer)) {
        !           891:       free(writer);
        !           892:       writer = NULL;
        !           893:     }
        !           894:   }
        !           895: 
        !           896:   return writer;
        !           897: }
        !           898: 
        !           899: /* Write data using an unencoding writer stack. */
        !           900: CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
        !           901:                              const char *buf, size_t nbytes)
        !           902: {
        !           903:   if(!nbytes)
        !           904:     return CURLE_OK;
        !           905:   return writer->handler->unencode_write(conn, writer, buf, nbytes);
        !           906: }
        !           907: 
        !           908: /* Close and clean-up the connection's writer stack. */
        !           909: void Curl_unencode_cleanup(struct connectdata *conn)
        !           910: {
        !           911:   struct Curl_easy *data = conn->data;
        !           912:   struct SingleRequest *k = &data->req;
        !           913:   contenc_writer *writer = k->writer_stack;
        !           914: 
        !           915:   while(writer) {
        !           916:     k->writer_stack = writer->downstream;
        !           917:     writer->handler->close_writer(conn, writer);
        !           918:     free(writer);
        !           919:     writer = k->writer_stack;
        !           920:   }
        !           921: }
        !           922: 
        !           923: /* Find the content encoding by name. */
        !           924: static const content_encoding *find_encoding(const char *name, size_t len)
        !           925: {
        !           926:   const content_encoding * const *cep;
        !           927: 
        !           928:   for(cep = encodings; *cep; cep++) {
        !           929:     const content_encoding *ce = *cep;
        !           930:     if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
        !           931:        (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
        !           932:       return ce;
        !           933:   }
        !           934:   return NULL;
        !           935: }
        !           936: 
        !           937: /* Set-up the unencoding stack from the Content-Encoding header value.
        !           938:  * See RFC 7231 section 3.1.2.2. */
        !           939: CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
        !           940:                                      const char *enclist, int maybechunked)
        !           941: {
        !           942:   struct Curl_easy *data = conn->data;
        !           943:   struct SingleRequest *k = &data->req;
        !           944: 
        !           945:   do {
        !           946:     const char *name;
        !           947:     size_t namelen;
        !           948: 
        !           949:     /* Parse a single encoding name. */
        !           950:     while(ISSPACE(*enclist) || *enclist == ',')
        !           951:       enclist++;
        !           952: 
        !           953:     name = enclist;
        !           954: 
        !           955:     for(namelen = 0; *enclist && *enclist != ','; enclist++)
        !           956:       if(!ISSPACE(*enclist))
        !           957:         namelen = enclist - name + 1;
        !           958: 
        !           959:     /* Special case: chunked encoding is handled at the reader level. */
        !           960:     if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) {
        !           961:       k->chunk = TRUE;             /* chunks coming our way. */
        !           962:       Curl_httpchunk_init(conn);   /* init our chunky engine. */
        !           963:     }
        !           964:     else if(namelen) {
        !           965:       const content_encoding *encoding = find_encoding(name, namelen);
        !           966:       contenc_writer *writer;
        !           967: 
        !           968:       if(!k->writer_stack) {
        !           969:         k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL);
        !           970: 
        !           971:         if(!k->writer_stack)
        !           972:           return CURLE_OUT_OF_MEMORY;
        !           973:       }
        !           974: 
        !           975:       if(!encoding)
        !           976:         encoding = &error_encoding;  /* Defer error at stack use. */
        !           977: 
        !           978:       /* Stack the unencoding stage. */
        !           979:       writer = new_unencoding_writer(conn, encoding, k->writer_stack);
        !           980:       if(!writer)
        !           981:         return CURLE_OUT_OF_MEMORY;
        !           982:       k->writer_stack = writer;
        !           983:     }
        !           984:   } while(*enclist);
        !           985: 
        !           986:   return CURLE_OK;
        !           987: }
        !           988: 
        !           989: #else
        !           990: /* Stubs for builds without HTTP. */
        !           991: CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
        !           992:                                      const char *enclist, int maybechunked)
        !           993: {
        !           994:   (void) conn;
        !           995:   (void) enclist;
        !           996:   (void) maybechunked;
        !           997:   return CURLE_NOT_BUILT_IN;
        !           998: }
        !           999: 
        !          1000: CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
        !          1001:                              const char *buf, size_t nbytes)
        !          1002: {
        !          1003:   (void) conn;
        !          1004:   (void) writer;
        !          1005:   (void) buf;
        !          1006:   (void) nbytes;
        !          1007:   return CURLE_NOT_BUILT_IN;
        !          1008: }
        !          1009: 
        !          1010: void Curl_unencode_cleanup(struct connectdata *conn)
        !          1011: {
        !          1012:   (void) conn;
        !          1013: }
        !          1014: 
        !          1015: char *Curl_all_content_encodings(void)
        !          1016: {
        !          1017:   return strdup(CONTENT_ENCODING_DEFAULT);  /* Satisfy caller. */
        !          1018: }
        !          1019: 
        !          1020: #endif /* CURL_DISABLE_HTTP */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>