1 /*
2  * Copyright 2008-2014 Arsen Chaloyan
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Id: mrcp_generic_header.c 2136 2014-07-04 06:33:36Z achaloyan@gmail.com $
17  */
18 
19 #include "mrcp_generic_header.h"
20 #include "mrcp_start_line.h"
21 
22 /** String table of mrcp generic-header fields (mrcp_generic_header_id) */
23 static const apt_str_table_item_t generic_header_string_table[] = {
24 	{{"Active-Request-Id-List",    22},3},
25 	{{"Proxy-Sync-Id",             13},0},
26 	{{"Accept-Charset",            14},7},
27 	{{"Content-Type",              12},9},
28 	{{"Content-Id",                10},9},
29 	{{"Content-Base",              12},8},
30 	{{"Content-Encoding",          16},9},
31 	{{"Content-Location",          16},9},
32 	{{"Content-Length",            14},10},
33 	{{"Cache-Control",             13},1},
34 	{{"Logging-Tag",               11},0},
35 	{{"Vendor-Specific-Parameters",26},0},
36 	{{"Accept",                     6},6},
37 	{{"Fetch-Timeout",             13},0},
38 	{{"Set-Cookie",                10},10},
39 	{{"Set-Cookie2",               11},10}
40 };
41 
42 /** Parse mrcp request-id list */
mrcp_request_id_list_parse(mrcp_request_id_list_t * request_id_list,const apt_str_t * value)43 static apt_bool_t mrcp_request_id_list_parse(mrcp_request_id_list_t *request_id_list, const apt_str_t *value)
44 {
45 	apt_str_t field;
46 	apt_text_stream_t stream;
47 	stream.text = *value;
48 	apt_text_stream_reset(&stream);
49 	request_id_list->count = 0;
50 	while(request_id_list->count < MAX_ACTIVE_REQUEST_ID_COUNT) {
51 		if(apt_text_field_read(&stream,',',TRUE,&field) == FALSE) {
52 			break;
53 		}
54 		request_id_list->ids[request_id_list->count] = mrcp_request_id_parse(&field);
55 		request_id_list->count++;
56 	}
57 	return TRUE;
58 }
59 
60 /** Generate mrcp request-id list */
mrcp_request_id_list_generate(const mrcp_request_id_list_t * request_id_list,apt_str_t * str,apr_pool_t * pool)61 static apt_bool_t mrcp_request_id_list_generate(const mrcp_request_id_list_t *request_id_list, apt_str_t *str, apr_pool_t *pool)
62 {
63 	apr_size_t i;
64 	int length;
65 	char *pos;
66 
67 	/* compute estimated length, assuming request-ids consist of upto 10 digits */
68 	str->length = 10 * request_id_list->count;
69 	if(request_id_list->count > 1) {
70 		/* , */
71 		str->length += request_id_list->count - 1;
72 	}
73 
74 	str->buf = apr_palloc(pool,str->length + 1);
75 
76 	pos = str->buf;
77 	for(i=0; i<request_id_list->count; i++) {
78 		if(i != 0) {
79 			*pos++ = ',';
80 		}
81 
82 		length = apr_snprintf(pos, str->length - (pos - str->buf), "%"MRCP_REQUEST_ID_FMT, request_id_list->ids[i]);
83 		if(length < 0)
84 			return FALSE;
85 		pos += length;
86 	}
87 	*pos = '\0';
88 	return TRUE;
89 }
90 
91 
92 /** Initialize generic-header */
mrcp_generic_header_init(mrcp_generic_header_t * generic_header)93 static void mrcp_generic_header_init(mrcp_generic_header_t *generic_header)
94 {
95 	generic_header->active_request_id_list.count = 0;
96 	apt_string_reset(&generic_header->proxy_sync_id);
97 	apt_string_reset(&generic_header->accept_charset);
98 	apt_string_reset(&generic_header->content_type);
99 	apt_string_reset(&generic_header->content_id);
100 	apt_string_reset(&generic_header->content_base);
101 	apt_string_reset(&generic_header->content_encoding);
102 	apt_string_reset(&generic_header->content_location);
103 	generic_header->content_length = 0;
104 	apt_string_reset(&generic_header->cache_control);
105 	apt_string_reset(&generic_header->logging_tag);
106 	generic_header->vendor_specific_params = NULL;
107 	/* initializes additionnal MRCP v2 generic header fields */
108 	apt_string_reset(&generic_header->accept);
109 	generic_header->fetch_timeout = 0;
110 	apt_string_reset(&generic_header->set_cookie);
111 	apt_string_reset(&generic_header->set_cookie2);
112 }
113 
114 
115 /** Allocate generic-header */
mrcp_generic_header_allocate(mrcp_header_accessor_t * accessor,apr_pool_t * pool)116 static void* mrcp_generic_header_allocate(mrcp_header_accessor_t *accessor, apr_pool_t *pool)
117 {
118 	mrcp_generic_header_t *generic_header = apr_palloc(pool,sizeof(mrcp_generic_header_t));
119 	mrcp_generic_header_init(generic_header);
120 	accessor->data = generic_header;
121 	return accessor->data;
122 }
123 
124 /** Parse generic-header */
mrcp_generic_header_parse(mrcp_header_accessor_t * accessor,size_t id,const apt_str_t * value,apr_pool_t * pool)125 static apt_bool_t mrcp_generic_header_parse(mrcp_header_accessor_t *accessor, size_t id, const apt_str_t *value, apr_pool_t *pool)
126 {
127 	apt_bool_t status = TRUE;
128 	mrcp_generic_header_t *generic_header = accessor->data;
129 	switch(id) {
130 		case GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST:
131 			mrcp_request_id_list_parse(&generic_header->active_request_id_list,value);
132 			break;
133 		case GENERIC_HEADER_PROXY_SYNC_ID:
134 			generic_header->proxy_sync_id = *value;
135 			break;
136 		case GENERIC_HEADER_ACCEPT_CHARSET:
137 			generic_header->accept_charset = *value;
138 			break;
139 		case GENERIC_HEADER_CONTENT_TYPE:
140 			generic_header->content_type =  *value;
141 			break;
142 		case GENERIC_HEADER_CONTENT_ID:
143 			generic_header->content_id = *value;
144 			break;
145 		case GENERIC_HEADER_CONTENT_BASE:
146 			generic_header->content_base = *value;
147 			break;
148 		case GENERIC_HEADER_CONTENT_ENCODING:
149 			generic_header->content_encoding = *value;
150 			break;
151 		case GENERIC_HEADER_CONTENT_LOCATION:
152 			generic_header->content_location = *value;
153 			break;
154 		case GENERIC_HEADER_CONTENT_LENGTH:
155 			generic_header->content_length = apt_size_value_parse(value);
156 			break;
157 		case GENERIC_HEADER_CACHE_CONTROL:
158 			generic_header->cache_control = *value;
159 			break;
160 		case GENERIC_HEADER_LOGGING_TAG:
161 			generic_header->logging_tag = *value;
162 			break;
163 		case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS:
164 			if(!generic_header->vendor_specific_params) {
165 				generic_header->vendor_specific_params = apt_pair_array_create(1,pool);
166 			}
167 			apt_pair_array_parse(generic_header->vendor_specific_params,value,pool);
168 			break;
169 		case GENERIC_HEADER_ACCEPT:
170 			generic_header->accept = *value;
171 			break;
172 		case GENERIC_HEADER_FETCH_TIMEOUT:
173 			generic_header->fetch_timeout = apt_size_value_parse(value);
174 			break;
175 		case GENERIC_HEADER_SET_COOKIE:
176 			generic_header->set_cookie = *value;
177 			break;
178 		case GENERIC_HEADER_SET_COOKIE2:
179 			generic_header->set_cookie2 = *value;
180 			break;
181 		default:
182 			status = FALSE;
183 	}
184 	return status;
185 }
186 
187 /** Generate generic-header */
mrcp_generic_header_generate(const mrcp_header_accessor_t * accessor,apr_size_t id,apt_str_t * value,apr_pool_t * pool)188 static apt_bool_t mrcp_generic_header_generate(const mrcp_header_accessor_t *accessor, apr_size_t id, apt_str_t *value, apr_pool_t *pool)
189 {
190 	mrcp_generic_header_t *generic_header = accessor->data;
191 	switch(id) {
192 		case GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST:
193 			mrcp_request_id_list_generate(&generic_header->active_request_id_list,value,pool);
194 			break;
195 		case GENERIC_HEADER_PROXY_SYNC_ID:
196 			*value = generic_header->proxy_sync_id;
197 			break;
198 		case GENERIC_HEADER_ACCEPT_CHARSET:
199 			*value = generic_header->accept_charset;
200 			break;
201 		case GENERIC_HEADER_CONTENT_TYPE:
202 			*value = generic_header->content_type;
203 			break;
204 		case GENERIC_HEADER_CONTENT_ID:
205 			*value = generic_header->content_id;
206 			break;
207 		case GENERIC_HEADER_CONTENT_BASE:
208 			*value = generic_header->content_base;
209 			break;
210 		case GENERIC_HEADER_CONTENT_ENCODING:
211 			*value = generic_header->content_encoding;
212 			break;
213 		case GENERIC_HEADER_CONTENT_LOCATION:
214 			*value = generic_header->content_location;
215 			break;
216 		case GENERIC_HEADER_CONTENT_LENGTH:
217 			apt_size_value_generate(generic_header->content_length,value,pool);
218 			break;
219 		case GENERIC_HEADER_CACHE_CONTROL:
220 			*value = generic_header->cache_control;
221 			break;
222 		case GENERIC_HEADER_LOGGING_TAG:
223 			*value = generic_header->logging_tag;
224 			break;
225 		case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS:
226 			apt_pair_array_generate(generic_header->vendor_specific_params,value,pool);
227 			break;
228 		case GENERIC_HEADER_ACCEPT:
229 			*value = generic_header->accept;
230 			break;
231 		case GENERIC_HEADER_FETCH_TIMEOUT:
232 			apt_size_value_generate(generic_header->fetch_timeout,value,pool);
233 			break;
234 		case GENERIC_HEADER_SET_COOKIE:
235 			*value = generic_header->set_cookie;
236 			break;
237 		case GENERIC_HEADER_SET_COOKIE2:
238 			*value = generic_header->set_cookie2;
239 			break;
240 		default:
241 			break;
242 	}
243 	return TRUE;
244 }
245 
246 /** Duplicate generic-header */
mrcp_generic_header_duplicate(mrcp_header_accessor_t * accessor,const mrcp_header_accessor_t * src,apr_size_t id,const apt_str_t * value,apr_pool_t * pool)247 static apt_bool_t mrcp_generic_header_duplicate(mrcp_header_accessor_t *accessor, const mrcp_header_accessor_t *src, apr_size_t id, const apt_str_t *value, apr_pool_t *pool)
248 {
249 	mrcp_generic_header_t *generic_header = accessor->data;
250 	const mrcp_generic_header_t *src_generic_header = src->data;
251 	apt_bool_t status = TRUE;
252 
253 	if(!generic_header || !src_generic_header) {
254 		return FALSE;
255 	}
256 
257 	switch(id) {
258 		case GENERIC_HEADER_ACTIVE_REQUEST_ID_LIST:
259 			break;
260 		case GENERIC_HEADER_PROXY_SYNC_ID:
261 			generic_header->proxy_sync_id = *value;
262 			break;
263 		case GENERIC_HEADER_ACCEPT_CHARSET:
264 			generic_header->accept_charset = *value;
265 			break;
266 		case GENERIC_HEADER_CONTENT_TYPE:
267 			generic_header->content_type = *value;
268 			break;
269 		case GENERIC_HEADER_CONTENT_ID:
270 			generic_header->content_id = *value;
271 			break;
272 		case GENERIC_HEADER_CONTENT_BASE:
273 			generic_header->content_base = *value;
274 			break;
275 		case GENERIC_HEADER_CONTENT_ENCODING:
276 			generic_header->content_encoding = *value;
277 			break;
278 		case GENERIC_HEADER_CONTENT_LOCATION:
279 			generic_header->content_location = *value;
280 			break;
281 		case GENERIC_HEADER_CONTENT_LENGTH:
282 			generic_header->content_length = src_generic_header->content_length;
283 			break;
284 		case GENERIC_HEADER_CACHE_CONTROL:
285 			generic_header->cache_control = *value;
286 			break;
287 		case GENERIC_HEADER_LOGGING_TAG:
288 			generic_header->logging_tag = *value;
289 			break;
290 		case GENERIC_HEADER_VENDOR_SPECIFIC_PARAMS:
291 			generic_header->vendor_specific_params = apt_pair_array_copy(src_generic_header->vendor_specific_params,pool);
292 			break;
293 		case GENERIC_HEADER_ACCEPT:
294 			generic_header->accept = *value;
295 			break;
296 		case GENERIC_HEADER_FETCH_TIMEOUT:
297 			generic_header->fetch_timeout = src_generic_header->fetch_timeout;
298 			break;
299 		case GENERIC_HEADER_SET_COOKIE:
300 			generic_header->set_cookie = *value;
301 			break;
302 		case GENERIC_HEADER_SET_COOKIE2:
303 			generic_header->set_cookie2 = *value;
304 			break;
305 		default:
306 			status = FALSE;
307 	}
308 	return status;
309 }
310 
311 static const mrcp_header_vtable_t vtable = {
312 	mrcp_generic_header_allocate,
313 	NULL, /* nothing to destroy */
314 	mrcp_generic_header_parse,
315 	mrcp_generic_header_generate,
316 	mrcp_generic_header_duplicate,
317 	generic_header_string_table,
318 	GENERIC_HEADER_COUNT
319 };
320 
321 
mrcp_generic_header_vtable_get(mrcp_version_e version)322 MRCP_DECLARE(const mrcp_header_vtable_t*) mrcp_generic_header_vtable_get(mrcp_version_e version)
323 {
324 	return &vtable;
325 }
326 
327 
328 /** Append active request id list */
active_request_id_list_append(mrcp_generic_header_t * generic_header,mrcp_request_id request_id)329 MRCP_DECLARE(apt_bool_t) active_request_id_list_append(mrcp_generic_header_t *generic_header, mrcp_request_id request_id)
330 {
331 	mrcp_request_id_list_t *request_id_list = &generic_header->active_request_id_list;
332 	if(request_id_list->count >= MAX_ACTIVE_REQUEST_ID_COUNT) {
333 		return FALSE;
334 	}
335 	request_id_list->ids[request_id_list->count++] = request_id;
336 	return TRUE;
337 }
338 
339 /** Find request id in active request id list */
active_request_id_list_find(const mrcp_generic_header_t * generic_header,mrcp_request_id request_id)340 MRCP_DECLARE(apt_bool_t) active_request_id_list_find(const mrcp_generic_header_t *generic_header, mrcp_request_id request_id)
341 {
342 	size_t i;
343 	const mrcp_request_id_list_t *request_id_list = &generic_header->active_request_id_list;
344 	for(i=0; i<request_id_list->count; i++) {
345 		if(request_id_list->ids[i] == request_id) {
346 			return TRUE;
347 		}
348 	}
349 	return FALSE;
350 }
351