links

lynx-like text mode web browser
git clone anongit@rnpnr.xyz:links.git
Log | Files | Refs | Feed | README | LICENSE

compress.c (10322B)


      1 #include "links.h"
      2 
      3 #include <zlib.h>
      4 
      5 int decompressed_cache_size = 0;
      6 
      7 static int
      8 display_error(struct terminal *term, unsigned char *msg, int *errp)
      9 {
     10 	if (errp)
     11 		*errp = 1;
     12 	if (!term)
     13 		return 0;
     14 	if (!errp)
     15 		if (find_msg_box(term, msg, NULL, NULL))
     16 			return 0;
     17 	return 1;
     18 }
     19 
     20 static void
     21 decoder_memory_init(unsigned char **p, size_t *size, off_t init_length)
     22 {
     23 	if (init_length > 0 && init_length < INT_MAX)
     24 		*size = (int)init_length;
     25 	else
     26 		*size = 4096;
     27 	*p = xmalloc(*size);
     28 }
     29 
     30 static int
     31 decoder_memory_expand(unsigned char **p, size_t size, size_t *addsize)
     32 {
     33 	size_t add = size / 4 + 1;
     34 	if (size + add < size) {
     35 		if (add > 1)
     36 			add >>= 1;
     37 		else
     38 			overalloc();
     39 	}
     40 	*p = xrealloc(*p, size + add);
     41 	*addsize = add;
     42 	return 0;
     43 }
     44 
     45 static void
     46 decompress_error(struct terminal *term, struct cache_entry *ce,
     47                  unsigned char *lib, unsigned char *msg, int *errp)
     48 {
     49 	unsigned char *u, *server;
     50 	if ((u = parse_http_header(ce->head, cast_uchar "Content-Encoding",
     51 	                           NULL))) {
     52 		free(u);
     53 		if ((server = get_host_name(ce->url))) {
     54 			add_blacklist_entry(server, BL_NO_COMPRESSION);
     55 			free(server);
     56 		}
     57 	}
     58 	if (!display_error(term, TEXT_(T_DECOMPRESSION_ERROR), errp))
     59 		return;
     60 	u = display_url(term, ce->url, 1);
     61 	msg_box(term, getml(u, NULL), TEXT_(T_DECOMPRESSION_ERROR), AL_CENTER,
     62 	        TEXT_(T_ERROR_DECOMPRESSING_), u, TEXT_(T__wITH_), lib,
     63 	        cast_uchar ": ", msg, MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL),
     64 	        msg_box_null, B_ENTER | B_ESC);
     65 }
     66 
     67 static int
     68 decode_gzip(struct terminal *term, struct cache_entry *ce, int defl, int *errp)
     69 {
     70 	unsigned char err;
     71 	unsigned char memory_error;
     72 	unsigned char skip_gzip_header;
     73 	unsigned char old_zlib;
     74 	z_stream z;
     75 	off_t offset;
     76 	int r;
     77 	unsigned char *p;
     78 	struct fragment *f = NULL;
     79 	struct list_head *lf;
     80 	size_t size;
     81 
     82 retry_after_memory_error:
     83 	memory_error = 0;
     84 	decoder_memory_init(&p, &size, ce->length);
     85 init_again:
     86 	err = 0;
     87 	skip_gzip_header = 0;
     88 	old_zlib = 0;
     89 	memset(&z, 0, sizeof(z));
     90 	z.next_in = NULL;
     91 	z.avail_in = 0;
     92 	z.next_out = p;
     93 	z.avail_out = (unsigned)size;
     94 	z.zalloc = NULL;
     95 	z.zfree = NULL;
     96 	z.opaque = NULL;
     97 	r = inflateInit2(&z, defl == 1 ? 15 : defl == 2 ? -15 : 15 + 16);
     98 init_failed:
     99 	switch (r) {
    100 	case Z_OK:
    101 		break;
    102 	case Z_MEM_ERROR:
    103 		memory_error = 1;
    104 		err = 1;
    105 		goto after_inflateend;
    106 	case Z_STREAM_ERROR:
    107 		if (!defl && !old_zlib) {
    108 			if (defrag_entry(ce)) {
    109 				memory_error = 1;
    110 				err = 1;
    111 				goto after_inflateend;
    112 			}
    113 			r = inflateInit2(&z, -15);
    114 			skip_gzip_header = 1;
    115 			old_zlib = 1;
    116 			goto init_failed;
    117 		}
    118 		decompress_error(term, ce, cast_uchar "zlib",
    119 		                 z.msg ? (unsigned char *)z.msg
    120 		                       : (unsigned char *)"Invalid parameter",
    121 		                 errp);
    122 		err = 1;
    123 		goto after_inflateend;
    124 	case Z_VERSION_ERROR:
    125 		decompress_error(term, ce, cast_uchar "zlib",
    126 		                 z.msg ? (unsigned char *)z.msg
    127 		                       : (unsigned char *)"Bad zlib version",
    128 		                 errp);
    129 		err = 1;
    130 		goto after_inflateend;
    131 	default:
    132 		decompress_error(
    133 		    term, ce, cast_uchar "zlib",
    134 		    z.msg ? (unsigned char *)z.msg
    135 			  : (unsigned char
    136 		                 *)"Unknown return value on inflateInit2",
    137 		    errp);
    138 		err = 1;
    139 		goto after_inflateend;
    140 	}
    141 	offset = 0;
    142 	foreach (struct fragment, f, lf, ce->frag) {
    143 		if (f->offset != offset)
    144 			break;
    145 		z.next_in = f->data;
    146 		z.avail_in = (unsigned)f->length;
    147 		if ((off_t)z.avail_in != f->length)
    148 			overalloc();
    149 repeat_frag:
    150 		if (skip_gzip_header == 2) {
    151 			if (z.avail_in < 8)
    152 				goto finish;
    153 			z.next_in = (unsigned char *)z.next_in + 8;
    154 			z.avail_in -= 8;
    155 			skip_gzip_header = 1;
    156 		}
    157 		if (skip_gzip_header) {
    158 			/* FIXME */
    159 			/* if zlib is old, we have to skip gzip header manually
    160 			   otherwise zlib 1.2.x can do it automatically */
    161 			unsigned char *head = z.next_in;
    162 			unsigned headlen = 10;
    163 			if (z.avail_in <= 11)
    164 				goto finish;
    165 			if (head[0] != 0x1f || head[1] != 0x8b) {
    166 				decompress_error(term, ce, cast_uchar "zlib",
    167 				                 TEXT_(T_COMPRESSED_ERROR),
    168 				                 errp);
    169 				err = 1;
    170 				goto finish;
    171 			}
    172 			if (head[2] != 8 || head[3] & 0xe0) {
    173 				decompress_error(
    174 				    term, ce, cast_uchar "zlib",
    175 				    TEXT_(T_UNKNOWN_COMPRESSION_METHOD), errp);
    176 				err = 1;
    177 				goto finish;
    178 			}
    179 			if (head[3] & 0x04) {
    180 				headlen += 2 + head[10] + (head[11] << 8);
    181 				if (headlen >= z.avail_in)
    182 					goto finish;
    183 			}
    184 			if (head[3] & 0x08)
    185 				do {
    186 					headlen++;
    187 					if (headlen >= z.avail_in)
    188 						goto finish;
    189 				} while (head[headlen - 1]);
    190 			if (head[3] & 0x10)
    191 				do {
    192 					headlen++;
    193 					if (headlen >= z.avail_in)
    194 						goto finish;
    195 				} while (head[headlen - 1]);
    196 			if (head[3] & 0x01) {
    197 				headlen += 2;
    198 				if (headlen >= z.avail_in)
    199 					goto finish;
    200 			}
    201 			z.next_in = (unsigned char *)z.next_in + headlen;
    202 			z.avail_in -= headlen;
    203 			skip_gzip_header = 0;
    204 		}
    205 		r = inflate(&z, f->list_entry.next == &ce->frag ? Z_SYNC_FLUSH
    206 		                                                : Z_NO_FLUSH);
    207 		switch (r) {
    208 		case Z_OK:
    209 		case Z_BUF_ERROR:
    210 			break;
    211 		case Z_STREAM_END:
    212 			r = inflateEnd(&z);
    213 			if (r != Z_OK)
    214 				goto end_failed;
    215 			r = inflateInit2(&z, old_zlib ? -15
    216 			                     : defl   ? 15
    217 			                              : 15 + 16);
    218 			if (r != Z_OK) {
    219 				old_zlib = 0;
    220 				goto init_failed;
    221 			}
    222 			if (old_zlib)
    223 				skip_gzip_header = 2;
    224 			break;
    225 		case Z_NEED_DICT:
    226 		case Z_DATA_ERROR:
    227 			if (defl == 1) {
    228 				defl = 2;
    229 				r = inflateEnd(&z);
    230 				if (r != Z_OK)
    231 					goto end_failed;
    232 				goto init_again;
    233 			}
    234 			decompress_error(term, ce, cast_uchar "zlib",
    235 			                 z.msg ? (unsigned char *)z.msg
    236 			                       : TEXT_(T_COMPRESSED_ERROR),
    237 			                 errp);
    238 			err = 1;
    239 			goto finish;
    240 		case Z_STREAM_ERROR:
    241 			decompress_error(
    242 			    term, ce, cast_uchar "zlib",
    243 			    z.msg
    244 				? (unsigned char *)z.msg
    245 				: (unsigned char *)"Internal error on inflate",
    246 			    errp);
    247 			err = 1;
    248 			goto finish;
    249 		case Z_MEM_ERROR:
    250 			memory_error = 1;
    251 			err = 1;
    252 			goto finish;
    253 		default:
    254 			decompress_error(
    255 			    term, ce, cast_uchar "zlib",
    256 			    z.msg ? (unsigned char *)z.msg
    257 				  : (unsigned char
    258 			                 *)"Unknown return value on inflate",
    259 			    errp);
    260 			err = 1;
    261 			break;
    262 		}
    263 		if (!z.avail_out) {
    264 			size_t addsize;
    265 			decoder_memory_expand(&p, size, &addsize);
    266 			z.next_out = p + size;
    267 			z.avail_out = (unsigned)addsize;
    268 			size += addsize;
    269 		}
    270 		if (z.avail_in)
    271 			goto repeat_frag;
    272 		/* FIXME */
    273 		/* In zlib 1.1.3, inflate(Z_SYNC_FLUSH) doesn't work.
    274 		   The following line fixes it --- for last fragment, loop until
    275 		   we get an eof. */
    276 		if (r == Z_OK && f->list_entry.next == &ce->frag)
    277 			goto repeat_frag;
    278 		offset += f->length;
    279 	}
    280 finish:
    281 	r = inflateEnd(&z);
    282 end_failed:
    283 	switch (r) {
    284 	case Z_OK:
    285 		break;
    286 	case Z_STREAM_ERROR:
    287 		decompress_error(
    288 		    term, ce, cast_uchar "zlib",
    289 		    z.msg ? (unsigned char *)z.msg
    290 			  : (unsigned char *)"Internal error on inflateEnd",
    291 		    errp);
    292 		err = 1;
    293 		break;
    294 	case Z_MEM_ERROR:
    295 		memory_error = 1;
    296 		err = 1;
    297 		break;
    298 	default:
    299 		decompress_error(
    300 		    term, ce, cast_uchar "zlib",
    301 		    z.msg
    302 			? (unsigned char *)z.msg
    303 			: (unsigned char *)"Unknown return value on inflateEnd",
    304 		    errp);
    305 		err = 1;
    306 		break;
    307 	}
    308 after_inflateend:
    309 	if (memory_error) {
    310 		free(p);
    311 		if (out_of_memory())
    312 			goto retry_after_memory_error;
    313 		decompress_error(term, ce, cast_uchar "zlib",
    314 		                 z.msg ? (unsigned char *)z.msg
    315 		                       : TEXT_(T_OUT_OF_MEMORY),
    316 		                 errp);
    317 		return 1;
    318 	}
    319 	if (err && (unsigned char *)z.next_out == p) {
    320 		free(p);
    321 		return 1;
    322 	}
    323 	ce->decompressed = p;
    324 	ce->decompressed_len = (unsigned char *)z.next_out - (unsigned char *)p;
    325 	decompressed_cache_size += ce->decompressed_len;
    326 	ce->decompressed = xrealloc(ce->decompressed, ce->decompressed_len);
    327 	return 0;
    328 }
    329 
    330 int
    331 get_file_by_term(struct terminal *term, struct cache_entry *ce,
    332                  unsigned char **start, size_t *len, int *errp)
    333 {
    334 	unsigned char *enc;
    335 	struct fragment *fr;
    336 	int e;
    337 	if (errp)
    338 		*errp = 0;
    339 	*start = NULL;
    340 	*len = 0;
    341 	if (!ce)
    342 		return 1;
    343 	if (ce->decompressed) {
    344 return_decompressed:
    345 		*start = ce->decompressed;
    346 		*len = ce->decompressed_len;
    347 		return 0;
    348 	}
    349 	enc = get_content_encoding(ce->head, ce->url, 0);
    350 	if (enc) {
    351 		if (!casestrcmp(enc, cast_uchar "gzip")
    352 		    || !casestrcmp(enc, cast_uchar "x-gzip")
    353 		    || !casestrcmp(enc, cast_uchar "deflate")) {
    354 			int defl = !casestrcmp(enc, cast_uchar "deflate");
    355 			free(enc);
    356 			if (decode_gzip(term, ce, defl, errp))
    357 				goto uncompressed;
    358 			goto return_decompressed;
    359 		}
    360 		free(enc);
    361 		goto uncompressed;
    362 	}
    363 uncompressed:
    364 	if ((e = defrag_entry(ce)) < 0) {
    365 		unsigned char *msg = get_err_msg(e);
    366 		if (display_error(term, TEXT_(T_ERROR), errp)) {
    367 			unsigned char *u = display_url(term, ce->url, 1);
    368 			msg_box(term, getml(u, NULL), TEXT_(T_ERROR), AL_CENTER,
    369 			        TEXT_(T_ERROR_LOADING), cast_uchar " ", u,
    370 			        cast_uchar ":\n\n", msg, MSG_BOX_END, NULL, 1,
    371 			        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
    372 		}
    373 	}
    374 	if (list_empty(ce->frag))
    375 		return 1;
    376 	fr = list_struct(ce->frag.next, struct fragment);
    377 	if (fr->offset || !fr->length)
    378 		return 1;
    379 	*start = fr->data;
    380 	*len = fr->length;
    381 	return 0;
    382 }
    383 
    384 int
    385 get_file(struct object_request *o, unsigned char **start, size_t *len)
    386 {
    387 	struct terminal *term;
    388 	*start = NULL;
    389 	*len = 0;
    390 	if (!o)
    391 		return 1;
    392 	term = find_terminal(o->term);
    393 	return get_file_by_term(term, o->ce, start, len, NULL);
    394 }
    395 
    396 void
    397 free_decompressed_data(struct cache_entry *e)
    398 {
    399 	if (e->decompressed) {
    400 		if (decompressed_cache_size < e->decompressed_len)
    401 			internal("free_decompressed_data: "
    402 			         "decompressed_cache_size underflow %lu, %lu",
    403 			         (unsigned long)decompressed_cache_size,
    404 			         (unsigned long)e->decompressed_len);
    405 		decompressed_cache_size -= e->decompressed_len;
    406 		e->decompressed_len = 0;
    407 		free(e->decompressed);
    408 		e->decompressed = NULL;
    409 	}
    410 }
    411 
    412 size_t
    413 add_compress_methods(unsigned char **s, size_t sl)
    414 {
    415 	sl = add_to_str(s, sl, cast_uchar "ZLIB");
    416 #ifdef zlib_version
    417 	sl = add_to_str(s, sl, cast_uchar " (");
    418 	sl = add_to_str(s, sl, (unsigned char *)zlib_version);
    419 	sl = add_chr_to_str(s, sl, ')');
    420 #endif
    421 	return sl;
    422 }