File Coverage

third_party/modest/source/myurl/host.c
Criterion Covered Total %
statement 0 262 0.0
branch 0 178 0.0
condition n/a
subroutine n/a
pod n/a
total 0 440 0.0


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2016-2017 Alexander Borisov
3            
4             This library is free software; you can redistribute it and/or
5             modify it under the terms of the GNU Lesser General Public
6             License as published by the Free Software Foundation; either
7             version 2.1 of the License, or (at your option) any later version.
8            
9             This library is distributed in the hope that it will be useful,
10             but WITHOUT ANY WARRANTY; without even the implied warranty of
11             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12             Lesser General Public License for more details.
13            
14             You should have received a copy of the GNU Lesser General Public
15             License along with this library; if not, write to the Free Software
16             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17            
18             Author: lex.borisov@gmail.com (Alexander Borisov)
19             */
20              
21             #include "myurl/host.h"
22             #include "myurl/url.h"
23             #include "myurl/resources.h"
24             #include "mycore/utils/resources.h"
25              
26 0           myurl_host_t * myurl_host_create(myurl_t* url)
27             {
28 0           myurl_host_t *host = url->callback_malloc(sizeof(myurl_host_t), url->callback_ctx);
29            
30 0 0         if(host)
31 0           memset(host, 0, sizeof(myurl_host_t));
32            
33 0           return host;
34             }
35              
36 0           mystatus_t myurl_host_init(myurl_t* url)
37             {
38 0           return MyURL_STATUS_OK;
39             }
40              
41 0           void myurl_host_clean(myurl_t* url, myurl_host_t* host)
42             {
43 0 0         if(host->type == MyURL_HOST_TYPE_DOMAIN)
44 0           url->callback_free(host->value.domain.value, url->callback_ctx);
45            
46 0 0         if(host->type == MyURL_HOST_TYPE_OPAQUE)
47 0           url->callback_free(host->value.opaque.value, url->callback_ctx);
48            
49 0           memset(host, 0, sizeof(myurl_host_t));
50 0           }
51              
52 0           myurl_host_t * myurl_host_destroy(myurl_t* url, myurl_host_t* host, bool destroy_self)
53             {
54 0 0         if(host == NULL)
55 0           return NULL;
56            
57 0           myurl_host_clean(url, host);
58            
59 0 0         if(destroy_self) {
60 0           return url->callback_free(host, url->callback_ctx);
61             }
62            
63 0           return host;
64             }
65              
66 0           mystatus_t myurl_host_copy(myurl_t* url, myurl_host_t* host_from, myurl_host_t* host_to)
67             {
68 0           host_to->type = host_from->type;
69            
70 0 0         switch (host_from->type) {
71             case MyURL_HOST_TYPE_DOMAIN:
72 0           return myurl_utils_data_copy_set(url, host_from->value.domain.value, host_from->value.domain.length,
73             &host_to->value.domain.value, &host_to->value.domain.length);
74            
75             default:
76 0           break;
77             }
78            
79 0           return MyURL_STATUS_OK;
80             }
81              
82             /* Create Values */
83 0           myurl_host_ipv_t * myurl_host_ipv6_entry_create(myurl_t* url)
84             {
85 0           myurl_host_ipv_t *ipv = url->callback_malloc(sizeof(myurl_host_ipv_t), url->callback_ctx);
86            
87 0 0         if(ipv)
88 0           memset(ipv, 0, sizeof(myurl_host_ipv_t));
89            
90 0           return ipv;
91             }
92              
93             /* Parsing */
94 0           mystatus_t myurl_host_parser(myurl_t* url, myurl_host_t* host, const char* data, size_t data_size, bool is_special)
95             {
96 0           size_t data_length = 0;
97            
98             /* 1 */
99 0 0         if(data[data_length] == '[') {
100 0 0         if(data[ (data_size - 1) ] != ']') {
101             // parse error
102 0           return MyURL_STATUS_ERROR;
103             }
104            
105 0           data_length++;
106            
107 0           host->type = MyURL_HOST_TYPE_IPv6;
108 0           return myurl_host_ipv6_parser(&host->value.ipv, &data[data_length], (data_size - 2));
109             }
110            
111             /* 2 */
112 0 0         if(is_special == false) {
113 0           host->type = MyURL_HOST_TYPE_OPAQUE;
114 0           return myurl_host_opaque_host_parser(url, &host->value.opaque, data, data_size);
115             }
116            
117             /* 3 */
118 0           char *domain = myurl_utils_data_copy(url, data, data_size);
119 0           size_t domain_size = myurl_utils_percent_decode_bytes_in_data(domain, data_size);
120            
121             /* 4 */
122             char* ascii_domain;
123             size_t ascii_domain_size;
124 0           mystatus_t status = myurl_host_domain_to_ascii(url, &ascii_domain, &ascii_domain_size, domain, domain_size,
125             false, false, MyURL_HOST_IDNA_PROCESSING_OPTION_NONTRANSITIONAL);
126             /* 5 */
127 0 0         if(status != MyURL_STATUS_OK) {
128             // parse error
129 0           return status;
130             }
131            
132             /* 6 */
133 0           const unsigned char *u_ascii_domain = (const unsigned char*)ascii_domain;
134 0           data_length = 0;
135            
136 0 0         while(data_length < ascii_domain_size) {
137 0 0         if(myurl_resources_static_map_forbidden_host_code_point[ u_ascii_domain[data_length] ] != 0xff) {
138             // parse error
139 0           return MyURL_STATUS_ERROR;
140             }
141            
142 0           data_length++;
143             }
144            
145             /* 7 */
146             bool failure;
147 0 0         if(myurl_host_ipv4_parser(&host->value.ipv, ascii_domain, ascii_domain_size, &failure) == MyURL_STATUS_OK) {
148 0           url->callback_free(ascii_domain, url->callback_ctx);
149            
150 0           host->type = MyURL_HOST_TYPE_IPv4;
151 0           return MyURL_STATUS_OK;
152             }
153            
154 0 0         if(failure) {
155             // parse error
156 0           url->callback_free(ascii_domain, url->callback_ctx);
157 0           return MyURL_STATUS_ERROR;
158             }
159            
160 0           host->type = MyURL_HOST_TYPE_DOMAIN;
161 0           host->value.domain.value = ascii_domain;
162 0           host->value.domain.length = ascii_domain_size;
163            
164 0           return MyURL_STATUS_OK;
165             }
166              
167 0           mystatus_t myurl_host_domain_to_ascii(myurl_t* url, char** return_domain, size_t* return_domain_size,
168             char* domain, size_t domain_size,
169             bool UseSTD3ASCIIRules, bool VerifyDnsLength,
170             myurl_host_idna_processing_option_t opt)
171             {
172            
173            
174            
175 0           *return_domain = domain;
176 0           *return_domain_size = domain_size;
177            
178 0           return MyURL_STATUS_OK;
179             }
180              
181 0           mystatus_t myurl_host_opaque_host_parser(myurl_t* url, myurl_host_opaque_t* opaque, const char* data, size_t data_size)
182             {
183             // TODO: see this
184             /* 1 */
185             /* If input contains a forbidden host code point excluding "%", validation error, return failure. */
186 0           size_t length = 0, offset = 0;
187 0           const unsigned char *u_data = (const unsigned char*)data;
188            
189 0 0         while(length < data_size) {
190 0 0         if(myurl_resources_static_map_forbidden_host_code_point[ u_data[length] ] != 0xff) {
191 0           offset = length;
192            
193 0 0         while(offset) {
194 0           offset--;
195            
196 0 0         if(data[offset] == '%') {
197 0           break;
198             }
199             }
200            
201 0 0         if(offset == 0 && data[offset] != '%') {
    0          
202             // parse error
203 0           return MyURL_STATUS_ERROR;
204             }
205             }
206            
207 0           length++;
208             }
209            
210             /* 2 */
211 0           length = 0;
212 0           char *in_hex_val = myurl_utils_percent_encode(url, data, data_size, myurl_resources_static_map_C0, &length);
213            
214 0 0         if(in_hex_val == NULL) {
215             // parse error
216 0           return MyURL_STATUS_ERROR;
217             }
218            
219             /* 3 */
220 0           opaque->value = in_hex_val;
221 0           opaque->length = length;
222            
223 0           return MyURL_STATUS_OK;
224             }
225              
226 0           mystatus_t myurl_host_ipv4_number_parser(const char* data, size_t data_size, unsigned int* number, bool* validationErrorFlag)
227             {
228 0           size_t length = 0;
229            
230             /* 1 */
231 0           unsigned int r = 10;
232            
233             /* 2 */
234 0 0         if(data_size > 1) {
235 0 0         if(*data == '0' && (data[1] == 'x' || data[1] == 'X')) {
    0          
    0          
236             /* 2.1 */
237 0           *validationErrorFlag = true;
238            
239             /* 2.2 */
240 0           length += 2;
241            
242             /* 2.3 */
243 0           r = 16;
244             }
245 0 0         else if(*data == '0') {
246             /* 3.1 */
247 0           *validationErrorFlag = true;
248            
249             /* 3.2 */
250 0           length++;
251            
252             /* 3.3 */
253 0           r = 8;
254             }
255             }
256            
257 0           *number = 0;
258            
259 0 0         if(r == 10) {
260 0 0         while(length < data_size) {
261 0 0         if(mycore_string_chars_num_map[ (unsigned char)data[length] ] == 0xff) {
262 0           return MyURL_STATUS_ERROR;
263             }
264            
265 0           *number = mycore_string_chars_num_map[ (unsigned char)data[length] ] + *number * r;
266            
267 0           length++;
268             }
269             }
270 0 0         else if(r == 16) {
271 0 0         while(length < data_size) {
272 0 0         if(mycore_string_chars_hex_map[ (unsigned char)data[length] ] == 0xff) {
273 0           return MyURL_STATUS_ERROR;
274             }
275            
276 0           *number = mycore_string_chars_hex_map[ (unsigned char)data[length] ] + *number * r;
277            
278 0           length++;
279             }
280             }
281             else {
282 0 0         while(length < data_size) {
283 0 0         if((unsigned char)data[length] < 0x30 || (unsigned char)data[length] > 0x37) {
    0          
284 0           return MyURL_STATUS_ERROR;
285             }
286            
287 0           *number = mycore_string_chars_num_map[ (unsigned char)data[length] ] + *number * r;
288            
289 0           length++;
290             }
291             }
292            
293 0           return MyURL_STATUS_OK;
294             }
295              
296 0           mystatus_t myurl_host_ipv4_parser(myurl_host_ipv_t* ipv, const char* data, size_t data_size, bool* failure)
297             {
298 0 0         if(failure)
299 0           *failure = false;
300            
301 0           size_t data_length = 0;
302 0           memset(ipv, 0, sizeof(myurl_host_ipv_t));
303            
304             /* 1 */
305 0           bool validationErrorFlag = false;
306            
307             /* 2 */
308 0           size_t part_begin = data_length;
309 0           size_t part_count = 0;
310            
311 0 0         while(data_length < data_size)
312             {
313 0 0         if(data[data_length] == '.')
314             {
315             /* 4 */
316 0 0         if(part_count == 3) {
317 0           return MyURL_STATUS_ERROR;
318             }
319            
320             /* 6.1 */
321 0 0         if((data_length - part_begin) == 0) {
322 0           return MyURL_STATUS_ERROR;
323             }
324            
325 0 0         if(myurl_host_ipv4_number_parser(&data[part_begin], (data_length - part_begin), &ipv->pieces[part_count], &validationErrorFlag)) {
326 0           return MyURL_STATUS_ERROR;
327             }
328            
329 0           part_begin = data_length + 1;
330 0           part_count++;
331             }
332            
333 0           data_length++;
334             }
335            
336 0 0         if(data_length - part_begin) {
337 0 0         if(myurl_host_ipv4_number_parser(&data[part_begin], (data_length - part_begin), &ipv->pieces[part_count], &validationErrorFlag)) {
338 0           return MyURL_STATUS_ERROR;
339             }
340            
341 0           part_count++;
342             }
343            
344 0 0         if(part_count == 0) {
345 0           return MyURL_STATUS_ERROR;
346             }
347            
348             /* 7 */
349             // if(validationErrorFlag) {
350             // // parse error
351             // }
352            
353             /* 8 */
354 0 0         for(size_t i = 0; i < part_count; i++) {
355 0 0         if(ipv->pieces[i] > 255) {
356             // parse error
357            
358             /* if not last */
359 0 0         if(i != (part_count - 1)) {
360 0 0         if(failure)
361 0           *failure = true;
362            
363 0           return MyURL_STATUS_ERROR;
364             }
365             }
366             }
367            
368             /* 9 */
369 0 0         if(ipv->pieces[(part_count - 1)] >= mycore_power(256, (5 - part_count))) {
370 0 0         if(failure)
371 0           *failure = true;
372            
373 0           return MyURL_STATUS_ERROR;
374             }
375            
376             /* 10 */
377 0           part_count--;
378 0           unsigned int ipv4 = ipv->pieces[part_count];
379            
380             /* calc end char count */
381 0 0         for(size_t i = 0; i < part_count; i++) {
382 0           size_t n = mycore_power(256, (3 - i));
383 0           ipv4 += ipv->pieces[i] * n;
384             }
385            
386 0           ipv->pieces[0] = ipv4;
387 0           ipv->type = MyURL_HOST_TYPE_IP_v4;
388            
389 0           return MyURL_STATUS_OK;
390             }
391              
392 0           mystatus_t myurl_host_ipv6_parser(myurl_host_ipv_t* ipv, const char* data, size_t data_size)
393             {
394 0           size_t data_length = 0;
395 0           const unsigned char *u_data = (const unsigned char*)data;
396            
397             /* 1 */
398 0           memset(ipv, 0, sizeof(myurl_host_ipv_t));
399             /* 2 */
400 0           unsigned int *piece = ipv->pieces;
401 0           unsigned int *piece_pointer = ipv->pieces;
402             /* 3 */
403 0           unsigned int *compress_pointer = NULL;
404            
405 0           ipv->type = MyURL_HOST_TYPE_IP_v6;
406            
407             /* 5 */
408 0 0         if(data[data_length] == ':') {
409 0           data_length++;
410            
411             /* 5.1 */
412 0 0         if(data_length >= data_size || data[data_length] != ':') {
    0          
413 0           return MyURL_STATUS_ERROR;
414             }
415            
416             /* 5.2 */
417 0           data_length++;
418            
419             /* 5.3 */
420 0           piece_pointer++;
421 0           piece = piece_pointer;
422            
423 0           compress_pointer = piece_pointer;
424             }
425            
426             /* 6 */
427 0 0         while(data_length < data_size)
428             {
429             /* 6.1 */
430 0 0         if(piece_pointer == &ipv->pieces[8]) {
431             // parse error
432 0           return MyURL_STATUS_ERROR;
433             }
434            
435             /* 6.2 */
436 0 0         if(data[data_length] == ':') {
437             /* 6.2.1 */
438 0 0         if(compress_pointer != NULL) {
439             // parse error
440 0           return MyURL_STATUS_ERROR;
441             }
442            
443             /* 6.2.2 */
444 0           data_length++;
445            
446 0           piece_pointer++;
447 0           piece = piece_pointer;
448            
449 0           compress_pointer = piece_pointer;
450 0           continue;
451             }
452            
453             /* 6.3 and 6.4 */
454 0           unsigned int num = 0;
455 0           size_t i = 0;
456            
457 0 0         while((i < 4) && (data_length < data_size)) {
    0          
458 0 0         if(mycore_string_chars_hex_map[ u_data[data_length] ] != 0xff) {
459 0           num <<= 4;
460 0           num |= mycore_string_chars_hex_map[ u_data[data_length] ];
461             }
462             else
463 0           break;
464            
465 0           data_length++;
466 0           i++;
467             }
468            
469             /* 6.5 */
470 0 0         if(data_length < data_size)
471             {
472 0 0         if(data[data_length] == '.') {
473             /* 6.5.1 */
474 0 0         if(i == 0) {
475             // parse error
476 0           return MyURL_STATUS_ERROR;
477             }
478            
479             /* 6.5.2 */
480 0           data_length -= i;
481            
482             /* 6.5.3 */
483 0 0         if(myurl_host_ipv6_ipv4_parser(ipv, &data[data_length], (data_size - data_length), &piece_pointer)) {
484 0           return MyURL_STATUS_ERROR;
485             }
486            
487 0           break;
488             }
489 0 0         else if(data[data_length] == ':') {
490             /* 6.5.1 */
491 0           data_length++;
492            
493             /* 6.5.2 */
494 0 0         if(data_length >= data_size) {
495             // parse error
496 0           return MyURL_STATUS_ERROR;
497             }
498             }
499             else {
500             // parse error
501 0           return MyURL_STATUS_ERROR;
502             }
503             }
504            
505             /* 6.6 */
506 0           *piece = num;
507             /* 6.7 */
508 0           piece_pointer++;
509 0           piece = piece_pointer;
510             }
511            
512             /* 11 */
513             /* 11.1 */
514 0 0         if(compress_pointer) {
515 0           unsigned int swaps = (unsigned int)(piece_pointer - compress_pointer);
516 0           size_t i = 7;
517            
518             /* 11.2 and 11.3 */
519 0 0         while(i && swaps > 0) {
    0          
520 0           unsigned int *tmp = compress_pointer + (swaps - 1);
521 0           unsigned int num = *tmp;
522            
523 0           *tmp = ipv->pieces[i];
524 0           ipv->pieces[i] = num;
525            
526 0           swaps--;
527 0           i--;
528             }
529            
530 0           return MyURL_STATUS_OK;
531             }
532            
533             /* 12 */
534 0 0         if(compress_pointer == NULL && piece_pointer != &ipv->pieces[8]) {
    0          
535             // parse error
536 0           return MyURL_STATUS_ERROR;
537             }
538            
539 0           return MyURL_STATUS_OK;
540             }
541              
542 0           mystatus_t myurl_host_ipv6_ipv4_parser(myurl_host_ipv_t* ipv, const char* data, size_t data_size, unsigned int** piece_pointer)
543             {
544 0           size_t data_length = 0;
545 0           const unsigned char *u_data = (const unsigned char*)data;
546            
547             /* 8 */
548 0 0         if((*piece_pointer - ipv->pieces) > 6) {
549             // parse error
550 0           return MyURL_STATUS_ERROR;
551             }
552            
553             /* 9 */
554 0           unsigned int numbersSeen = 0;
555            
556             /* 10 */
557 0 0         while(data_length < data_size)
558             {
559             /* 10.1 */
560 0           int value = -1;
561            
562             /* 10.2 */
563 0 0         if(numbersSeen > 0)
564             {
565 0 0         if(data[data_length] != '.' || numbersSeen >= 4) {
    0          
566             // parse error
567 0           return MyURL_STATUS_ERROR;
568             }
569            
570 0           data_length++;
571            
572 0 0         if(data_length >= data_size)
573 0           return MyURL_STATUS_ERROR;
574             }
575            
576             /* 10.3 */
577 0 0         if(mycore_string_chars_num_map[ u_data[data_length] ] == 0xff) {
578             // parse error
579 0           return MyURL_STATUS_ERROR;
580             }
581            
582             /* 10.4 */
583 0 0         while(data_length < data_size && mycore_string_chars_num_map[ u_data[data_length] ] != 0xff)
    0          
584             {
585             /* 10.4.1 */
586 0           unsigned int number = mycore_string_chars_num_map[ u_data[data_length] ];
587            
588             /* 10.4.2 */
589 0 0         if(value == -1) {
590 0           value = (int)number;
591             }
592 0 0         else if(value == 0) {
593             // parse error
594 0           return MyURL_STATUS_ERROR;
595             }
596             else {
597 0           value = value * 10 + number;
598             }
599            
600             /* 10.4.3 */
601 0 0         if(value > 255) {
602             // parse error
603 0           return MyURL_STATUS_ERROR;
604             }
605            
606             /* 10.4.2 */
607 0           data_length++;
608             }
609            
610             /* 10.5 */
611 0           **piece_pointer = **piece_pointer * 0x100 + value;
612            
613             /* 10.6 */
614 0           numbersSeen++;
615            
616             /* 10.7 */ // maybe: (numbersSeen % 2 == 0) ?
617 0 0         if(numbersSeen == 2 || numbersSeen == 4) {
    0          
618 0           (*piece_pointer)++;
619             }
620            
621             /* 10.8 */
622 0 0         if(data_length >= data_size && numbersSeen != 4) {
    0          
623             // parse error
624 0           return MyURL_STATUS_ERROR;
625             }
626             }
627            
628 0           return MyURL_STATUS_OK;
629             }
630              
631