Mercurial > embed
comparison uriparser/src/UriCommon.c @ 60:a2be1eba7adb
uriparser: import 0.8.5, close #878 @10m
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 13 Jul 2018 10:50:43 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
59:e5880f2798a1 | 60:a2be1eba7adb |
---|---|
1 /* | |
2 * uriparser - RFC 3986 URI parsing library | |
3 * | |
4 * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | |
5 * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org> | |
6 * All rights reserved. | |
7 * | |
8 * Redistribution and use in source and binary forms, with or without | |
9 * modification, are permitted provided that the following conditions | |
10 * are met: | |
11 * | |
12 * * Redistributions of source code must retain the above | |
13 * copyright notice, this list of conditions and the following | |
14 * disclaimer. | |
15 * | |
16 * * Redistributions in binary form must reproduce the above | |
17 * copyright notice, this list of conditions and the following | |
18 * disclaimer in the documentation and/or other materials | |
19 * provided with the distribution. | |
20 * | |
21 * * Neither the name of the <ORGANIZATION> nor the names of its | |
22 * contributors may be used to endorse or promote products | |
23 * derived from this software without specific prior written | |
24 * permission. | |
25 * | |
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
37 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
38 */ | |
39 | |
40 /* What encodings are enabled? */ | |
41 #include <uriparser/UriDefsConfig.h> | |
42 #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | |
43 /* Include SELF twice */ | |
44 # ifdef URI_ENABLE_ANSI | |
45 # define URI_PASS_ANSI 1 | |
46 # include "UriCommon.c" | |
47 # undef URI_PASS_ANSI | |
48 # endif | |
49 # ifdef URI_ENABLE_UNICODE | |
50 # define URI_PASS_UNICODE 1 | |
51 # include "UriCommon.c" | |
52 # undef URI_PASS_UNICODE | |
53 # endif | |
54 #else | |
55 # ifdef URI_PASS_ANSI | |
56 # include <uriparser/UriDefsAnsi.h> | |
57 # else | |
58 # include <uriparser/UriDefsUnicode.h> | |
59 # include <wchar.h> | |
60 # endif | |
61 | |
62 | |
63 | |
64 #ifndef URI_DOXYGEN | |
65 # include <uriparser/Uri.h> | |
66 # include "UriCommon.h" | |
67 #endif | |
68 | |
69 | |
70 | |
71 /*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X"); | |
72 /*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT("."); | |
73 /*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT(".."); | |
74 | |
75 | |
76 | |
77 void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) { | |
78 memset(uri, 0, sizeof(URI_TYPE(Uri))); | |
79 } | |
80 | |
81 | |
82 | |
83 /* Compares two text ranges for equal text content */ | |
84 int URI_FUNC(CompareRange)( | |
85 const URI_TYPE(TextRange) * a, | |
86 const URI_TYPE(TextRange) * b) { | |
87 int diff; | |
88 | |
89 /* NOTE: Both NULL means equal! */ | |
90 if ((a == NULL) || (b == NULL)) { | |
91 return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1); | |
92 } | |
93 | |
94 /* NOTE: Both NULL means equal! */ | |
95 if ((a->first == NULL) || (b->first == NULL)) { | |
96 return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1); | |
97 } | |
98 | |
99 diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first)); | |
100 if (diff > 0) { | |
101 return 1; | |
102 } else if (diff < 0) { | |
103 return -1; | |
104 } | |
105 | |
106 diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first)); | |
107 | |
108 if (diff > 0) { | |
109 return 1; | |
110 } else if (diff < 0) { | |
111 return -1; | |
112 } | |
113 | |
114 return diff; | |
115 } | |
116 | |
117 | |
118 | |
119 /* Properly removes "." and ".." path segments */ | |
120 UriBool URI_FUNC(RemoveDotSegments)(URI_TYPE(Uri) * uri, | |
121 UriBool relative) { | |
122 if (uri == NULL) { | |
123 return URI_TRUE; | |
124 } | |
125 return URI_FUNC(RemoveDotSegmentsEx)(uri, relative, uri->owner); | |
126 } | |
127 | |
128 | |
129 | |
130 UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, | |
131 UriBool relative, UriBool pathOwned) { | |
132 URI_TYPE(PathSegment) * walker; | |
133 if ((uri == NULL) || (uri->pathHead == NULL)) { | |
134 return URI_TRUE; | |
135 } | |
136 | |
137 walker = uri->pathHead; | |
138 walker->reserved = NULL; /* Prev pointer */ | |
139 do { | |
140 UriBool removeSegment = URI_FALSE; | |
141 int len = (int)(walker->text.afterLast - walker->text.first); | |
142 switch (len) { | |
143 case 1: | |
144 if ((walker->text.first)[0] == _UT('.')) { | |
145 /* "." segment -> remove if not essential */ | |
146 URI_TYPE(PathSegment) * const prev = walker->reserved; | |
147 URI_TYPE(PathSegment) * const nextBackup = walker->next; | |
148 | |
149 /* Is this dot segment essential? */ | |
150 removeSegment = URI_TRUE; | |
151 if (relative && (walker == uri->pathHead) && (walker->next != NULL)) { | |
152 const URI_CHAR * ch = walker->next->text.first; | |
153 for (; ch < walker->next->text.afterLast; ch++) { | |
154 if (*ch == _UT(':')) { | |
155 removeSegment = URI_FALSE; | |
156 break; | |
157 } | |
158 } | |
159 } | |
160 | |
161 if (removeSegment) { | |
162 /* Last segment? */ | |
163 if (walker->next != NULL) { | |
164 /* Not last segment */ | |
165 walker->next->reserved = prev; | |
166 | |
167 if (prev == NULL) { | |
168 /* First but not last segment */ | |
169 uri->pathHead = walker->next; | |
170 } else { | |
171 /* Middle segment */ | |
172 prev->next = walker->next; | |
173 } | |
174 | |
175 if (pathOwned && (walker->text.first != walker->text.afterLast)) { | |
176 free((URI_CHAR *)walker->text.first); | |
177 } | |
178 free(walker); | |
179 } else { | |
180 /* Last segment */ | |
181 if (pathOwned && (walker->text.first != walker->text.afterLast)) { | |
182 free((URI_CHAR *)walker->text.first); | |
183 } | |
184 | |
185 if (prev == NULL) { | |
186 /* Last and first */ | |
187 if (URI_FUNC(IsHostSet)(uri)) { | |
188 /* Replace "." with empty segment to represent trailing slash */ | |
189 walker->text.first = URI_FUNC(SafeToPointTo); | |
190 walker->text.afterLast = URI_FUNC(SafeToPointTo); | |
191 } else { | |
192 free(walker); | |
193 | |
194 uri->pathHead = NULL; | |
195 uri->pathTail = NULL; | |
196 } | |
197 } else { | |
198 /* Last but not first, replace "." with empty segment to represent trailing slash */ | |
199 walker->text.first = URI_FUNC(SafeToPointTo); | |
200 walker->text.afterLast = URI_FUNC(SafeToPointTo); | |
201 } | |
202 } | |
203 | |
204 walker = nextBackup; | |
205 } | |
206 } | |
207 break; | |
208 | |
209 case 2: | |
210 if (((walker->text.first)[0] == _UT('.')) | |
211 && ((walker->text.first)[1] == _UT('.'))) { | |
212 /* Path ".." -> remove this and the previous segment */ | |
213 URI_TYPE(PathSegment) * const prev = walker->reserved; | |
214 URI_TYPE(PathSegment) * prevPrev; | |
215 URI_TYPE(PathSegment) * const nextBackup = walker->next; | |
216 | |
217 removeSegment = URI_TRUE; | |
218 if (relative) { | |
219 if (prev == NULL) { | |
220 removeSegment = URI_FALSE; | |
221 } else if ((prev != NULL) | |
222 && ((prev->text.afterLast - prev->text.first) == 2) | |
223 && ((prev->text.first)[0] == _UT('.')) | |
224 && ((prev->text.first)[1] == _UT('.'))) { | |
225 removeSegment = URI_FALSE; | |
226 } | |
227 } | |
228 | |
229 if (removeSegment) { | |
230 if (prev != NULL) { | |
231 /* Not first segment */ | |
232 prevPrev = prev->reserved; | |
233 if (prevPrev != NULL) { | |
234 /* Not even prev is the first one */ | |
235 prevPrev->next = walker->next; | |
236 if (walker->next != NULL) { | |
237 walker->next->reserved = prevPrev; | |
238 } else { | |
239 /* Last segment -> insert "" segment to represent trailing slash, update tail */ | |
240 URI_TYPE(PathSegment) * const segment = malloc(1 * sizeof(URI_TYPE(PathSegment))); | |
241 if (segment == NULL) { | |
242 if (pathOwned && (walker->text.first != walker->text.afterLast)) { | |
243 free((URI_CHAR *)walker->text.first); | |
244 } | |
245 free(walker); | |
246 | |
247 if (pathOwned && (prev->text.first != prev->text.afterLast)) { | |
248 free((URI_CHAR *)prev->text.first); | |
249 } | |
250 free(prev); | |
251 | |
252 return URI_FALSE; /* Raises malloc error */ | |
253 } | |
254 memset(segment, 0, sizeof(URI_TYPE(PathSegment))); | |
255 segment->text.first = URI_FUNC(SafeToPointTo); | |
256 segment->text.afterLast = URI_FUNC(SafeToPointTo); | |
257 prevPrev->next = segment; | |
258 uri->pathTail = segment; | |
259 } | |
260 | |
261 if (pathOwned && (walker->text.first != walker->text.afterLast)) { | |
262 free((URI_CHAR *)walker->text.first); | |
263 } | |
264 free(walker); | |
265 | |
266 if (pathOwned && (prev->text.first != prev->text.afterLast)) { | |
267 free((URI_CHAR *)prev->text.first); | |
268 } | |
269 free(prev); | |
270 | |
271 walker = nextBackup; | |
272 } else { | |
273 /* Prev is the first segment */ | |
274 if (walker->next != NULL) { | |
275 uri->pathHead = walker->next; | |
276 walker->next->reserved = NULL; | |
277 | |
278 if (pathOwned && (walker->text.first != walker->text.afterLast)) { | |
279 free((URI_CHAR *)walker->text.first); | |
280 } | |
281 free(walker); | |
282 } else { | |
283 /* Re-use segment for "" path segment to represent trailing slash, update tail */ | |
284 URI_TYPE(PathSegment) * const segment = walker; | |
285 if (pathOwned && (segment->text.first != segment->text.afterLast)) { | |
286 free((URI_CHAR *)segment->text.first); | |
287 } | |
288 segment->text.first = URI_FUNC(SafeToPointTo); | |
289 segment->text.afterLast = URI_FUNC(SafeToPointTo); | |
290 uri->pathHead = segment; | |
291 uri->pathTail = segment; | |
292 } | |
293 | |
294 if (pathOwned && (prev->text.first != prev->text.afterLast)) { | |
295 free((URI_CHAR *)prev->text.first); | |
296 } | |
297 free(prev); | |
298 | |
299 walker = nextBackup; | |
300 } | |
301 } else { | |
302 URI_TYPE(PathSegment) * const anotherNextBackup = walker->next; | |
303 /* First segment -> update head pointer */ | |
304 uri->pathHead = walker->next; | |
305 if (walker->next != NULL) { | |
306 walker->next->reserved = NULL; | |
307 } else { | |
308 /* Last segment -> update tail */ | |
309 uri->pathTail = NULL; | |
310 } | |
311 | |
312 if (pathOwned && (walker->text.first != walker->text.afterLast)) { | |
313 free((URI_CHAR *)walker->text.first); | |
314 } | |
315 free(walker); | |
316 | |
317 walker = anotherNextBackup; | |
318 } | |
319 } | |
320 } | |
321 break; | |
322 | |
323 } | |
324 | |
325 if (!removeSegment) { | |
326 if (walker->next != NULL) { | |
327 walker->next->reserved = walker; | |
328 } else { | |
329 /* Last segment -> update tail */ | |
330 uri->pathTail = walker; | |
331 } | |
332 walker = walker->next; | |
333 } | |
334 } while (walker != NULL); | |
335 | |
336 return URI_TRUE; | |
337 } | |
338 | |
339 | |
340 | |
341 /* Properly removes "." and ".." path segments */ | |
342 UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri) { | |
343 const UriBool ABSOLUTE = URI_FALSE; | |
344 return URI_FUNC(RemoveDotSegments)(uri, ABSOLUTE); | |
345 } | |
346 | |
347 | |
348 | |
349 unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) { | |
350 switch (hexdig) { | |
351 case _UT('0'): | |
352 case _UT('1'): | |
353 case _UT('2'): | |
354 case _UT('3'): | |
355 case _UT('4'): | |
356 case _UT('5'): | |
357 case _UT('6'): | |
358 case _UT('7'): | |
359 case _UT('8'): | |
360 case _UT('9'): | |
361 return (unsigned char)(9 + hexdig - _UT('9')); | |
362 | |
363 case _UT('a'): | |
364 case _UT('b'): | |
365 case _UT('c'): | |
366 case _UT('d'): | |
367 case _UT('e'): | |
368 case _UT('f'): | |
369 return (unsigned char)(15 + hexdig - _UT('f')); | |
370 | |
371 case _UT('A'): | |
372 case _UT('B'): | |
373 case _UT('C'): | |
374 case _UT('D'): | |
375 case _UT('E'): | |
376 case _UT('F'): | |
377 return (unsigned char)(15 + hexdig - _UT('F')); | |
378 | |
379 default: | |
380 return 0; | |
381 } | |
382 } | |
383 | |
384 | |
385 | |
386 URI_CHAR URI_FUNC(HexToLetter)(unsigned int value) { | |
387 /* Uppercase recommended in section 2.1. of RFC 3986 * | |
388 * http://tools.ietf.org/html/rfc3986#section-2.1 */ | |
389 return URI_FUNC(HexToLetterEx)(value, URI_TRUE); | |
390 } | |
391 | |
392 | |
393 | |
394 URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) { | |
395 switch (value) { | |
396 case 0: return _UT('0'); | |
397 case 1: return _UT('1'); | |
398 case 2: return _UT('2'); | |
399 case 3: return _UT('3'); | |
400 case 4: return _UT('4'); | |
401 case 5: return _UT('5'); | |
402 case 6: return _UT('6'); | |
403 case 7: return _UT('7'); | |
404 case 8: return _UT('8'); | |
405 case 9: return _UT('9'); | |
406 | |
407 case 10: return (uppercase == URI_TRUE) ? _UT('A') : _UT('a'); | |
408 case 11: return (uppercase == URI_TRUE) ? _UT('B') : _UT('b'); | |
409 case 12: return (uppercase == URI_TRUE) ? _UT('C') : _UT('c'); | |
410 case 13: return (uppercase == URI_TRUE) ? _UT('D') : _UT('d'); | |
411 case 14: return (uppercase == URI_TRUE) ? _UT('E') : _UT('e'); | |
412 default: return (uppercase == URI_TRUE) ? _UT('F') : _UT('f'); | |
413 } | |
414 } | |
415 | |
416 | |
417 | |
418 /* Checks if a URI has the host component set. */ | |
419 UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri) { | |
420 return (uri != NULL) | |
421 && ((uri->hostText.first != NULL) | |
422 || (uri->hostData.ip4 != NULL) | |
423 || (uri->hostData.ip6 != NULL) | |
424 || (uri->hostData.ipFuture.first != NULL) | |
425 ); | |
426 } | |
427 | |
428 | |
429 | |
430 /* Copies the path segment list from one URI to another. */ | |
431 UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, | |
432 const URI_TYPE(Uri) * source) { | |
433 if (source->pathHead == NULL) { | |
434 /* No path component */ | |
435 dest->pathHead = NULL; | |
436 dest->pathTail = NULL; | |
437 } else { | |
438 /* Copy list but not the text contained */ | |
439 URI_TYPE(PathSegment) * sourceWalker = source->pathHead; | |
440 URI_TYPE(PathSegment) * destPrev = NULL; | |
441 do { | |
442 URI_TYPE(PathSegment) * cur = malloc(sizeof(URI_TYPE(PathSegment))); | |
443 if (cur == NULL) { | |
444 /* Fix broken list */ | |
445 if (destPrev != NULL) { | |
446 destPrev->next = NULL; | |
447 } | |
448 return URI_FALSE; /* Raises malloc error */ | |
449 } | |
450 | |
451 /* From this functions usage we know that * | |
452 * the dest URI cannot be uri->owner */ | |
453 cur->text = sourceWalker->text; | |
454 if (destPrev == NULL) { | |
455 /* First segment ever */ | |
456 dest->pathHead = cur; | |
457 } else { | |
458 destPrev->next = cur; | |
459 } | |
460 destPrev = cur; | |
461 sourceWalker = sourceWalker->next; | |
462 } while (sourceWalker != NULL); | |
463 dest->pathTail = destPrev; | |
464 dest->pathTail->next = NULL; | |
465 } | |
466 | |
467 dest->absolutePath = source->absolutePath; | |
468 return URI_TRUE; | |
469 } | |
470 | |
471 | |
472 | |
473 /* Copies the authority part of an URI over to another. */ | |
474 UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, | |
475 const URI_TYPE(Uri) * source) { | |
476 /* From this functions usage we know that * | |
477 * the dest URI cannot be uri->owner */ | |
478 | |
479 /* Copy userInfo */ | |
480 dest->userInfo = source->userInfo; | |
481 | |
482 /* Copy hostText */ | |
483 dest->hostText = source->hostText; | |
484 | |
485 /* Copy hostData */ | |
486 if (source->hostData.ip4 != NULL) { | |
487 dest->hostData.ip4 = malloc(sizeof(UriIp4)); | |
488 if (dest->hostData.ip4 == NULL) { | |
489 return URI_FALSE; /* Raises malloc error */ | |
490 } | |
491 *(dest->hostData.ip4) = *(source->hostData.ip4); | |
492 dest->hostData.ip6 = NULL; | |
493 dest->hostData.ipFuture.first = NULL; | |
494 dest->hostData.ipFuture.afterLast = NULL; | |
495 } else if (source->hostData.ip6 != NULL) { | |
496 dest->hostData.ip4 = NULL; | |
497 dest->hostData.ip6 = malloc(sizeof(UriIp6)); | |
498 if (dest->hostData.ip6 == NULL) { | |
499 return URI_FALSE; /* Raises malloc error */ | |
500 } | |
501 *(dest->hostData.ip6) = *(source->hostData.ip6); | |
502 dest->hostData.ipFuture.first = NULL; | |
503 dest->hostData.ipFuture.afterLast = NULL; | |
504 } else { | |
505 dest->hostData.ip4 = NULL; | |
506 dest->hostData.ip6 = NULL; | |
507 dest->hostData.ipFuture = source->hostData.ipFuture; | |
508 } | |
509 | |
510 /* Copy portText */ | |
511 dest->portText = source->portText; | |
512 | |
513 return URI_TRUE; | |
514 } | |
515 | |
516 | |
517 | |
518 UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri) { | |
519 URI_TYPE(PathSegment) * segment; | |
520 | |
521 if ( /* Case 1: absolute path, empty first segment */ | |
522 (uri->absolutePath | |
523 && (uri->pathHead != NULL) | |
524 && (uri->pathHead->text.afterLast == uri->pathHead->text.first)) | |
525 | |
526 /* Case 2: relative path, empty first and second segment */ | |
527 || (!uri->absolutePath | |
528 && (uri->pathHead != NULL) | |
529 && (uri->pathHead->next != NULL) | |
530 && (uri->pathHead->text.afterLast == uri->pathHead->text.first) | |
531 && (uri->pathHead->next->text.afterLast == uri->pathHead->next->text.first))) { | |
532 /* NOOP */ | |
533 } else { | |
534 return URI_TRUE; | |
535 } | |
536 | |
537 segment = malloc(1 * sizeof(URI_TYPE(PathSegment))); | |
538 if (segment == NULL) { | |
539 return URI_FALSE; /* Raises malloc error */ | |
540 } | |
541 | |
542 /* Insert "." segment in front */ | |
543 segment->next = uri->pathHead; | |
544 segment->text.first = URI_FUNC(ConstPwd); | |
545 segment->text.afterLast = URI_FUNC(ConstPwd) + 1; | |
546 uri->pathHead = segment; | |
547 return URI_TRUE; | |
548 } | |
549 | |
550 | |
551 | |
552 void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri) { | |
553 /* Fix path if only one empty segment */ | |
554 if (!uri->absolutePath | |
555 && !URI_FUNC(IsHostSet)(uri) | |
556 && (uri->pathHead != NULL) | |
557 && (uri->pathHead->next == NULL) | |
558 && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) { | |
559 free(uri->pathHead); | |
560 uri->pathHead = NULL; | |
561 uri->pathTail = NULL; | |
562 } | |
563 } | |
564 | |
565 | |
566 | |
567 #endif |