1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26
27 static int
lcs_init_compression_brotli(lws_comp_ctx_t * ctx,int decomp)28 lcs_init_compression_brotli(lws_comp_ctx_t *ctx, int decomp)
29 {
30 ctx->is_decompression = (unsigned char)!!decomp;
31
32 if (!decomp) {
33 ctx->u.br_en = BrotliEncoderCreateInstance(NULL, NULL, NULL);
34 if (ctx->u.br_en) {
35 BrotliEncoderSetParameter(ctx->u.br_en,
36 BROTLI_PARAM_MODE, BROTLI_MODE_TEXT);
37 BrotliEncoderSetParameter(ctx->u.br_en,
38 BROTLI_PARAM_QUALITY, BROTLI_MIN_QUALITY);
39 }
40 }
41 else
42 ctx->u.br_de = BrotliDecoderCreateInstance(NULL, NULL, NULL);
43
44 return !ctx->u.br_de;
45 }
46
47 static int
lcs_process_brotli(lws_comp_ctx_t * ctx,const void * in,size_t * ilen_iused,void * out,size_t * olen_oused)48 lcs_process_brotli(lws_comp_ctx_t *ctx, const void *in, size_t *ilen_iused,
49 void *out, size_t *olen_oused)
50 {
51 size_t a_in, a_out, t_out;
52 const uint8_t *n_in;
53 uint8_t *n_out;
54 int n;
55
56 n_in = (void *)in;
57 a_in = *ilen_iused;
58 a_out = *olen_oused;
59 n_out = out;
60 t_out = 0;
61
62 if (!ctx->is_decompression) {
63
64 if (!a_in && !BrotliEncoderHasMoreOutput(ctx->u.br_en)) {
65 *olen_oused = 0;
66
67 goto bail;
68 }
69
70 n = BROTLI_OPERATION_PROCESS;
71 if (!ctx->buflist_comp && ctx->final_on_input_side)
72 n = BROTLI_OPERATION_FINISH;
73
74 if (BrotliEncoderCompressStream(ctx->u.br_en, n, &a_in, &n_in,
75 &a_out, &n_out, &t_out) ==
76 BROTLI_FALSE) {
77 lwsl_err("brotli encode failed\n");
78
79 return -1;
80 }
81
82 ctx->may_have_more = !a_out;
83
84 } else {
85 n = BrotliDecoderDecompressStream(ctx->u.br_de, &a_in, &n_in,
86 &a_out, &n_out, &t_out);
87
88 switch (n) {
89 case BROTLI_DECODER_RESULT_ERROR:
90 lwsl_err("brotli decoder error\n");
91 return -1;
92 }
93 }
94
95 *ilen_iused -= a_in;
96 *olen_oused -= a_out;
97
98 bail:
99 if (!ctx->is_decompression)
100 return BrotliEncoderIsFinished(ctx->u.br_en);
101 else
102 return BrotliDecoderIsFinished(ctx->u.br_de);
103 }
104
105 static void
lcs_destroy_brotli(lws_comp_ctx_t * ctx)106 lcs_destroy_brotli(lws_comp_ctx_t *ctx)
107 {
108 if (!ctx)
109 return;
110
111 if (!(*ctx).is_decompression)
112 BrotliEncoderDestroyInstance((*ctx).u.br_en);
113 else
114 BrotliDecoderDestroyInstance((*ctx).u.br_de);
115
116 (*ctx).u.generic_ctx_ptr = NULL;
117 }
118
119 struct lws_compression_support lcs_brotli = {
120 /* .encoding_name */ "br",
121 /* .init_compression */ lcs_init_compression_brotli,
122 /* .process */ lcs_process_brotli,
123 /* .destroy */ lcs_destroy_brotli,
124 };
125