-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrequest.c
More file actions
178 lines (145 loc) · 4.43 KB
/
request.c
File metadata and controls
178 lines (145 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <assert.h>
#include <ck_spinlock.h>
#include "hash.h"
#include "request.h"
#include "truncate.h"
#include "util.h"
static size_t
init_raw_request_from_src(const char *src, char *raw_buf, size_t raw_size)
{
/* Compute request field length */
const char *s = src;
size_t method_size = strcspn(s, " ");
s += method_size + 1;
size_t sep_size = strspn(s, " \t\v");
s += sep_size + 1;
size_t url_size = strcspn(s, "?\" \n");
size_t req_size = method_size + sep_size + url_size + 2;
if (raw_size < req_size)
WARNX("truncating request over %zu bytes long", raw_size);
req_size = MIN(req_size, raw_size);
memcpy(raw_buf, src, req_size);
raw_buf[req_size] = '\0';
return req_size;
}
static size_t
init_raw_request_from_fields(struct request_info *ri, char *raw_buf, size_t raw_size)
{
assert(ri->method != NULL);
assert(ri->domain != NULL);
assert(ri->endpoint != NULL);
size_t method_size = strcspn(ri->method, " \t");
size_t sep_size = 1;
size_t protocol_size = 0;
size_t protocol_sep_size = 0; /* ":// */
if (ri->protocol != NULL) {
protocol_size = strcspn(ri->protocol, " \t");
protocol_sep_size = 3;
}
size_t domain_size = strcspn(ri->domain, " \t");
size_t endpoint_size = strcspn(ri->endpoint, " \t");
size_t req_size = method_size + sep_size + protocol_size
+ protocol_sep_size + domain_size + endpoint_size;
if (raw_size < req_size)
WARNX("truncating request over %zu bytes long", raw_size);
req_size = MIN(req_size, raw_size);
char *s = raw_buf;
memcpy(s, ri->method, method_size);
s += method_size;
*s++ = ' ';
if (ri->protocol != NULL) {
memcpy(s, ri->protocol, protocol_size);
s += protocol_size;
memcpy(s, "://", protocol_sep_size);
s += protocol_sep_size;
}
memcpy(s, ri->domain, domain_size);
s += domain_size;
memcpy(s, ri->endpoint, endpoint_size);
s += endpoint_size;
raw_buf[req_size] = '\0';
return req_size;
}
/*
* Stores a request field pointed to by src into the request set rs.
* Returns a numeric request ID.
*/
request_id_t
add_request_set_entry(struct request_set *rs, struct request_info *ri,
struct truncate_patterns *tp)
{
assert(rs != NULL);
assert(ri != NULL);
assert(tp != NULL);
size_t hash = hash64_init();
struct request_set_entry **handlep;
ck_spinlock_t *bucket_lock;
struct request_set_entry *entry;
#define REQUEST_LEN_MAX 4096
char raw_buf[REQUEST_LEN_MAX + 1] = {0};
size_t req_size = 0;
if (ri->request != NULL)
req_size = init_raw_request_from_src(ri->request, raw_buf, sizeof(raw_buf) - 1);
else
req_size = init_raw_request_from_fields(ri, raw_buf, sizeof(raw_buf) - 1);
char trunc_buf[req_size + tp->max_alias_size * REQUEST_NTRUNCS_MAX + 1];
size_t trunc_size = truncate_raw_request(trunc_buf, sizeof(trunc_buf) - 1,
raw_buf, req_size, tp);
hash = hash64_update(hash, trunc_buf, trunc_size);
size_t bucket_idx = hash & REQUEST_SET_BUCKET_MASK;
handlep = &rs->handles[bucket_idx];
bucket_lock = &rs->locks[bucket_idx];
entry = NULL;
ck_spinlock_lock(bucket_lock);
HASH_FIND(hh, *handlep, trunc_buf, trunc_size, entry);
if (entry != NULL)
goto finish;
entry = calloc(1, sizeof(*entry));
if (entry == NULL)
ERR("%s", "calloc");
entry->data = calloc(1, trunc_size + 1);
if (entry->data == NULL)
ERR("%s", "calloc");
memcpy(entry->data, trunc_buf, trunc_size);
ck_spinlock_lock(&rs->rid_lock);
entry->hash = hash;
entry->rid = rs->rid_ctr++;
ck_spinlock_unlock(&rs->rid_lock);
HASH_ADD_KEYPTR(hh, *handlep, entry->data, trunc_size, entry);
rs->nrequests++;
finish:
ck_spinlock_unlock(bucket_lock);
return entry->rid;
}
void
init_request_set(struct request_set *rs)
{
for (size_t i = 0; i< REQUEST_SET_NBUCKETS; i++) {
rs->handles[i] = NULL;
ck_spinlock_init(&rs->locks[i]);
}
ck_spinlock_init(&rs->rid_lock);
rs->nrequests = 0;
rs->rid_ctr = REQUEST_ID_START;
}
void
gen_request_table(struct request_table *rt, struct request_set *rs)
{
assert(rt != NULL);
assert(rs != NULL);
rt->nrequests = rs->nrequests;
rt->requests = calloc(rt->nrequests, sizeof(*rt->requests));
if (rt->requests == NULL)
ERR("%s", "calloc");
rt->hashes = calloc(rt->nrequests, sizeof(*rt->hashes));
if (rt->hashes == NULL)
ERR("%s", "calloc");
for (size_t bucket_idx = 0; bucket_idx < REQUEST_SET_NBUCKETS; bucket_idx++) {
struct request_set_entry *entry, *tmp;
HASH_ITER(hh, rs->handles[bucket_idx], entry, tmp) {
request_id_t rid = entry->rid;
rt->requests[rid] = entry->data;
rt->hashes[rid] = entry->hash;
}
}
}