-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't cache and don't forward hop-by-hop headers #650
Changes from all commits
69f989e
52b8531
44fce2c
a324f43
9af66cb
983a970
66090da
4f4d636
e8c64b3
be64e79
1611092
69fffd8
298b35a
e057b1a
8585f26
5db01cf
f0df55d
ab7b431
bd357b4
386f212
dda3d56
8b5f00e
9f26a4b
fbf0082
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -131,26 +131,6 @@ enum { | |
TFW_CACHE_REPLICA, | ||
}; | ||
|
||
/* | ||
* Non-cacheable hop-by-hop response headers in terms of RFC 2068. | ||
* The table is used if server doesn't specify Cache-Control no-cache | ||
* directive (RFC 7234 5.2.2.2) explicitly. | ||
* | ||
* Server header isn't defined as hop-by-hop by the RFC, but we don't show | ||
* protected server to world. | ||
* | ||
* We don't store the headers in cache and create then from scratch. | ||
* Adding a header is faster then modify it, so this speeds up headers | ||
* adjusting as well as saves cache storage. | ||
* | ||
* TODO process Cache-Control no-cache | ||
*/ | ||
static const int hbh_hdrs[] = { | ||
[0 ... TFW_HTTP_HDR_RAW] = 0, | ||
[TFW_HTTP_HDR_SERVER] = 1, | ||
[TFW_HTTP_HDR_CONNECTION] = 1, | ||
}; | ||
|
||
typedef struct { | ||
int cpu[NR_CPUS]; | ||
atomic_t cpu_idx; | ||
|
@@ -764,9 +744,15 @@ tfw_cache_copy_resp(TfwCacheEntry *ce, TfwHttpResp *resp, TfwHttpReq *req, | |
ce->hdr_len = 0; | ||
ce->hdr_num = resp->h_tbl->off; | ||
FOR_EACH_HDR_FIELD(field, end1, resp) { | ||
n = field - resp->h_tbl->tbl; | ||
/* Skip hop-by-hop headers. */ | ||
h = (n < TFW_HTTP_HDR_RAW && hbh_hdrs[n]) ? &empty : field; | ||
if (!(field->flags & TFW_STR_HBH_HDR)) { | ||
h = field; | ||
} else if (field - resp->h_tbl->tbl < TFW_HTTP_HDR_RAW) { | ||
h = ∅ | ||
} else { | ||
--ce->hdr_num; | ||
continue; | ||
} | ||
n = tfw_cache_copy_hdr(&p, &trec, h, &tot_len); | ||
if (n < 0) { | ||
TFW_ERR("Cache: cannot copy HTTP header\n"); | ||
|
@@ -809,7 +795,6 @@ tfw_cache_copy_resp(TfwCacheEntry *ce, TfwHttpResp *resp, TfwHttpReq *req, | |
static size_t | ||
__cache_entry_size(TfwHttpResp *resp, TfwHttpReq *req) | ||
{ | ||
long n; | ||
size_t size = CE_BODY_SIZE; | ||
TfwStr *h, *hdr, *hdr_end, *dup, *dup_end, empty = {}; | ||
|
||
|
@@ -820,8 +805,13 @@ __cache_entry_size(TfwHttpResp *resp, TfwHttpReq *req) | |
/* Add all the headers size */ | ||
FOR_EACH_HDR_FIELD(hdr, hdr_end, resp) { | ||
/* Skip hop-by-hop headers. */ | ||
n = hdr - resp->h_tbl->tbl; | ||
h = (n < TFW_HTTP_HDR_RAW && hbh_hdrs[n]) ? &empty : hdr; | ||
if (!(hdr->flags & TFW_STR_HBH_HDR)) | ||
h = hdr; | ||
else if (hdr - resp->h_tbl->tbl < TFW_HTTP_HDR_RAW) | ||
h = ∅ | ||
else | ||
continue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see the comment above regarding the use of |
||
|
||
if (!TFW_STR_DUP(h)) { | ||
size += sizeof(TfwCStr); | ||
size += h->len ? (h->len + SLEN(S_CRLF)) : 0; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,47 +136,16 @@ typedef struct { | |
time_t expires; | ||
} TfwCacheControl; | ||
|
||
/** | ||
* 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. | ||
* | ||
* @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; | ||
* @_acc - integer accumulator for parsing chunked integers; | ||
* @_date - accumulator for a date in date related headers; | ||
* @_hdr_tag - stores header id which must be closed on generic EoL handling | ||
* (see RGEN_EOL()); | ||
* @_tmp_chunk - currently parsed (sub)string, possibly chunked; | ||
* @hdr - currently parsed header. | ||
*/ | ||
typedef struct { | ||
unsigned short to_go; | ||
int state; | ||
int _i_st; | ||
int to_read; | ||
unsigned long _acc; | ||
time_t _date; | ||
unsigned int _hdr_tag; | ||
TfwStr _tmp_chunk; | ||
TfwStr hdr; | ||
} TfwHttpParser; | ||
|
||
/** | ||
* Http headers table. | ||
* | ||
* Singular headers (in terms of RFC 7230 3.2.2) go first to protect header | ||
* repetition attacks. See __hdr_is_singular() and don't forget to | ||
* update the static headers array when add a new singular header here. | ||
* If the new header is hop-by-hop (must not be forwarded and cached by Tempesta) | ||
* it must be listed in __hbh_parser_init_req()/__hbh_parser_init_resp() for | ||
* unconditionally hop-by-hop header or in __parse_connection() otherwize. | ||
* If the header is end-to-end it must be listed in __hbh_parser_add_data(). | ||
* | ||
* Note: don't forget to update __http_msg_hdr_val() upon adding a new header. | ||
* | ||
|
@@ -198,6 +167,7 @@ typedef enum { | |
|
||
TFW_HTTP_HDR_CONNECTION = TFW_HTTP_HDR_NONSINGULAR, | ||
TFW_HTTP_HDR_X_FORWARDED_FOR, | ||
TFW_HTTP_HDR_KEEP_ALIVE, | ||
TFW_HTTP_HDR_TRANSFER_ENCODING, | ||
|
||
/* Start of list of generic (raw) headers. */ | ||
|
@@ -217,12 +187,76 @@ typedef struct { | |
+ 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 unconditionaly treated as hop-by-hop must be listed in | ||
* __hbh_parser_init_req()/__hbh_parser_init_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]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps a corresponding proper |
||
* @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. | ||
* | ||
* @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 | ||
*/ | ||
typedef struct { | ||
unsigned short to_go; | ||
int state; | ||
int _i_st; | ||
int to_read; | ||
unsigned long _acc; | ||
time_t _date; | ||
unsigned int _hdr_tag; | ||
TfwStr _tmp_chunk; | ||
TfwStr hdr; | ||
TfwHttpHbhHdrs hbh_parser; | ||
} TfwHttpParser; | ||
|
||
/* Common flags for requests and responses. */ | ||
#define TFW_HTTP_CONN_CLOSE 0x000001 | ||
#define TFW_HTTP_CONN_KA 0x000002 | ||
#define __TFW_HTTP_CONN_MASK (TFW_HTTP_CONN_CLOSE | TFW_HTTP_CONN_KA) | ||
#define TFW_HTTP_CHUNKED 0x000004 | ||
#define TFW_HTTP_MSG_SENT 0x000008 | ||
#define TFW_HTTP_CONN_EXTRA 0x000004 | ||
#define TFW_HTTP_CHUNKED 0x000008 | ||
#define TFW_HTTP_MSG_SENT 0x000010 | ||
|
||
/* Request flags */ | ||
#define TFW_HTTP_HAS_STICKY 0x000100 | ||
|
@@ -263,6 +297,7 @@ typedef struct { | |
* @content_length - the value of Content-Length header field; | ||
* @conn - connection which the message was received on; | ||
* @jtstamp - time the message has been received, in jiffies; | ||
* @keep_alive - the value of timeout specified in Keep-Alive header; | ||
* @crlf - pointer to CRLF between headers and body; | ||
* @body - pointer to the body of a message; | ||
* | ||
|
@@ -278,6 +313,7 @@ typedef struct { | |
unsigned int flags; \ | ||
unsigned long content_length; \ | ||
unsigned long jtstamp; \ | ||
unsigned int keep_alive; \ | ||
TfwConnection *conn; \ | ||
void (*destructor)(void *msg); \ | ||
TfwStr crlf; \ | ||
|
@@ -340,7 +376,6 @@ typedef struct { | |
TFW_HTTP_MSG_COMMON; | ||
TfwStr s_line; | ||
unsigned short status; | ||
unsigned int keep_alive; | ||
time_t date; | ||
} TfwHttpResp; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that
n
is not used as an array index, perhaps it's best to postpone its calculation until theelse if
case.