Exemple #1
0
CURLcode
Curl_unencode_gzip_write(struct SessionHandle *data,
                         struct Curl_transfer_keeper *k,
                         ssize_t nread)
{
  int status;                   /* zlib status */
  int result;                   /* Curl_client_write status */
  char decomp[DSIZ];            /* Put the decompressed data here. */
  z_stream *z = &k->z;          /* zlib state structure */

  /* Initialize zlib? */
  if (!k->zlib_init) {
    z->zalloc = (alloc_func)Z_NULL;
    z->zfree = (free_func)Z_NULL;
    z->opaque = 0;              /* of dubious use 08/27/02 jhrg */
    if (inflateInit2(z, -MAX_WBITS) != Z_OK)
      return process_zlib_error(data, z);
    k->zlib_init = 1;   /* Initial call state */
  }

  /* This next mess is to get around the potential case where there isn't
  enough data passed in to skip over the gzip header.  If that happens,
  we malloc a block and copy what we have then wait for the next call.  If
  there still isn't enough (this is definitely a worst-case scenario), we
  make the block bigger, copy the next part in and keep waiting. */

  /* Skip over gzip header? */
  if (k->zlib_init == 1) {
    /* Initial call state */
    ssize_t hlen;

    switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
    case GZIP_OK:
      z->next_in = (Bytef *)k->str + hlen;
      z->avail_in = nread - hlen;
      k->zlib_init = 3; /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We need more data so we can find the end of the gzip header.
      It's possible that the memory block we malloc here will never be
      freed if the transfer abruptly aborts after this point.  Since it's
      unlikely that circumstances will be right for this code path to be
      followed in the first place, and it's even more unlikely for a transfer
      to fail immediately afterwards, it should seldom be a problem. */
      z->avail_in = nread;
      z->next_in = malloc(z->avail_in);
      if (z->next_in == NULL) {
        return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
      }
      memcpy(z->next_in, k->str, z->avail_in);
      k->zlib_init = 2;   /* Need more gzip header data state */
      /* We don't have any data to inflate yet */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
    }

  }
  else if (k->zlib_init == 2) {
    /* Need more gzip header data state */
    ssize_t hlen;
    unsigned char *oldblock = z->next_in;

    z->avail_in += nread;
    z->next_in = realloc(z->next_in, z->avail_in);
    if (z->next_in == NULL) {
      free(oldblock);
      return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
    }
    /* Append the new block of data to the previous one */
    memcpy(z->next_in + z->avail_in - nread, k->str, nread);

    switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
    case GZIP_OK:
      /* This is the zlib stream data */
      free(z->next_in);
      /* Don't point into the malloced block since we just freed it */
      z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
      z->avail_in = z->avail_in - hlen;
      k->zlib_init = 3;   /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We still don't have any data to inflate! */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      free(z->next_in);
      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
    }

  }
  else {
    /* Inflating stream state */
    z->next_in = (Bytef *)k->str;
    z->avail_in = nread;
  }

  if (z->avail_in == 0) {
    /* We don't have any data to inflate; wait until next time */
    return CURLE_OK;
  }

  /* because the buffer size is fixed, iteratively decompress
     and transfer to the client via client_write. */
  for (;;) {
    /* (re)set buffer for decompressed output for every iteration */
    z->next_out = (Bytef *)&decomp[0];
    z->avail_out = DSIZ;

    status = inflate(z, Z_SYNC_FLUSH);
    if (status == Z_OK || status == Z_STREAM_END) {
      if(DSIZ - z->avail_out) {
        result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
                                   DSIZ - z->avail_out);
        /* if !CURLE_OK, clean up, return */
        if (result)
          return exit_zlib(z, &k->zlib_init, result);
      }

      /* Done?; clean up, return */
      /* We should really check the gzip CRC here */
      if (status == Z_STREAM_END) {
        if (inflateEnd(z) == Z_OK)
          return exit_zlib(z, &k->zlib_init, result);
        else
          return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
      }

      /* Done with these bytes, exit */
      if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
        return result;
    }
    else {                      /* Error; exit loop, handle below */
      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
    }
  }
}
Exemple #2
0
static CURLcode gzip_unencode_write(struct connectdata *conn,
                                    contenc_writer *writer,
                                    const char *buf, size_t nbytes)
{
  zlib_params *zp = (zlib_params *) &writer->params;
  z_stream *z = &zp->z;     /* zlib state structure */

  if(zp->zlib_init == ZLIB_INIT_GZIP) {
    /* Let zlib handle the gzip decompression entirely */
    z->next_in = (Bytef *) buf;
    z->avail_in = (uInt) nbytes;
    /* Now uncompress the data */
    return inflate_stream(conn, writer, ZLIB_INIT_GZIP);
  }

#ifndef OLD_ZLIB_SUPPORT
  /* Support for old zlib versions is compiled away and we are running with
     an old version, so return an error. */
  return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);

#else
  /* This next mess is to get around the potential case where there isn't
   * enough data passed in to skip over the gzip header.  If that happens, we
   * malloc a block and copy what we have then wait for the next call.  If
   * there still isn't enough (this is definitely a worst-case scenario), we
   * make the block bigger, copy the next part in and keep waiting.
   *
   * This is only required with zlib versions < 1.2.0.4 as newer versions
   * can handle the gzip header themselves.
   */

  switch(zp->zlib_init) {
  /* Skip over gzip header? */
  case ZLIB_INIT:
  {
    /* Initial call state */
    ssize_t hlen;

    switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
    case GZIP_OK:
      z->next_in = (Bytef *) buf + hlen;
      z->avail_in = (uInt) (nbytes - hlen);
      zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We need more data so we can find the end of the gzip header.  It's
       * possible that the memory block we malloc here will never be freed if
       * the transfer abruptly aborts after this point.  Since it's unlikely
       * that circumstances will be right for this code path to be followed in
       * the first place, and it's even more unlikely for a transfer to fail
       * immediately afterwards, it should seldom be a problem.
       */
      z->avail_in = (uInt) nbytes;
      z->next_in = malloc(z->avail_in);
      if(z->next_in == NULL) {
        return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
      }
      memcpy(z->next_in, buf, z->avail_in);
      zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
      /* We don't have any data to inflate yet */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
    }

  }
  break;

  case ZLIB_GZIP_HEADER:
  {
    /* Need more gzip header data state */
    ssize_t hlen;
    z->avail_in += (uInt) nbytes;
    z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
    if(z->next_in == NULL) {
      return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
    }
    /* Append the new block of data to the previous one */
    memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);

    switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
    case GZIP_OK:
      /* This is the zlib stream data */
      free(z->next_in);
      /* Don't point into the malloced block since we just freed it */
      z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
      z->avail_in = (uInt) (z->avail_in - hlen);
      zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We still don't have any data to inflate! */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
    }

  }
  break;

  case ZLIB_GZIP_TRAILER:
    z->next_in = (Bytef *) buf;
    z->avail_in = (uInt) nbytes;
    return process_trailer(conn, zp);

  case ZLIB_GZIP_INFLATING:
  default:
    /* Inflating stream state */
    z->next_in = (Bytef *) buf;
    z->avail_in = (uInt) nbytes;
    break;
  }

  if(z->avail_in == 0) {
    /* We don't have any data to inflate; wait until next time */
    return CURLE_OK;
  }

  /* We've parsed the header, now uncompress the data */
  return inflate_stream(conn, writer, ZLIB_GZIP_INFLATING);
#endif
}
CURLcode
Curl_unencode_gzip_write(struct connectdata *conn,
                         struct SingleRequest *k,
                         ssize_t nread)
{
  z_stream *z = &k->z;          /* zlib state structure */

  /* Initialize zlib? */
  if(k->zlib_init == ZLIB_UNINIT) {
    z->zalloc = (alloc_func)Z_NULL;
    z->zfree = (free_func)Z_NULL;
    z->opaque = 0;
    z->next_in = NULL;
    z->avail_in = 0;

    if(strcmp(ZLIB_VERSION, "1.2.0.4") >= 0) {
        /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
        if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
          return process_zlib_error(conn, z);
        }
        k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */

    } else {
        /* we must parse the gzip header ourselves */
        if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
          return process_zlib_error(conn, z);
        }
        k->zlib_init = ZLIB_INIT;   /* Initial call state */
    }
  }

  if(k->zlib_init == ZLIB_INIT_GZIP) {
     /* Let zlib handle the gzip decompression entirely */
     z->next_in = (Bytef *)k->str;
     z->avail_in = (uInt)nread;
     /* Now uncompress the data */
     return inflate_stream(conn, k);
  }

#ifndef OLD_ZLIB_SUPPORT
  /* Support for old zlib versions is compiled away and we are running with
     an old version, so return an error. */
  return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND);

#else
  /* This next mess is to get around the potential case where there isn't
   * enough data passed in to skip over the gzip header.  If that happens, we
   * malloc a block and copy what we have then wait for the next call.  If
   * there still isn't enough (this is definitely a worst-case scenario), we
   * make the block bigger, copy the next part in and keep waiting.
   *
   * This is only required with zlib versions < 1.2.0.4 as newer versions
   * can handle the gzip header themselves.
   */

  switch (k->zlib_init) {
  /* Skip over gzip header? */
  case ZLIB_INIT:
  {
    /* Initial call state */
    ssize_t hlen;

    switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
    case GZIP_OK:
      z->next_in = (Bytef *)k->str + hlen;
      z->avail_in = (uInt)(nread - hlen);
      k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We need more data so we can find the end of the gzip header.  It's
       * possible that the memory block we malloc here will never be freed if
       * the transfer abruptly aborts after this point.  Since it's unlikely
       * that circumstances will be right for this code path to be followed in
       * the first place, and it's even more unlikely for a transfer to fail
       * immediately afterwards, it should seldom be a problem.
       */
      z->avail_in = (uInt)nread;
      z->next_in = (curlNamespace::z_Bytef *) malloc(z->avail_in);
      if(z->next_in == NULL) {
        return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
      }
      memcpy(z->next_in, k->str, z->avail_in);
      k->zlib_init = ZLIB_GZIP_HEADER;   /* Need more gzip header data state */
      /* We don't have any data to inflate yet */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
    }

  }
  break;

  case ZLIB_GZIP_HEADER:
  {
    /* Need more gzip header data state */
    ssize_t hlen;
    unsigned char *oldblock = z->next_in;

    z->avail_in += nread;
    z->next_in = (curlNamespace::z_Bytef *) realloc(z->next_in, z->avail_in);
    if(z->next_in == NULL) {
      free(oldblock);
      return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
    }
    /* Append the new block of data to the previous one */
    memcpy(z->next_in + z->avail_in - nread, k->str, nread);

    switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
    case GZIP_OK:
      /* This is the zlib stream data */
      free(z->next_in);
      /* Don't point into the malloced block since we just freed it */
      z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
      z->avail_in = (uInt)(z->avail_in - hlen);
      k->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We still don't have any data to inflate! */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      free(z->next_in);
      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
    }

  }
  break;

  case ZLIB_GZIP_INFLATING:
  default:
    /* Inflating stream state */
    z->next_in = (Bytef *)k->str;
    z->avail_in = (uInt)nread;
    break;
  }

  if(z->avail_in == 0) {
    /* We don't have any data to inflate; wait until next time */
    return CURLE_OK;
  }

  /* We've parsed the header, now uncompress the data */
  return inflate_stream(conn, k);
#endif
}
Exemple #4
0
/* Inflate the  compressed data and check that the decompressed data agrees with the input data */
int inflate_check(uint8_t * z_buf, int z_size, uint8_t * in_buf, int in_size)
{
	/* Test inflate with reference inflate */

	int ret = 0;
	struct inflate_state gstream;
	uint32_t test_size = in_size;
	uint8_t *test_buf = NULL;
	int mem_result = 0;

	assert(in_buf != NULL);

	if (in_size > 0) {
		test_buf = malloc(test_size);

		if (test_buf == NULL)
			return MALLOC_FAILED;
	}
	if (test_buf != NULL)
		memset(test_buf, 0xff, test_size);

#ifndef DEFLATE
	int gzip_hdr_result, gzip_trl_result;

	gzip_hdr_result = check_gzip_header(z_buf);
	z_buf += gzip_hdr_bytes;
	z_size -= gzip_hdr_bytes;
#endif

	igzip_inflate_init(&gstream, z_buf, z_size, test_buf, test_size);
	ret = igzip_inflate(&gstream);

	if (test_buf != NULL)
		mem_result = memcmp(in_buf, test_buf, in_size);

#ifdef VERBOSE
	int i;
	if (mem_result)
		for (i = 0; i < in_size; i++) {
			if (in_buf[i] != test_buf[i]) {
				printf("First incorrect data at 0x%x of 0x%x, 0x%x != 0x%x\n",
				       i, in_size, in_buf[i], test_buf[i]);
				break;
			}
		}
#endif

#ifndef DEFLATE
	gzip_trl_result = check_gzip_trl(&gstream);
	gstream.in_buffer.avail_in -= gzip_trl_bytes;
	gstream.in_buffer.next_in += gzip_trl_bytes;
#endif

	if (test_buf != NULL)
		free(test_buf);

	switch (ret) {
	case 0:
		break;
	case END_OF_INPUT:
		return INFLATE_END_OF_INPUT;
		break;
	case INVALID_BLOCK_HEADER:
		return INFLATE_INVALID_BLOCK_HEADER;
		break;
	case INVALID_SYMBOL:
		return INFLATE_INVALID_SYMBOL;
		break;
	case OUT_BUFFER_OVERFLOW:
		return INFLATE_OUT_BUFFER_OVERFLOW;
		break;
	case INVALID_NON_COMPRESSED_BLOCK_LENGTH:
		return INFLATE_INVALID_NON_COMPRESSED_BLOCK_LENGTH;
		break;
	case INVALID_LOOK_BACK_DISTANCE:
		return INFLATE_INVALID_LOOK_BACK_DISTANCE;
		break;
	default:
		return INFLATE_GENERAL_ERROR;
		break;
	}

	if (gstream.in_buffer.avail_in != 0)
		return INFLATE_LEFTOVER_INPUT;

	if (gstream.out_buffer.total_out != in_size)
		return INFLATE_INCORRECT_OUTPUT_SIZE;

	if (mem_result)
		return RESULT_ERROR;

#ifndef DEFLATE
	if (gzip_hdr_result)
		return INVALID_GZIP_HEADER;

	if (gzip_trl_result)
		return INCORRECT_GZIP_TRAILER;
#endif

	return 0;
}