2 * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
12 #include "bio_local.h"
13 #include "internal/cryptlib.h"
14 #include <openssl/evp.h>
16 static int linebuffer_write(BIO
*h
, const char *buf
, int num
);
17 static int linebuffer_read(BIO
*h
, char *buf
, int size
);
18 static int linebuffer_puts(BIO
*h
, const char *str
);
19 static int linebuffer_gets(BIO
*h
, char *str
, int size
);
20 static long linebuffer_ctrl(BIO
*h
, int cmd
, long arg1
, void *arg2
);
21 static int linebuffer_new(BIO
*h
);
22 static int linebuffer_free(BIO
*data
);
23 static long linebuffer_callback_ctrl(BIO
*h
, int cmd
, BIO_info_cb
*fp
);
25 /* A 10k maximum should be enough for most purposes */
26 #define DEFAULT_LINEBUFFER_SIZE 1024*10
30 static const BIO_METHOD methods_linebuffer
= {
42 linebuffer_callback_ctrl
,
45 const BIO_METHOD
*BIO_f_linebuffer(void)
47 return &methods_linebuffer
;
50 typedef struct bio_linebuffer_ctx_struct
{
51 char *obuf
; /* the output char array */
52 int obuf_size
; /* how big is the output buffer */
53 int obuf_len
; /* how many bytes are in it */
56 static int linebuffer_new(BIO
*bi
)
58 BIO_LINEBUFFER_CTX
*ctx
;
60 if ((ctx
= OPENSSL_malloc(sizeof(*ctx
))) == NULL
)
62 ctx
->obuf
= OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE
);
63 if (ctx
->obuf
== NULL
) {
67 ctx
->obuf_size
= DEFAULT_LINEBUFFER_SIZE
;
71 bi
->ptr
= (char *)ctx
;
76 static int linebuffer_free(BIO
*a
)
78 BIO_LINEBUFFER_CTX
*b
;
82 b
= (BIO_LINEBUFFER_CTX
*)a
->ptr
;
83 OPENSSL_free(b
->obuf
);
91 static int linebuffer_read(BIO
*b
, char *out
, int outl
)
97 if (b
->next_bio
== NULL
)
99 ret
= BIO_read(b
->next_bio
, out
, outl
);
100 BIO_clear_retry_flags(b
);
101 BIO_copy_next_retry(b
);
105 static int linebuffer_write(BIO
*b
, const char *in
, int inl
)
107 int i
, num
= 0, foundnl
;
108 BIO_LINEBUFFER_CTX
*ctx
;
110 if ((in
== NULL
) || (inl
<= 0))
112 ctx
= (BIO_LINEBUFFER_CTX
*)b
->ptr
;
113 if ((ctx
== NULL
) || (b
->next_bio
== NULL
))
116 BIO_clear_retry_flags(b
);
122 for (p
= in
, c
= '\0'; p
< in
+ inl
&& (c
= *p
) != '\n'; p
++) ;
130 * If a NL was found and we already have text in the save buffer,
131 * concatenate them and write
133 while ((foundnl
|| p
- in
> ctx
->obuf_size
- ctx
->obuf_len
)
134 && ctx
->obuf_len
> 0) {
135 int orig_olen
= ctx
->obuf_len
;
137 i
= ctx
->obuf_size
- ctx
->obuf_len
;
140 memcpy(&(ctx
->obuf
[ctx
->obuf_len
]), in
, p
- in
);
141 ctx
->obuf_len
+= p
- in
;
146 memcpy(&(ctx
->obuf
[ctx
->obuf_len
]), in
, i
);
153 i
= BIO_write(b
->next_bio
, ctx
->obuf
, ctx
->obuf_len
);
155 ctx
->obuf_len
= orig_olen
;
156 BIO_copy_next_retry(b
);
159 return ((num
> 0) ? num
: i
);
163 if (i
< ctx
->obuf_len
)
164 memmove(ctx
->obuf
, ctx
->obuf
+ i
, ctx
->obuf_len
- i
);
169 * Now that the save buffer is emptied, let's write the input buffer
170 * if a NL was found and there is anything to write.
172 if ((foundnl
|| p
- in
> ctx
->obuf_size
) && p
- in
> 0) {
173 i
= BIO_write(b
->next_bio
, in
, p
- in
);
175 BIO_copy_next_retry(b
);
177 return ((num
> 0) ? num
: i
);
186 while (foundnl
&& inl
> 0);
188 * We've written as much as we can. The rest of the input buffer, if
189 * any, is text that doesn't and with a NL and therefore needs to be
190 * saved for the next trip.
193 memcpy(&(ctx
->obuf
[ctx
->obuf_len
]), in
, inl
);
194 ctx
->obuf_len
+= inl
;
200 static long linebuffer_ctrl(BIO
*b
, int cmd
, long num
, void *ptr
)
203 BIO_LINEBUFFER_CTX
*ctx
;
209 ctx
= (BIO_LINEBUFFER_CTX
*)b
->ptr
;
214 if (b
->next_bio
== NULL
)
216 ret
= BIO_ctrl(b
->next_bio
, cmd
, num
, ptr
);
219 ret
= (long)ctx
->obuf_len
;
221 case BIO_CTRL_WPENDING
:
222 ret
= (long)ctx
->obuf_len
;
224 if (b
->next_bio
== NULL
)
226 ret
= BIO_ctrl(b
->next_bio
, cmd
, num
, ptr
);
229 case BIO_C_SET_BUFF_SIZE
:
234 if ((obs
> DEFAULT_LINEBUFFER_SIZE
) && (obs
!= ctx
->obuf_size
)) {
235 p
= OPENSSL_malloc((size_t)obs
);
239 if (ctx
->obuf
!= p
) {
240 if (ctx
->obuf_len
> obs
) {
243 memcpy(p
, ctx
->obuf
, ctx
->obuf_len
);
244 OPENSSL_free(ctx
->obuf
);
246 ctx
->obuf_size
= obs
;
249 case BIO_C_DO_STATE_MACHINE
:
250 if (b
->next_bio
== NULL
)
252 BIO_clear_retry_flags(b
);
253 ret
= BIO_ctrl(b
->next_bio
, cmd
, num
, ptr
);
254 BIO_copy_next_retry(b
);
258 if (b
->next_bio
== NULL
)
260 if (ctx
->obuf_len
<= 0) {
261 ret
= BIO_ctrl(b
->next_bio
, cmd
, num
, ptr
);
262 BIO_copy_next_retry(b
);
267 BIO_clear_retry_flags(b
);
268 if (ctx
->obuf_len
> 0) {
269 r
= BIO_write(b
->next_bio
, ctx
->obuf
, ctx
->obuf_len
);
270 BIO_copy_next_retry(b
);
273 if (r
< ctx
->obuf_len
)
274 memmove(ctx
->obuf
, ctx
->obuf
+ r
, ctx
->obuf_len
- r
);
281 ret
= BIO_ctrl(b
->next_bio
, cmd
, num
, ptr
);
282 BIO_copy_next_retry(b
);
286 if (BIO_set_write_buffer_size(dbio
, ctx
->obuf_size
) <= 0)
290 if (b
->next_bio
== NULL
)
292 ret
= BIO_ctrl(b
->next_bio
, cmd
, num
, ptr
);
298 static long linebuffer_callback_ctrl(BIO
*b
, int cmd
, BIO_info_cb
*fp
)
300 if (b
->next_bio
== NULL
)
302 return BIO_callback_ctrl(b
->next_bio
, cmd
, fp
);
305 static int linebuffer_gets(BIO
*b
, char *buf
, int size
)
307 if (b
->next_bio
== NULL
)
309 return BIO_gets(b
->next_bio
, buf
, size
);
312 static int linebuffer_puts(BIO
*b
, const char *str
)
314 return linebuffer_write(b
, str
, strlen(str
));