BIO: Add BIO_f_prefix(), a text line prefixing filter

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10531)
This commit is contained in:
Richard Levitte 2019-11-27 16:02:33 +01:00
parent a0848daee5
commit 319cee9e2f
6 changed files with 293 additions and 1 deletions

207
crypto/bio/bf_prefix.c Normal file
View File

@ -0,0 +1,207 @@
/*
* Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "bio_local.h"
static int prefix_write(BIO *b, const char *out, size_t outl,
size_t *numwritten);
static int prefix_read(BIO *b, char *buf, size_t size, size_t *numread);
static int prefix_puts(BIO *b, const char *str);
static int prefix_gets(BIO *b, char *str, int size);
static long prefix_ctrl(BIO *b, int cmd, long arg1, void *arg2);
static int prefix_create(BIO *b);
static int prefix_destroy(BIO *b);
static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
static const BIO_METHOD prefix_meth = {
BIO_TYPE_BUFFER,
"prefix",
prefix_write,
NULL,
prefix_read,
NULL,
prefix_puts,
prefix_gets,
prefix_ctrl,
prefix_create,
prefix_destroy,
prefix_callback_ctrl,
};
const BIO_METHOD *BIO_f_prefix(void)
{
return &prefix_meth;
}
typedef struct prefix_ctx_st {
char *prefix; /* Text prefix, given by user */
unsigned int indent; /* Indentation amount, given by user */
int linestart; /* flag to indicate we're at the line start */
} PREFIX_CTX;
static int prefix_create(BIO *b)
{
PREFIX_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL)
return 0;
ctx->prefix = NULL;
ctx->indent = 0;
ctx->linestart = 1;
BIO_set_data(b, ctx);
BIO_set_init(b, 1);
return 1;
}
static int prefix_destroy(BIO *b)
{
PREFIX_CTX *ctx = BIO_get_data(b);
OPENSSL_free(ctx->prefix);
OPENSSL_free(ctx);
return 1;
}
static int prefix_read(BIO *b, char *in, size_t size, size_t *numread)
{
return BIO_read_ex(BIO_next(b), in, size, numread);
}
static int prefix_write(BIO *b, const char *out, size_t outl,
size_t *numwritten)
{
PREFIX_CTX *ctx = BIO_get_data(b);
if (ctx == NULL)
return 0;
/*
* If no prefix is set or if it's empty, and no indentation amount is set,
* we've got nothing to do here
*/
if ((ctx->prefix == NULL || *ctx->prefix == '\0')
&& ctx->indent == 0) {
/*
* We do note if what comes next will be a new line, though, so we're
* prepared to handle prefix and indentation the next time around.
*/
if (outl > 0)
ctx->linestart = (out[outl-1] == '\n');
return BIO_write_ex(BIO_next(b), out, outl, numwritten);
}
*numwritten = 0;
while (outl > 0) {
size_t i;
char c;
/*
* If we know that we're at the start of the line, output prefix and
* indentation.
*/
if (ctx->linestart) {
size_t dontcare;
if (ctx->prefix != NULL
&& !BIO_write_ex(BIO_next(b), ctx->prefix, strlen(ctx->prefix),
&dontcare))
return 0;
BIO_printf(BIO_next(b), "%*s", ctx->indent, "");
ctx->linestart = 0;
}
/* Now, go look for the next LF, or the end of the string */
for (i = 0, c = '\0'; i < outl && (c = out[i]) != '\n'; i++)
continue;
if (c == '\n')
i++;
/* Output what we found so far */
while (i > 0) {
size_t num = 0;
if (!BIO_write_ex(BIO_next(b), out, i, &num))
return 0;
out += num;
outl -= num;
*numwritten += num;
i -= num;
}
/* If we found a LF, what follows is a new line, so take note */
if (c == '\n')
ctx->linestart = 1;
}
return 1;
}
static long prefix_ctrl(BIO *b, int cmd, long num, void *ptr)
{
long ret = 0;
PREFIX_CTX *ctx = BIO_get_data(b);
if (ctx == NULL)
return -1;
switch (cmd) {
case BIO_CTRL_SET_PREFIX:
OPENSSL_free(ctx->prefix);
if (ptr == NULL) {
ctx->prefix = NULL;
ret = 1;
} else {
ctx->prefix = OPENSSL_strdup((const char *)ptr);
ret = ctx->prefix != NULL;
}
break;
case BIO_CTRL_SET_INDENT:
if (num >= 0) {
ctx->indent = (unsigned int)num;
ret = 1;
}
break;
case BIO_CTRL_GET_INDENT:
ret = (long)ctx->indent;
break;
default:
/* Commands that we intercept before passing them along */
switch (cmd) {
case BIO_C_FILE_SEEK:
case BIO_CTRL_RESET:
ctx->linestart = 1;
break;
}
if (BIO_next(b) != NULL)
ret = BIO_ctrl(BIO_next(b), cmd, num, ptr);
break;
}
return ret;
}
static long prefix_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
{
return BIO_callback_ctrl(BIO_next(b), cmd, fp);
}
static int prefix_gets(BIO *b, char *buf, int size)
{
return BIO_gets(BIO_next(b), buf, size);
}
static int prefix_puts(BIO *b, const char *str)
{
return BIO_write(b, str, strlen(str));
}

View File

@ -15,4 +15,4 @@ SOURCE[../../libcrypto]=\
# Filters
SOURCE[../../libcrypto]=\
bf_null.c bf_buff.c bf_lbuf.c bf_nbio.c
bf_null.c bf_buff.c bf_lbuf.c bf_nbio.c bf_prefix.c

70
doc/man3/BIO_f_prefix.pod Normal file
View File

@ -0,0 +1,70 @@
=pod
=head1 NAME
BIO_f_prefix, BIO_set_prefix, BIO_set_indent, BIO_get_indent
- prefix BIO filter
=head1 SYNOPSIS
#include <openssl/bio.h>
const BIO_METHOD *BIO_f_prefix(void);
long BIO_set_prefix(BIO *b, const char *prefix);
long BIO_set_indent(BIO *b, long indent);
long BIO_get_indent(BIO *b);
=head1 DESCRIPTION
BIO_f_cipher() returns the prefix BIO method. This is a filter for
text output, where each line gets automatically prefixed and indented
according to user input.
The prefix and the indentation are combined. For each line of output
going through this filter, the prefix is output first, then the amount
of additional spaces indicated by the indentation, and then the line
itself.
By default, there is no prefix, and indentation is set to 0.
BIO_set_prefix() sets the prefix to be used for future lines of
text, using I<prefix>. I<prefix> may be NULL, signifying that there
should be no prefix. If I<prefix> isn't NULL, this function makes a
copy of it.
BIO_set_indent() sets the indentation to be used for future lines of
text, using I<indent>. Negative values are not allowed.
BIO_get_indent() gets the current indentation.
=head1 NOTES
BIO_set_prefix(), BIO_set_indent() and BIO_get_indent() are
implemented as macros.
=head1 RETURN VALUES
BIO_f_prefix() returns the prefix BIO method.
BIO_set_prefix() returns 1 if the prefix was correctly set, or 0 on
failure.
BIO_set_indent() returns 1 if the prefix was correctly set, or 0 on
failure.
BIO_get_indent() returns the current indentation.
=head1 SEE ALSO
L<bio(7)>
=head1 COPYRIGHT
Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View File

@ -160,6 +160,11 @@ extern "C" {
# define BIO_CTRL_DGRAM_SCTP_WAIT_FOR_DRY 77
# define BIO_CTRL_DGRAM_SCTP_MSG_WAITING 78
/* BIO_f_prefix controls */
# define BIO_CTRL_SET_PREFIX 79
# define BIO_CTRL_SET_INDENT 80
# define BIO_CTRL_GET_INDENT 81
# ifndef OPENSSL_NO_KTLS
# define BIO_get_ktls_send(b) \
BIO_ctrl(b, BIO_CTRL_GET_KTLS_SEND, 0, NULL)
@ -552,6 +557,11 @@ int BIO_ctrl_reset_read_request(BIO *b);
# define BIO_dgram_get_mtu_overhead(b) \
(unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_MTU_OVERHEAD, 0, NULL)
/* ctrl macros for BIO_f_prefix */
# define BIO_set_prefix(b,p) BIO_ctrl((b), BIO_CTRL_SET_PREFIX, 0, (void *)(p))
# define BIO_set_indent(b,i) BIO_ctrl((b), BIO_CTRL_SET_INDENT, (i), NULL)
# define BIO_get_indent(b) BIO_ctrl((b), BIO_CTRL_GET_INDENT, 0, NULL)
#define BIO_get_ex_new_index(l, p, newf, dupf, freef) \
CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_BIO, l, p, newf, dupf, freef)
int BIO_set_ex_data(BIO *bio, int idx, void *data);
@ -630,6 +640,7 @@ const BIO_METHOD *BIO_f_null(void);
const BIO_METHOD *BIO_f_buffer(void);
const BIO_METHOD *BIO_f_linebuffer(void);
const BIO_METHOD *BIO_f_nbio_test(void);
const BIO_METHOD *BIO_f_prefix(void);
# ifndef OPENSSL_NO_DGRAM
const BIO_METHOD *BIO_s_datagram(void);
int BIO_dgram_non_fatal_error(int error);

View File

@ -4911,3 +4911,4 @@ i2d_X509_PUBKEY_bio ? 3_0_0 EXIST::FUNCTION:
RSA_get0_pss_params ? 3_0_0 EXIST::FUNCTION:RSA
X509_cmp_timeframe ? 3_0_0 EXIST::FUNCTION:
OSSL_CMP_MSG_get0_header ? 3_0_0 EXIST::FUNCTION:CMP
BIO_f_prefix ? 3_0_0 EXIST::FUNCTION:

View File

@ -127,6 +127,7 @@ BIO_get_conn_port define
BIO_get_conn_ip_family define
BIO_get_fd define
BIO_get_fp define
BIO_get_indent define
BIO_get_info_callback define
BIO_get_md define
BIO_get_md_ctx define
@ -158,12 +159,14 @@ BIO_set_conn_port define
BIO_set_conn_ip_family define
BIO_set_fd define
BIO_set_fp define
BIO_set_indent define
BIO_set_info_callback define
BIO_set_md define
BIO_set_mem_buf define
BIO_set_mem_eof_return define
BIO_set_nbio define
BIO_set_nbio_accept define
BIO_set_prefix define
BIO_set_read_buffer_size define
BIO_set_ssl define
BIO_set_ssl_mode define