Skip to content

Commit

Permalink
Merge pull request #1138 from tempesta-tech/ik-move-parser-to-connection
Browse files Browse the repository at this point in the history
Move http parser to connection
  • Loading branch information
vankoven authored Dec 27, 2018
2 parents c861b0f + ab8400a commit 3c278c6
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 165 deletions.
6 changes: 3 additions & 3 deletions tempesta_fw/addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ tfw_addr_pton_v4(const TfwStr *s, TfwAddr *addr)

TFW_STR_FOR_EACH_CHUNK(c, s, end) {
for (k = 0; k != c->len; ++k) {
p = c->ptr + k;
p = (char *)c->ptr + k;
if (isdigit(*p)) {
octet = (octet == -1)
? *p - '0'
Expand Down Expand Up @@ -101,7 +101,7 @@ tfw_addr_pton_v6(const TfwStr *s, TfwAddr *addr)

TFW_STR_FOR_EACH_CHUNK(c, s, end) {
for (k = 0; k != c->len; ++k) {
p = c->ptr + k;
p = (char *)c->ptr + k;
if (i > 7 && !(i == 8 && port == 1))
return -EINVAL;

Expand Down Expand Up @@ -249,7 +249,7 @@ tfw_addr_pton(const TfwStr *str, TfwAddr *addr)
TFW_STR_FOR_EACH_CHUNK(c, str, end) {
int i;
for (i = 0; i != c->len; ++i) {
pos = c->ptr + i;
pos = (char *)c->ptr + i;
if (!isdigit(*pos))
goto delim;
}
Expand Down
3 changes: 3 additions & 0 deletions tempesta_fw/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "msg.h"
#include "peer.h"

#include "http_parser.h"

#include "sync_socket.h"
#include "tls.h"

Expand Down Expand Up @@ -93,6 +95,7 @@ enum {
#define TFW_CONN_COMMON \
SsProto proto; \
TfwGState state; \
TfwHttpParser parser; \
struct list_head list; \
atomic_t refcnt; \
struct timer_list timer; \
Expand Down
19 changes: 11 additions & 8 deletions tempesta_fw/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "cache.h"
#include "http_limits.h"
#include "http_tbl.h"
#include "http_parser.h"
#include "client.h"
#include "http_msg.h"
#include "http_sess.h"
Expand Down Expand Up @@ -1685,14 +1686,20 @@ tfw_http_resp_pair(TfwHttpMsg *hmresp)
static TfwMsg *
tfw_http_conn_msg_alloc(TfwConn *conn)
{
TfwHttpMsg *hm = __tfw_http_msg_alloc(TFW_CONN_TYPE(conn), true);
int type = TFW_CONN_TYPE(conn);
TfwHttpMsg *hm = __tfw_http_msg_alloc(type, true);
if (unlikely(!hm))
return NULL;

hm->conn = conn;
tfw_connection_get(conn);

if (TFW_CONN_TYPE(conn) & Conn_Clnt) {
if (type & Conn_Clnt)
tfw_http_init_parser_req((TfwHttpReq *)hm);
else
tfw_http_init_parser_resp((TfwHttpResp *)hm);

if (type & Conn_Clnt) {
TFW_INC_STAT_BH(clnt.rx_messages);
} else {
if (unlikely(tfw_http_resp_pair(hm))) {
Expand Down Expand Up @@ -2699,7 +2706,7 @@ tfw_http_req_process(TfwConn *conn, const TfwFsmData *data)
bool block = false;
TfwHttpMsg *hmsib = NULL;
TfwHttpReq *req = (TfwHttpReq *)conn->msg;
TfwHttpParser *parser = &req->parser;
TfwHttpParser *parser = &conn->parser;

/*
* Process/parse data in the SKB.
Expand Down Expand Up @@ -3183,7 +3190,7 @@ tfw_http_resp_process(TfwConn *conn, const TfwFsmData *data)
TfwHttpParser *parser;

hmresp = (TfwHttpMsg *)conn->msg;
parser = &hmresp->parser;
parser = &conn->parser;

/*
* Process/parse data in the SKB.
Expand Down Expand Up @@ -4196,10 +4203,6 @@ tfw_http_init(void)
{
int r;

/* Make sure @req->httperr doesn't take too much space. */
BUILD_BUG_ON(FIELD_SIZEOF(TfwHttpMsg, httperr)
> FIELD_SIZEOF(TfwHttpMsg, parser));

r = tfw_gfsm_register_fsm(TFW_FSM_HTTP, tfw_http_msg_process);
if (r)
return r;
Expand Down
106 changes: 3 additions & 103 deletions tempesta_fw/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@

#include <crypto/sha.h>

#include "http_types.h"
#include "connection.h"
#include "gfsm.h"
#include "msg.h"
#include "server.h"
#include "str.h"
#include "vhost.h"

typedef struct tfw_http_sess_t TfwHttpSess;

/**
* HTTP Generic FSM states.
*
Expand Down Expand Up @@ -204,82 +203,6 @@ typedef enum {
TFW_HTTP_HDR_NUM = 16,
} tfw_http_hdr_t;

typedef struct {
unsigned int size; /* number of elements in the table */
unsigned int off;
TfwStr tbl[0];
} TfwHttpHdrTbl;

#define __HHTBL_SZ(o) (TFW_HTTP_HDR_NUM * (o))
#define TFW_HHTBL_EXACTSZ(s) (sizeof(TfwHttpHdrTbl) \
+ sizeof(TfwStr) * (s))
#define TFW_HHTBL_SZ(o) TFW_HHTBL_EXACTSZ(__HHTBL_SZ(o))

/** Maximum of hop-by-hop tokens listed in Connection header. */
#define TFW_HBH_TOKENS_MAX 16

/**
* Non-cacheable hop-by-hop headers in terms of RFC 7230.
*
* We don't store the headers in cache and create them from scratch if needed.
* Adding a header is faster then modify it, so this speeds up headers
* adjusting as well as saves cache storage.
*
* Headers unconditionally treated as hop-by-hop must be listed in
* tfw_http_init_parser_req()/tfw_http_init_parser_resp() functions and must be
* members of Special headers.
* group.
*
* @spec - bit array for special headers. Hop-by-hop special header is
* stored as (0x1 << tfw_http_hdr_t[hid]);
* @raw - table of raw headers names, parsed form connection field;
* @off - offset of last added raw header name;
*/
typedef struct {
unsigned int spec;
unsigned int off;
TfwStr raw[TFW_HBH_TOKENS_MAX];
} TfwHttpHbhHdrs;

/**
* We use goto/switch-driven automaton, so compiler typically generates binary
* search code over jump labels, so it gives log(N) lookup complexity where
* N is number of states. However, DFA for full HTTP processing can be quite
* large and log(N) becomes expensive and hard to code.
*
* So we use states space splitting to avoid states explosion.
* @_i_st is used to save current state and go to interior sub-automaton
* (e.g. process OWS using @state while current state is saved in @_i_st
* or using @_i_st parse value of a header described.
*
* @_cnt - currently the count of hex digits in a body chunk size;
* @to_go - remaining number of bytes to process in the data chunk;
* (limited by single packet size and never exceeds 64KB)
* @state - current parser state;
* @_i_st - helping (interior) state;
* @to_read - remaining number of bytes to read;
* @_hdr_tag - stores header id which must be closed on generic EoL handling
* (see RGEN_EOL());
* @_acc - integer accumulator for parsing chunked integers;
* @_tmp_chunk - currently parsed (sub)string, possibly chunked;
* @hdr - currently parsed header.
* @hbh_parser - list of special and raw headers names to be treated as
* hop-by-hop
* @_date - currently parsed http date value;
*/
typedef struct {
unsigned short to_go;
unsigned short _cnt;
unsigned int _hdr_tag;
int state;
int _i_st;
long to_read;
unsigned long _acc;
time_t _date;
TfwStr _tmp_chunk;
TfwStr hdr;
TfwHttpHbhHdrs hbh_parser;
} TfwHttpParser;

enum {
/* Common flags for requests and responses. */
Expand Down Expand Up @@ -353,7 +276,7 @@ enum {
#define TFW_HTTP_F_RESP_STALE (1U << TFW_HTTP_B_RESP_STALE)
#define TFW_HTTP_F_RESP_READY (1U << TFW_HTTP_B_RESP_READY)

/*
/**
* The structure to hold data for an HTTP error response.
* An error response is sent later in an unlocked queue context.
*
Expand All @@ -365,17 +288,12 @@ typedef struct {
unsigned short status;
}TfwHttpError;

typedef struct tfw_http_msg_t TfwHttpMsg;
typedef struct tfw_http_req_t TfwHttpReq;
typedef struct tfw_http_resp_t TfwHttpResp;

/**
* Common HTTP message members.
*
* @msg - the base data of an HTTP message;
* @pool - message's memory allocation pool;
* @h_tbl - table of message's HTTP headers in internal form;
* @parser - parser state data while a message is parsed;
* @httperr - HTTP error data used to form an error response;
* @pair - the message paired with this one;
* @req - the request paired with this response;
Expand All @@ -395,14 +313,6 @@ typedef struct tfw_http_resp_t TfwHttpResp;
*
* TfwStr members must be the last for efficient scanning.
*
* NOTE: The space taken by @parser member is shared with @httperr member.
* When a message results in an error, the parser state data is not used
* anymore, so this is safe. The reason for reuse is that it's imperative
* that saving the error data succeeds. If it fails, that will lead to
* a request without a response - a hole in @seq_queue. Alternatively,
* memory allocation from pool may fail, even if that's a rare case.
* BUILD_BUG_ON() is used in tfw_http_init() to ensure that @httperr
* doesn't make the whole structure bigger.
*/
#define TFW_HTTP_MSG_COMMON \
TfwMsg msg; \
Expand All @@ -413,10 +323,7 @@ typedef struct tfw_http_resp_t TfwHttpResp;
TfwHttpReq *req; \
TfwHttpResp *resp; \
}; \
union { \
TfwHttpParser parser; \
TfwHttpError httperr; \
}; \
TfwHttpError httperr; \
TfwCacheControl cache_ctl; \
unsigned char version; \
unsigned int flags; \
Expand Down Expand Up @@ -594,13 +501,6 @@ tfw_http_resp_code_range(const int n)

typedef void (*tfw_http_cache_cb_t)(TfwHttpMsg *);

/* Internal (parser) HTTP functions. */
void tfw_http_init_parser_req(TfwHttpReq *req);
void tfw_http_init_parser_resp(TfwHttpResp *resp);
int tfw_http_parse_req(void *req_data, unsigned char *data, size_t len);
int tfw_http_parse_resp(void *resp_data, unsigned char *data, size_t len);
bool tfw_http_parse_terminate(TfwHttpMsg *hm);

/* External HTTP functions. */
int tfw_http_msg_process(void *conn, const TfwFsmData *data);
unsigned long tfw_http_req_key_calc(TfwHttpReq *req);
Expand Down
6 changes: 4 additions & 2 deletions tempesta_fw/http_limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,11 @@ __frang_http_field_len(const TfwHttpReq *req, FrangAcc *ra,
static int
frang_http_field_len(const TfwHttpReq *req, FrangAcc *ra, unsigned int field_len)
{
if (req->parser.hdr.len > field_len) {
TfwHttpParser *parser = &req->conn->parser;

if (parser->hdr.len > field_len) {
frang_limmsg("HTTP in-progress field length",
req->parser.hdr.len, field_len,
parser->hdr.len, field_len,
&FRANG_ACC2CLI(ra)->addr);
return TFW_BLOCK;
}
Expand Down
21 changes: 9 additions & 12 deletions tempesta_fw/http_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "lib/str.h"
#include "gfsm.h"
#include "http_msg.h"
#include "http_parser.h"
#include "ss_skb.h"

/**
Expand Down Expand Up @@ -315,7 +316,7 @@ __hdr_lookup(TfwHttpMsg *hm, const TfwStr *hdr)
void
tfw_http_msg_hdr_open(TfwHttpMsg *hm, unsigned char *hdr_start)
{
TfwStr *hdr = &hm->parser.hdr;
TfwStr *hdr = &hm->conn->parser.hdr;

BUG_ON(!TFW_STR_EMPTY(hdr));

Expand All @@ -337,12 +338,13 @@ tfw_http_msg_hdr_close(TfwHttpMsg *hm, unsigned int id)
{
TfwStr *h;
TfwHttpHdrTbl *ht = hm->h_tbl;
TfwHttpParser *parser = &hm->conn->parser;

BUG_ON(hm->parser.hdr.flags & TFW_STR_DUPLICATE);
BUG_ON(parser->hdr.flags & TFW_STR_DUPLICATE);
BUG_ON(id > TFW_HTTP_HDR_RAW);

/* Close just parsed header. */
hm->parser.hdr.flags |= TFW_STR_COMPLETE;
parser->hdr.flags |= TFW_STR_COMPLETE;

/* Quick path for special headers. */
if (likely(id < TFW_HTTP_HDR_RAW)) {
Expand Down Expand Up @@ -373,7 +375,7 @@ tfw_http_msg_hdr_close(TfwHttpMsg *hm, unsigned int id)
* Both the headers, the new one and existing one, can already be
* compound.
*/
id = __hdr_lookup(hm, &hm->parser.hdr);
id = __hdr_lookup(hm, &parser->hdr);

/* Allocate some more room if not enough to store the header. */
if (unlikely(id == ht->size)) {
Expand All @@ -392,14 +394,14 @@ tfw_http_msg_hdr_close(TfwHttpMsg *hm, unsigned int id)
duplicate:
h = tfw_str_add_duplicate(hm->pool, h);
if (unlikely(!h)) {
TFW_WARN("Cannot close header %p id=%d\n", &hm->parser.hdr, id);
TFW_WARN("Cannot close header %p id=%d\n", &parser->hdr, id);
return TFW_BLOCK;
}

done:
*h = hm->parser.hdr;
*h = parser->hdr;

TFW_STR_INIT(&hm->parser.hdr);
TFW_STR_INIT(&parser->hdr);
TFW_DBG3("store header w/ ptr=%p len=%lu eolen=%u flags=%x id=%d\n",
h->ptr, h->len, h->eolen, h->flags, id);

Expand Down Expand Up @@ -1012,11 +1014,6 @@ __tfw_http_msg_alloc(int type, bool full)
hm->h_tbl->size = __HHTBL_SZ(1);
hm->h_tbl->off = TFW_HTTP_HDR_RAW;
bzero_fast(hm->h_tbl->tbl, __HHTBL_SZ(1) * sizeof(TfwStr));

if (type & Conn_Clnt)
tfw_http_init_parser_req((TfwHttpReq *)hm);
else
tfw_http_init_parser_resp((TfwHttpResp *)hm);
}

hm->msg.skb_head = NULL;
Expand Down
Loading

0 comments on commit 3c278c6

Please sign in to comment.