Imported Upstream version 3.2.0
[platform/upstream/libwebsockets.git] / lib / roles / http / compression / brotli / brotli.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "core/private.h"
23
24
25 static int
26 lcs_init_compression_brotli(lws_comp_ctx_t *ctx, int decomp)
27 {
28         ctx->is_decompression = decomp;
29
30         if (!decomp) {
31                 ctx->u.br_en = BrotliEncoderCreateInstance(NULL, NULL, NULL);
32                 if (ctx->u.br_en) {
33                         BrotliEncoderSetParameter(ctx->u.br_en,
34                                         BROTLI_PARAM_MODE, BROTLI_MODE_TEXT);
35                         BrotliEncoderSetParameter(ctx->u.br_en,
36                                 BROTLI_PARAM_QUALITY, BROTLI_MIN_QUALITY);
37                 }
38         }
39         else
40                 ctx->u.br_de = BrotliDecoderCreateInstance(NULL, NULL, NULL);
41
42         return !ctx->u.br_de;
43 }
44
45 static int
46 lcs_process_brotli(lws_comp_ctx_t *ctx, const void *in, size_t *ilen_iused,
47                    void *out, size_t *olen_oused)
48 {
49         size_t a_in, a_out, t_out;
50         const uint8_t *n_in;
51         uint8_t *n_out;
52         int n;
53
54         n_in = (void *)in;
55         a_in = *ilen_iused;
56         a_out = *olen_oused;
57         n_out = out;
58         t_out = 0;
59
60         if (!ctx->is_decompression) {
61
62                 if (!a_in && !BrotliEncoderHasMoreOutput(ctx->u.br_en)) {
63                         *olen_oused = 0;
64
65                         goto bail;
66                 }
67
68                 n = BROTLI_OPERATION_PROCESS;
69                 if (!ctx->buflist_comp && ctx->final_on_input_side)
70                         n = BROTLI_OPERATION_FINISH;
71
72                 if (BrotliEncoderCompressStream(ctx->u.br_en, n, &a_in, &n_in,
73                                                 &a_out, &n_out, &t_out) ==
74                     BROTLI_FALSE) {
75                         lwsl_err("brotli encode failed\n");
76
77                         return -1;
78                 }
79
80                 ctx->may_have_more = !a_out;
81
82         } else {
83                 n = BrotliDecoderDecompressStream(ctx->u.br_de, &a_in, &n_in,
84                                                   &a_out, &n_out, &t_out);
85
86                 switch (n) {
87                 case BROTLI_DECODER_RESULT_ERROR:
88                         lwsl_err("brotli decoder error\n");
89                         return -1;
90                 }
91         }
92
93         *ilen_iused -= a_in;
94         *olen_oused -= a_out;
95
96 bail:
97         if (!ctx->is_decompression)
98                 return BrotliEncoderIsFinished(ctx->u.br_en);
99         else
100                 return BrotliDecoderIsFinished(ctx->u.br_de);
101 }
102
103 static void
104 lcs_destroy_brotli(lws_comp_ctx_t *ctx)
105 {
106         if (!ctx)
107                 return;
108
109         if (!(*ctx).is_decompression)
110                 BrotliEncoderDestroyInstance((*ctx).u.br_en);
111         else
112                 BrotliDecoderDestroyInstance((*ctx).u.br_de);
113
114         (*ctx).u.generic_ctx_ptr = NULL;
115 }
116
117 struct lws_compression_support lcs_brotli = {
118         /* .encoding_name */            "br",
119         /* .init_compression */         lcs_init_compression_brotli,
120         /* .process */                  lcs_process_brotli,
121         /* .destroy */                  lcs_destroy_brotli,
122 };