summaryrefslogtreecommitdiffstats
path: root/plugins/uriparser/UriCommon.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/uriparser/UriCommon.c')
-rw-r--r--plugins/uriparser/UriCommon.c567
1 files changed, 567 insertions, 0 deletions
diff --git a/plugins/uriparser/UriCommon.c b/plugins/uriparser/UriCommon.c
new file mode 100644
index 0000000..37d6b39
--- /dev/null
+++ b/plugins/uriparser/UriCommon.c
@@ -0,0 +1,567 @@
1/*
2 * uriparser - RFC 3986 URI parsing library
3 *
4 * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
5 * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.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
77void 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 */
84int 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 */
120UriBool 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
130UriBool 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 */
342UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri) {
343 const UriBool ABSOLUTE = URI_FALSE;
344 return URI_FUNC(RemoveDotSegments)(uri, ABSOLUTE);
345}
346
347
348
349unsigned 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
386URI_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
394URI_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. */
419UriBool 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. */
431UriBool 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. */
474UriBool 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
518UriBool 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
552void 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