Coverage Report

Created: 2026-07-12 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/include/haproxy/htx-t.h
Line
Count
Source
1
/*
2
 * include/haproxy/htx-t.h
3
 * This file declares the types and constants used the internal HTTP messages
4
 *
5
 * Copyright (C) 2018 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com>
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation, version 2.1
10
 * exclusively.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
22
#ifndef _HAPROXY_HTX_T_H
23
#define _HAPROXY_HTX_T_H
24
25
#include <haproxy/api.h>
26
#include <haproxy/http-t.h>
27
#include <haproxy/show_flags-t.h>
28
29
/*
30
 * The internal representation of an HTTP message, called HTX, is a structure
31
 * with useful information on the message followed by a contiguous array
32
 * containing parts of the message, called blocks. A block is composed of
33
 * metadata (htx_blk) and the associated payload. Blocks' metadata are stored
34
 * starting from the end of the array while their payload are stored at the
35
 * beginning. Blocks' metadata are often simply called blocks. it is a misuse of
36
 * language that's simplify explanations.
37
 *
38
 *
39
 *  +-----+---------------+------------------------------+--------------+
40
 *  | HTX |  PAYLOADS ==> |                              | <== HTX_BLKs |
41
 *  +-----+---------------+------------------------------+--------------+
42
 *        ^
43
 *        blocks[] (the beginning of the blocks array)
44
 *
45
 *
46
 * The blocks part remains linear and sorted. You may think about it as an array
47
 * with negative indexes. But, instead of using negative indexes, we use
48
 * positive positions to identify a block. This position is then converted to a
49
 * address relatively to the beginning of the blocks array.
50
 *
51
 *
52
 *      .....--+------------------------------+-----+-----+
53
 *             |                       ...    | BLK | BLK |
54
 *      .....--+------------------------------+-----+-----+
55
 *                                            ^     ^
56
 *                            Addr of the block     Addr of the block
57
 *                            at the position 1     at the position 0
58
 *
59
 *
60
 * The payloads part is a raw space that may wrap. You never access to a block's
61
 * payload directly. Instead you get a block to retrieve the address of its
62
 * payload. When no more space left between blocks and payloads parts, the free
63
 * space at the beginning, if any, is used.
64
 *
65
 *
66
 *        +----------- WRAPPING ------------------------+
67
 *        |                                             |
68
 *        V                                             |
69
 *  +-----+-------------+---------------+---------------++--------------+
70
 *  | HTX | PAYLOAD ==> |               |  PAYLOADS ==X || X== HTX_BLKs |
71
 *  +-----+-------------+---------------+---------------++--------------+
72
 *
73
 *
74
 * The blocks part, on its side, never wrap. If we have no space to allocate a
75
 * new block and if there is a hole at the beginning of the blocks part (so at
76
 * the end of the blocks array), we move back all blocks.x
77
 *
78
 *
79
 *    ...+--------------+----------+   blocks  ...+----------+--------------+
80
 *       | X== HTX_BLKS |          |   defrag     |          | <== HTX_BLKS |
81
 *    ...+--------------+----------+   =====>  ...+----------+--------------+
82
 *
83
 *
84
 * At the end, if payload wrapping or blocks defragmentation is not enough, some
85
 * free space may be get back with a full defragmentation. This way, the holes in
86
 * the middle are not reusable but count in the available free space. The only
87
 * way to reuse this lost space is to fully defragment the HTX message.
88
 *
89
 *                                   - * -
90
 *
91
 * An HTX block is as well a header as a body part or a trailer. For all these
92
 * types of block, a payload is attached to the block. It can also be a mark,
93
 * like the end-of-headers or end-of-trailers. For these blocks, there is no
94
 * payload but it count for a byte. It is important to not skip it when data are
95
 * forwarded. Metadata of an HTX block are composed of 2 fields :
96
 *
97
 *     - .info : It a 32 bits field containing the block's type on 4 bits
98
 *               followed by the payload length. See below for details.
99
 *
100
 *     - .addr : The payload's address, if any, relatively to the beginning the
101
 *               array used to store the HTX message itself.
102
 *
103
 * htx_blk.info representation :
104
 *
105
 *   0b 0000 0000 0000 0000 0000 0000 0000 0000
106
 *      ---- ------------------------ ---------
107
 *      type     value (1 MB max)     name length (header/trailer)
108
 *           ----------------------------------
109
 *                data length (256 MB max)
110
 *    (body, method, path, version, status, reason)
111
 *
112
 *   types :
113
 *     - 0000 = request  start-line
114
 *     - 0001 = response start-line
115
 *     - 0010 = header
116
 *     - 0011 = end-of-headers
117
 *     - 0100 = data
118
 *     - 0101 = trailer
119
 *     - 0110 = end-of-trailers
120
 *       ...
121
 *     - 1111 = unused
122
 *
123
 */
124
125
/* HTX start-line flags.
126
 * Please also update the se_show_flags() function below in case of changes.
127
 */
128
0
#define HTX_SL_F_NONE           0x00000000
129
0
#define HTX_SL_F_IS_RESP        0x00000001 /* It is the response start-line (unset means the request one) */
130
0
#define HTX_SL_F_XFER_LEN       0x00000002 /* The message xfer size can be determined */
131
0
#define HTX_SL_F_XFER_ENC       0x00000004 /* The transfer-encoding header was found in message */
132
0
#define HTX_SL_F_CLEN           0x00000008 /* The content-length header was found in message */
133
0
#define HTX_SL_F_CHNK           0x00000010 /* The message payload is chunked */
134
0
#define HTX_SL_F_VER_11         0x00000020 /* The message indicates version 1.1 or above */
135
0
#define HTX_SL_F_BODYLESS       0x00000040 /* The message has no body (content-length = 0) */
136
0
#define HTX_SL_F_HAS_SCHM       0x00000080 /* The scheme is explicitly specified */
137
0
#define HTX_SL_F_SCHM_HTTP      0x00000100 /* The scheme HTTP should be used */
138
0
#define HTX_SL_F_SCHM_HTTPS     0x00000200 /* The scheme HTTPS should be used */
139
0
#define HTX_SL_F_HAS_AUTHORITY  0x00000400 /* The request authority is explicitly specified */
140
0
#define HTX_SL_F_NORMALIZED_URI 0x00000800 /* The received URI is normalized (an implicit absolute-uri form) */
141
0
#define HTX_SL_F_CONN_UPG       0x00001000 /* The message contains "connection: upgrade" header */
142
0
#define HTX_SL_F_BODYLESS_RESP  0x00002000 /* The response to this message is bodyless (only for request) */
143
0
#define HTX_SL_F_NOT_HTTP       0x00004000 /* Not an HTTP message (e.g "RTSP", only possible if invalid message are accepted) */
144
0
#define HTX_SL_F_UPG_HDR        0x00008000 /* non-empty Upgrapde header found */
145
146
/* This function is used to report flags in debugging tools. Please reflect
147
 * below any single-bit flag addition above in the same order via the
148
 * __APPEND_FLAG macro. The new end of the buffer is returned.
149
 */
150
static forceinline char *hsl_show_flags(char *buf, size_t len, const char *delim, uint flg)
151
0
{
152
0
#define _(f, ...) __APPEND_FLAG(buf, len, delim, flg, f, #f, __VA_ARGS__)
153
0
  /* prologue */
154
0
  _(0);
155
0
  /* flags */
156
0
157
0
  _(HTX_SL_F_IS_RESP, _(HTX_SL_F_XFER_LEN, _(HTX_SL_F_XFER_ENC,
158
0
  _(HTX_SL_F_CLEN, _(HTX_SL_F_CHNK, _(HTX_SL_F_VER_11,
159
0
  _(HTX_SL_F_BODYLESS, _(HTX_SL_F_HAS_SCHM, _(HTX_SL_F_SCHM_HTTP,
160
0
  _(HTX_SL_F_SCHM_HTTPS, _(HTX_SL_F_HAS_AUTHORITY,
161
0
  _(HTX_SL_F_NORMALIZED_URI, _(HTX_SL_F_CONN_UPG, _(HTX_SL_F_BODYLESS_RESP,
162
0
  _(HTX_SL_F_NOT_HTTP, _(HTX_SL_F_UPG_HDR))))))))))))))));
163
0
  /* epilogue */
164
0
  _(~0U);
165
0
  return buf;
166
0
#undef _
167
0
}
Unexecuted instantiation: cfgparse.c:hsl_show_flags
Unexecuted instantiation: cli.c:hsl_show_flags
Unexecuted instantiation: connection.c:hsl_show_flags
Unexecuted instantiation: debug.c:hsl_show_flags
Unexecuted instantiation: errors.c:hsl_show_flags
Unexecuted instantiation: fd.c:hsl_show_flags
Unexecuted instantiation: frontend.c:hsl_show_flags
Unexecuted instantiation: haproxy.c:hsl_show_flags
Unexecuted instantiation: http_ana.c:hsl_show_flags
Unexecuted instantiation: http_ext.c:hsl_show_flags
Unexecuted instantiation: http_htx.c:hsl_show_flags
Unexecuted instantiation: http_rules.c:hsl_show_flags
Unexecuted instantiation: htx.c:hsl_show_flags
Unexecuted instantiation: limits.c:hsl_show_flags
Unexecuted instantiation: listener.c:hsl_show_flags
Unexecuted instantiation: log.c:hsl_show_flags
Unexecuted instantiation: mworker.c:hsl_show_flags
Unexecuted instantiation: peers.c:hsl_show_flags
Unexecuted instantiation: pool.c:hsl_show_flags
Unexecuted instantiation: proto_rhttp.c:hsl_show_flags
Unexecuted instantiation: proto_sockpair.c:hsl_show_flags
Unexecuted instantiation: proxy.c:hsl_show_flags
Unexecuted instantiation: queue.c:hsl_show_flags
Unexecuted instantiation: resolvers.c:hsl_show_flags
Unexecuted instantiation: ring.c:hsl_show_flags
Unexecuted instantiation: sample.c:hsl_show_flags
Unexecuted instantiation: server.c:hsl_show_flags
Unexecuted instantiation: session.c:hsl_show_flags
Unexecuted instantiation: sink.c:hsl_show_flags
Unexecuted instantiation: sock.c:hsl_show_flags
Unexecuted instantiation: stats-html.c:hsl_show_flags
Unexecuted instantiation: stats-proxy.c:hsl_show_flags
Unexecuted instantiation: stats.c:hsl_show_flags
Unexecuted instantiation: stconn.c:hsl_show_flags
Unexecuted instantiation: stick_table.c:hsl_show_flags
Unexecuted instantiation: stream.c:hsl_show_flags
Unexecuted instantiation: tcp_rules.c:hsl_show_flags
Unexecuted instantiation: tcpcheck.c:hsl_show_flags
Unexecuted instantiation: thread.c:hsl_show_flags
Unexecuted instantiation: tools.c:hsl_show_flags
Unexecuted instantiation: trace.c:hsl_show_flags
Unexecuted instantiation: vars.c:hsl_show_flags
Unexecuted instantiation: activity.c:hsl_show_flags
Unexecuted instantiation: applet.c:hsl_show_flags
Unexecuted instantiation: backend.c:hsl_show_flags
Unexecuted instantiation: cfgparse-global.c:hsl_show_flags
Unexecuted instantiation: cfgparse-listen.c:hsl_show_flags
Unexecuted instantiation: channel.c:hsl_show_flags
Unexecuted instantiation: check.c:hsl_show_flags
Unexecuted instantiation: compression.c:hsl_show_flags
Unexecuted instantiation: dns.c:hsl_show_flags
Unexecuted instantiation: dns_ring.c:hsl_show_flags
Unexecuted instantiation: extcheck.c:hsl_show_flags
Unexecuted instantiation: filters.c:hsl_show_flags
Unexecuted instantiation: flt_http_comp.c:hsl_show_flags
Unexecuted instantiation: haterm.c:hsl_show_flags
Unexecuted instantiation: http_fetch.c:hsl_show_flags
Unexecuted instantiation: mux_spop.c:hsl_show_flags
Unexecuted instantiation: pattern.c:hsl_show_flags
Unexecuted instantiation: payload.c:hsl_show_flags
Unexecuted instantiation: proto_tcp.c:hsl_show_flags
Unexecuted instantiation: stats-json.c:hsl_show_flags
Unexecuted instantiation: cache.c:hsl_show_flags
Unexecuted instantiation: fcgi-app.c:hsl_show_flags
Unexecuted instantiation: flt_spoe.c:hsl_show_flags
Unexecuted instantiation: h1_htx.c:hsl_show_flags
168
169
/* Overhead induced by HTX on buffers during transfers. In addition to the size
170
 * of the HTX structure itself, and meta data for one block, another block is
171
 * accounted to favored zero-copy xfer.
172
 */
173
0
#define HTX_BUF_OVERHEAD     (sizeof(struct htx) + 2 * sizeof(struct htx_blk))
174
175
/* HTX flags.
176
 * Please also update the htx_show_flags() function below in case of changes.
177
 */
178
0
#define HTX_FL_NONE              0x00000000
179
0
#define HTX_FL_PARSING_ERROR     0x00000001 /* Set when a parsing error occurred */
180
0
#define HTX_FL_PROCESSING_ERROR  0x00000002 /* Set when a processing error occurred */
181
0
#define HTX_FL_FRAGMENTED        0x00000004 /* Set when the HTX buffer is fragmented */
182
0
#define HTX_FL_UNORDERED         0x00000008 /* Set when the HTX buffer are not ordered */
183
0
#define HTX_FL_EOM               0x00000010 /* Set when end-of-message is reached from the HTTP point of view
184
               * (at worst, on the EOM block is missing)
185
               */
186
/* This function is used to report flags in debugging tools. Please reflect
187
 * below any single-bit flag addition above in the same order via the
188
 * __APPEND_FLAG macro. The new end of the buffer is returned.
189
 */
190
static forceinline char *htx_show_flags(char *buf, size_t len, const char *delim, uint flg)
191
0
{
192
0
#define _(f, ...) __APPEND_FLAG(buf, len, delim, flg, f, #f, __VA_ARGS__)
193
0
  /* prologue */
194
0
  _(0);
195
0
  /* flags */
196
0
  _(HTX_FL_PARSING_ERROR, _(HTX_FL_PROCESSING_ERROR,
197
0
  _(HTX_FL_FRAGMENTED, _(HTX_FL_UNORDERED, _(HTX_FL_EOM)))));
198
0
  /* epilogue */
199
0
  _(~0U);
200
0
  return buf;
201
0
#undef _
202
0
}
Unexecuted instantiation: cfgparse.c:htx_show_flags
Unexecuted instantiation: cli.c:htx_show_flags
Unexecuted instantiation: connection.c:htx_show_flags
Unexecuted instantiation: debug.c:htx_show_flags
Unexecuted instantiation: errors.c:htx_show_flags
Unexecuted instantiation: fd.c:htx_show_flags
Unexecuted instantiation: frontend.c:htx_show_flags
Unexecuted instantiation: haproxy.c:htx_show_flags
Unexecuted instantiation: http_ana.c:htx_show_flags
Unexecuted instantiation: http_ext.c:htx_show_flags
Unexecuted instantiation: http_htx.c:htx_show_flags
Unexecuted instantiation: http_rules.c:htx_show_flags
Unexecuted instantiation: htx.c:htx_show_flags
Unexecuted instantiation: limits.c:htx_show_flags
Unexecuted instantiation: listener.c:htx_show_flags
Unexecuted instantiation: log.c:htx_show_flags
Unexecuted instantiation: mworker.c:htx_show_flags
Unexecuted instantiation: peers.c:htx_show_flags
Unexecuted instantiation: pool.c:htx_show_flags
Unexecuted instantiation: proto_rhttp.c:htx_show_flags
Unexecuted instantiation: proto_sockpair.c:htx_show_flags
Unexecuted instantiation: proxy.c:htx_show_flags
Unexecuted instantiation: queue.c:htx_show_flags
Unexecuted instantiation: resolvers.c:htx_show_flags
Unexecuted instantiation: ring.c:htx_show_flags
Unexecuted instantiation: sample.c:htx_show_flags
Unexecuted instantiation: server.c:htx_show_flags
Unexecuted instantiation: session.c:htx_show_flags
Unexecuted instantiation: sink.c:htx_show_flags
Unexecuted instantiation: sock.c:htx_show_flags
Unexecuted instantiation: stats-html.c:htx_show_flags
Unexecuted instantiation: stats-proxy.c:htx_show_flags
Unexecuted instantiation: stats.c:htx_show_flags
Unexecuted instantiation: stconn.c:htx_show_flags
Unexecuted instantiation: stick_table.c:htx_show_flags
Unexecuted instantiation: stream.c:htx_show_flags
Unexecuted instantiation: tcp_rules.c:htx_show_flags
Unexecuted instantiation: tcpcheck.c:htx_show_flags
Unexecuted instantiation: thread.c:htx_show_flags
Unexecuted instantiation: tools.c:htx_show_flags
Unexecuted instantiation: trace.c:htx_show_flags
Unexecuted instantiation: vars.c:htx_show_flags
Unexecuted instantiation: activity.c:htx_show_flags
Unexecuted instantiation: applet.c:htx_show_flags
Unexecuted instantiation: backend.c:htx_show_flags
Unexecuted instantiation: cfgparse-global.c:htx_show_flags
Unexecuted instantiation: cfgparse-listen.c:htx_show_flags
Unexecuted instantiation: channel.c:htx_show_flags
Unexecuted instantiation: check.c:htx_show_flags
Unexecuted instantiation: compression.c:htx_show_flags
Unexecuted instantiation: dns.c:htx_show_flags
Unexecuted instantiation: dns_ring.c:htx_show_flags
Unexecuted instantiation: extcheck.c:htx_show_flags
Unexecuted instantiation: filters.c:htx_show_flags
Unexecuted instantiation: flt_http_comp.c:htx_show_flags
Unexecuted instantiation: haterm.c:htx_show_flags
Unexecuted instantiation: http_fetch.c:htx_show_flags
Unexecuted instantiation: mux_spop.c:htx_show_flags
Unexecuted instantiation: pattern.c:htx_show_flags
Unexecuted instantiation: payload.c:htx_show_flags
Unexecuted instantiation: proto_tcp.c:htx_show_flags
Unexecuted instantiation: stats-json.c:htx_show_flags
Unexecuted instantiation: cache.c:htx_show_flags
Unexecuted instantiation: fcgi-app.c:htx_show_flags
Unexecuted instantiation: flt_spoe.c:htx_show_flags
Unexecuted instantiation: h1_htx.c:htx_show_flags
203
204
205
/* HTX block's type (max 15). */
206
enum htx_blk_type {
207
  HTX_BLK_REQ_SL =  0, /* Request start-line */
208
  HTX_BLK_RES_SL =  1, /* Response start-line */
209
  HTX_BLK_HDR    =  2, /* header name/value block */
210
  HTX_BLK_EOH    =  3, /* end-of-headers block */
211
  HTX_BLK_DATA   =  4, /* data block */
212
  HTX_BLK_TLR    =  5, /* trailer name/value block */
213
  HTX_BLK_EOT    =  6, /* end-of-trailers block */
214
  /* 7 .. 14 unused */
215
  HTX_BLK_UNUSED = 15, /* unused/removed block */
216
};
217
218
/* One HTX block descriptor */
219
struct htx_blk {
220
  uint32_t addr; /* relative storage address of the block's payload */
221
  uint32_t info; /* information about the block (type, length) */
222
};
223
224
/* Composite return value used by some HTX functions */
225
struct htx_ret {
226
  int32_t ret;         /* A numerical value */
227
  struct htx_blk *blk; /* An HTX block */
228
};
229
230
/* HTX start-line. This is almost always aligned except in rare cases where
231
 * parts of the URI are rewritten, hence the packed attribute.
232
 */
233
struct htx_sl {
234
  unsigned int flags; /* HTX_SL_F_* */
235
  union {
236
    struct {
237
      enum http_meth_t meth;   /* method */
238
    } req;
239
    struct {
240
      uint16_t         status; /* status code */
241
    } res;
242
  } info;
243
244
  /* XXX 2 bytes unused, must be present to keep the rest aligned
245
   * (check with "pahole -C htx_sl" that len[] is aligned in case
246
   * of doubt).
247
   */
248
  char __pad_1;
249
  char __pad_2;
250
251
  unsigned int len[3]; /* length of different parts of the start-line */
252
  char         l[VAR_ARRAY];
253
} __attribute__((packed));
254
255
/* Internal representation of an HTTP message */
256
struct htx {
257
  uint32_t size;   /* the array size, in bytes, used to store the HTTP message itself */
258
  uint32_t data;   /* the data size, in bytes. To known to total size used by all allocated
259
        * blocks (blocks and their contents), you need to add size used by blocks,
260
        * i.e. [ used * sizeof(struct htx_blk *) ] */
261
  uint32_t hdrs_data;
262
  int32_t tail;   /* newest inserted block. -1 if the HTX message is empty */
263
  int32_t head;   /* oldest inserted block. -1 if the HTX message is empty */
264
  int32_t first;  /* position of the first block to (re)start the analyse. -1 if unset. */
265
266
  uint32_t tail_addr; /* start address of the free space in front of the the blocks table */
267
  uint32_t head_addr; /* start address of the free space at the beginning */
268
  uint32_t end_addr;  /* end address of the free space at the beginning */
269
270
  uint32_t flags;  /* HTX_FL_* */
271
272
  /* Blocks representing the HTTP message itself */
273
  char blocks[VAR_ARRAY] ALIGNED(8);
274
};
275
276
#endif /* _HAPROXY_HTX_T_H */
277
278
/*
279
 * Local variables:
280
 *  c-indent-level: 8
281
 *  c-basic-offset: 8
282
 * End:
283
 */