3 #include "http_header.h"
9 typedef struct keyvlenvalue
{
11 const unsigned int vlen
;
12 const char * const value
;
15 /* Note: must be sorted by length */
16 /* Note: must be kept in sync with http_header.h enum http_header_e */
17 #define CONST_LEN_STR(x) (unsigned int)(sizeof(x)-1), (x)
18 static const keyvlenvalue http_headers
[] = {
19 { HTTP_HEADER_HOST
, CONST_LEN_STR("Host") }
20 ,{ HTTP_HEADER_DATE
, CONST_LEN_STR("Date") }
21 ,{ HTTP_HEADER_ETAG
, CONST_LEN_STR("ETag") }
22 ,{ HTTP_HEADER_VARY
, CONST_LEN_STR("Vary") }
23 ,{ HTTP_HEADER_RANGE
, CONST_LEN_STR("Range") }
24 ,{ HTTP_HEADER_COOKIE
, CONST_LEN_STR("Cookie") }
25 ,{ HTTP_HEADER_EXPECT
, CONST_LEN_STR("Expect") }
26 ,{ HTTP_HEADER_STATUS
, CONST_LEN_STR("Status") }
27 ,{ HTTP_HEADER_SERVER
, CONST_LEN_STR("Server") }
28 ,{ HTTP_HEADER_UPGRADE
, CONST_LEN_STR("Upgrade") }
29 ,{ HTTP_HEADER_LOCATION
, CONST_LEN_STR("Location") }
30 ,{ HTTP_HEADER_FORWARDED
, CONST_LEN_STR("Forwarded") }
31 ,{ HTTP_HEADER_CONNECTION
, CONST_LEN_STR("Connection") }
32 ,{ HTTP_HEADER_SET_COOKIE
, CONST_LEN_STR("Set-Cookie") }
33 ,{ HTTP_HEADER_CONTENT_TYPE
, CONST_LEN_STR("Content-Type") }
34 ,{ HTTP_HEADER_LAST_MODIFIED
, CONST_LEN_STR("Last-Modified") }
35 ,{ HTTP_HEADER_AUTHORIZATION
, CONST_LEN_STR("Authorization") }
36 ,{ HTTP_HEADER_IF_NONE_MATCH
, CONST_LEN_STR("If-None-Match") }
37 ,{ HTTP_HEADER_CACHE_CONTROL
, CONST_LEN_STR("Cache-Control") }
38 ,{ HTTP_HEADER_CONTENT_LENGTH
, CONST_LEN_STR("Content-Length") }
39 ,{ HTTP_HEADER_ACCEPT_ENCODING
, CONST_LEN_STR("Accept-Encoding") }
40 ,{ HTTP_HEADER_X_FORWARDED_FOR
, CONST_LEN_STR("X-Forwarded-For") }
41 ,{ HTTP_HEADER_CONTENT_ENCODING
, CONST_LEN_STR("Content-Encoding") }
42 ,{ HTTP_HEADER_CONTENT_LOCATION
, CONST_LEN_STR("Content-Location") }
43 ,{ HTTP_HEADER_IF_MODIFIED_SINCE
, CONST_LEN_STR("If-Modified-Since") }
44 ,{ HTTP_HEADER_TRANSFER_ENCODING
, CONST_LEN_STR("Transfer-Encoding") }
45 ,{ HTTP_HEADER_X_FORWARDED_PROTO
, CONST_LEN_STR("X-Forwarded-Proto") }
46 ,{ HTTP_HEADER_OTHER
, 0, NULL
}
49 enum http_header_e
http_header_hkey_get(const char *s
, size_t slen
) {
50 const struct keyvlenvalue
* const kv
= http_headers
;
51 for (int i
= 0; kv
[i
].vlen
&& slen
>= kv
[i
].vlen
; ++i
) {
52 if (slen
== kv
[i
].vlen
53 && buffer_eq_icase_ssn(s
, kv
[i
].value
, slen
))
54 return (enum http_header_e
)kv
[i
].key
;
56 return HTTP_HEADER_OTHER
;
60 buffer
* http_header_response_get(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
) {
61 data_string
* const ds
=
62 (id
<= HTTP_HEADER_OTHER
|| (con
->response
.htags
& id
))
63 ? (data_string
*)array_get_element_klen(con
->response
.headers
, k
, klen
)
65 return ds
&& !buffer_string_is_empty(ds
->value
) ? ds
->value
: NULL
;
68 void http_header_response_unset(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
) {
69 if (id
<= HTTP_HEADER_OTHER
|| (con
->response
.htags
& id
)) {
70 if (id
> HTTP_HEADER_OTHER
) con
->response
.htags
&= ~id
;
71 array_set_key_value(con
->response
.headers
, k
, klen
, CONST_STR_LEN(""));
75 void http_header_response_set(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
76 /* set value, including setting blank value if 0 == vlen
77 * (note: if 0 == vlen, header is still inserted with blank value,
78 * which is used to indicate a "removed" header)
80 if (id
> HTTP_HEADER_OTHER
)
81 (vlen
) ? (con
->response
.htags
|= id
) : (con
->response
.htags
&= ~id
);
82 array_set_key_value(con
->response
.headers
, k
, klen
, v
, vlen
);
85 void http_header_response_append(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
87 data_string
*ds
= (id
<= HTTP_HEADER_OTHER
|| (con
->response
.htags
& id
))
88 ? (data_string
*)array_get_element_klen(con
->response
.headers
,k
,klen
)
90 if (id
> HTTP_HEADER_OTHER
) con
->response
.htags
|= id
;
92 array_insert_key_value(con
->response
.headers
, k
, klen
, v
, vlen
);
94 else { /* append value */
95 buffer
*vb
= ds
->value
;
96 if (!buffer_string_is_empty(vb
))
97 buffer_append_string_len(vb
, CONST_STR_LEN(", "));
98 buffer_append_string_len(vb
, v
, vlen
);
103 void http_header_response_insert(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
105 data_string
*ds
= (id
<= HTTP_HEADER_OTHER
|| (con
->response
.htags
& id
))
106 ? (data_string
*)array_get_element_klen(con
->response
.headers
,k
,klen
)
108 if (id
> HTTP_HEADER_OTHER
) con
->response
.htags
|= id
;
110 array_insert_key_value(con
->response
.headers
, k
, klen
, v
, vlen
);
112 else { /* append value */
113 buffer
*vb
= ds
->value
;
114 if (!buffer_string_is_empty(vb
)) {
115 buffer_append_string_len(vb
, CONST_STR_LEN("\r\n"));
116 buffer_append_string_len(vb
, k
, klen
);
117 buffer_append_string_len(vb
, CONST_STR_LEN(": "));
119 buffer_append_string_len(vb
, v
, vlen
);
125 buffer
* http_header_request_get(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
) {
126 data_string
* const ds
=
127 (id
<= HTTP_HEADER_OTHER
|| (con
->request
.htags
& id
))
128 ? (data_string
*)array_get_element_klen(con
->request
.headers
, k
, klen
)
130 return ds
&& !buffer_string_is_empty(ds
->value
) ? ds
->value
: NULL
;
133 void http_header_request_unset(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
) {
134 if (id
<= HTTP_HEADER_OTHER
|| (con
->request
.htags
& id
)) {
135 if (id
> HTTP_HEADER_OTHER
) con
->request
.htags
&= ~id
;
136 array_set_key_value(con
->request
.headers
, k
, klen
, CONST_STR_LEN(""));
140 void http_header_request_set(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
141 /* set value, including setting blank value if 0 == vlen
142 * (note: if 0 == vlen, header is still inserted with blank value,
143 * which is used to indicate a "removed" header)
145 if (id
> HTTP_HEADER_OTHER
)
146 (vlen
) ? (con
->request
.htags
|= id
) : (con
->request
.htags
&= ~id
);
147 array_set_key_value(con
->request
.headers
, k
, klen
, v
, vlen
);
150 void http_header_request_append(connection
*con
, enum http_header_e id
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
152 data_string
*ds
= (id
<= HTTP_HEADER_OTHER
|| (con
->request
.htags
& id
))
153 ? (data_string
*)array_get_element_klen(con
->request
.headers
, k
, klen
)
155 if (id
> HTTP_HEADER_OTHER
) con
->request
.htags
|= id
;
157 array_insert_key_value(con
->request
.headers
, k
, klen
, v
, vlen
);
159 else { /* append value */
160 buffer
*vb
= ds
->value
;
161 if (!buffer_string_is_empty(vb
))
162 buffer_append_string_len(vb
, CONST_STR_LEN(", "));
163 buffer_append_string_len(vb
, v
, vlen
);
169 buffer
* http_header_env_get(connection
*con
, const char *k
, size_t klen
) {
170 data_string
* const ds
=
171 (data_string
*)array_get_element_klen(con
->environment
, k
, klen
);
172 return ds
&& !buffer_string_is_empty(ds
->value
) ? ds
->value
: NULL
;
175 void http_header_env_set(connection
*con
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
176 array_set_key_value(con
->environment
, k
, klen
, v
, vlen
);
179 void http_header_env_append(connection
*con
, const char *k
, size_t klen
, const char *v
, size_t vlen
) {
180 /*if (vlen)*/ /* skip check; permit env var w/ blank value to be appended */
182 buffer
* const vb
= http_header_env_get(con
, k
, klen
);
184 array_insert_key_value(con
->environment
, k
, klen
, v
, vlen
);
186 else if (vlen
) { /* append value */
187 buffer_append_string_len(vb
, CONST_STR_LEN(", "));
188 buffer_append_string_len(vb
, v
, vlen
);