static ngx_int_t ngx_http_brotli_filter_end(ngx_http_request_t *r, ngx_http_brotli_ctx_t *ctx) { ngx_chain_t *cl; BrotliEncoderDestroyInstance(ctx->bro); ctx->bro = NULL; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->out_buf->last_buf = 1; ctx->done = 1; r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED; return NGX_OK; }
static BROTLI_BOOL CompressFiles(Context* context) { while (NextFile(context)) { BROTLI_BOOL is_ok = BROTLI_TRUE; BrotliEncoderState* s = BrotliEncoderCreateInstance(NULL, NULL, NULL); if (!s) { fprintf(stderr, "out of memory\n"); return BROTLI_FALSE; } BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)context->quality); if (context->lgwin > 0) { /* Specified by user. */ /* Do not enable "large-window" extension, if not required. */ if (context->lgwin > BROTLI_MAX_WINDOW_BITS) { BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, 1u); } BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)context->lgwin); } else { /* 0, or not specified by user; could be chosen by compressor. */ uint32_t lgwin = DEFAULT_LGWIN; /* Use file size to limit lgwin. */ if (context->input_file_length >= 0) { int32_t size = 1 << BROTLI_MIN_WINDOW_BITS; lgwin = BROTLI_MIN_WINDOW_BITS; while (size < context->input_file_length) { size <<= 1; lgwin++; if (lgwin == BROTLI_MAX_WINDOW_BITS) break; } } BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, lgwin); } if (context->input_file_length > 0) { uint32_t size_hint = context->input_file_length < (1 << 30) ? (uint32_t)context->input_file_length : (1u << 30); BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, size_hint); } is_ok = OpenFiles(context); if (is_ok && !context->current_output_path && !context->force_overwrite && isatty(STDOUT_FILENO)) { fprintf(stderr, "Use -h help. Use -f to force output to a terminal.\n"); is_ok = BROTLI_FALSE; } if (is_ok) is_ok = CompressFile(context, s); BrotliEncoderDestroyInstance(s); if (!CloseFiles(context, is_ok)) is_ok = BROTLI_FALSE; if (!is_ok) return BROTLI_FALSE; } return BROTLI_TRUE; }
static void squash_brotli_stream_destroy (void* stream) { SquashBrotliStream* s = (SquashBrotliStream*) stream; if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_COMPRESS) { BrotliEncoderDestroyInstance(s->ctx.encoder); } else if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_DECOMPRESS) { BrotliDestroyState(s->ctx.decoder); } else { squash_assert_unreachable(); } squash_stream_destroy (stream); }
/* The brotli body is almost identical to gzip body */ static ngx_int_t ngx_http_brotli_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc; ngx_uint_t flush; ngx_chain_t *cl; ngx_http_brotli_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_brotli_filter_module); if (ctx == NULL || ctx->done || r->header_only) { return ngx_http_next_body_filter(r, in); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http brotli filter"); if (ctx->bro == NULL) { if (ngx_http_brotli_filter_start(r, ctx) != NGX_OK) { goto failed; } } if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { goto failed; } r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; } if (ctx->nomem) { /* flush busy buffers */ if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) { goto failed; } cl = NULL; ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, (ngx_buf_tag_t) &ngx_http_brotli_filter_module); ctx->nomem = 0; flush = 0; } else { flush = ctx->busy ? 1 : 0; } for ( ;; ) { /* cycle while we can write to a client */ for ( ;; ) { /* cycle while there is data to feed botli and ... */ rc = ngx_http_brotli_filter_add_data(r, ctx); if (rc == NGX_DECLINED) { break; } if (rc == NGX_AGAIN) { continue; } /* ... there are buffers to write brotli output */ rc = ngx_http_brotli_filter_get_buf(r, ctx); if (rc == NGX_DECLINED) { break; } if (rc == NGX_ERROR) { goto failed; } rc = ngx_http_brotli_filter_compress(r, ctx); if (rc == NGX_OK) { break; } if (rc == NGX_ERROR) { goto failed; } /* rc == NGX_AGAIN */ } if (ctx->out == NULL && !flush) { ngx_http_brotli_filter_free_copy_buf(r, ctx); return ctx->busy ? NGX_AGAIN : NGX_OK; } rc = ngx_http_next_body_filter(r, ctx->out); if (rc == NGX_ERROR) { goto failed; } ngx_http_brotli_filter_free_copy_buf(r, ctx); ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out, (ngx_buf_tag_t) &ngx_http_brotli_filter_module); ctx->last_out = &ctx->out; ctx->nomem = 0; flush = 0; if (ctx->done) { return rc; } } /* unreachable */ failed: ctx->done = 1; ngx_http_brotli_filter_free_copy_buf(r, ctx); BrotliEncoderDestroyInstance(ctx->bro); ctx->bro = NULL; return NGX_ERROR; }
static int Compress(int quality, int lgwin, FILE* fin, FILE* fout, const char *dictionary_path) { BrotliEncoderState* s = BrotliEncoderCreateInstance(0, 0, 0); uint8_t* buffer = (uint8_t*)malloc(kFileBufferSize << 1); uint8_t* input = buffer; uint8_t* output = buffer + kFileBufferSize; size_t available_in = 0; const uint8_t* next_in = NULL; size_t available_out = kFileBufferSize; uint8_t* next_out = output; int is_eof = 0; int is_ok = 1; if (!s || !buffer) { is_ok = 0; goto finish; } BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)quality); BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin); if (dictionary_path != NULL) { size_t dictionary_size = 0; uint8_t* dictionary = ReadDictionary(dictionary_path, &dictionary_size); BrotliEncoderSetCustomDictionary(s, dictionary_size, dictionary); free(dictionary); } while (1) { if (available_in == 0 && !is_eof) { available_in = fread(input, 1, kFileBufferSize, fin); next_in = input; if (ferror(fin)) break; is_eof = feof(fin); } if (!BrotliEncoderCompressStream(s, is_eof ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS, &available_in, &next_in, &available_out, &next_out, NULL)) { is_ok = 0; break; } if (available_out != kFileBufferSize) { size_t out_size = kFileBufferSize - available_out; fwrite(output, 1, out_size, fout); if (ferror(fout)) break; available_out = kFileBufferSize; next_out = output; } if (BrotliEncoderIsFinished(s)) break; } finish: free(buffer); BrotliEncoderDestroyInstance(s); if (!is_ok) { /* Should detect OOM? */ fprintf(stderr, "failed to compress data\n"); return 0; } else if (ferror(fout)) { fprintf(stderr, "failed to write output\n"); return 0; } else if (ferror(fin)) { fprintf(stderr, "failed to read input\n"); return 0; } return 1; }