• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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