diff options
Diffstat (limited to 'src/UriCommon.c')
-rw-r--r-- | src/UriCommon.c | 96 |
1 files changed, 70 insertions, 26 deletions
diff --git a/src/UriCommon.c b/src/UriCommon.c index 60bd319..7ba92f2 100644 --- a/src/UriCommon.c +++ b/src/UriCommon.c @@ -119,17 +119,6 @@ int URI_FUNC(CompareRange)( -/* Properly removes "." and ".." path segments */ -UriBool URI_FUNC(RemoveDotSegments)(URI_TYPE(Uri) * uri, - UriBool relative, UriMemoryManager * memory) { - if (uri == NULL) { - return URI_TRUE; - } - return URI_FUNC(RemoveDotSegmentsEx)(uri, relative, uri->owner, memory); -} - - - UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative, UriBool pathOwned, UriMemoryManager * memory) { URI_TYPE(PathSegment) * walker; @@ -149,7 +138,13 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, URI_TYPE(PathSegment) * const prev = walker->reserved; URI_TYPE(PathSegment) * const nextBackup = walker->next; - /* Is this dot segment essential? */ + /* + * Is this dot segment essential, + * i.e. is there a chance of changing semantics by dropping this dot segment? + * + * For example, changing "./http://foo" into "http://foo" would change semantics + * and hence the dot segment is essential to that case and cannot be removed. + */ removeSegment = URI_TRUE; if (relative && (walker == uri->pathHead) && (walker->next != NULL)) { const URI_CHAR * ch = walker->next->text.first; @@ -162,16 +157,23 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, } if (removeSegment) { + /* .. then let's go remove that segment. */ /* Last segment? */ if (walker->next != NULL) { - /* Not last segment */ + /* Not last segment, i.e. first or middle segment + * OLD: (prev|NULL) <- walker <- next + * NEW: (prev|NULL) <----------- next */ walker->next->reserved = prev; if (prev == NULL) { - /* First but not last segment */ + /* First but not last segment + * OLD: head -> walker -> next + * NEW: head -----------> next */ uri->pathHead = walker->next; } else { - /* Middle segment */ + /* Middle segment + * OLD: prev -> walker -> next + * NEW: prev -----------> next */ prev->next = walker->next; } @@ -220,11 +222,16 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, removeSegment = URI_TRUE; if (relative) { if (prev == NULL) { + /* We cannot remove traversal beyond because the + * URI is relative and may be resolved later. + * So we can simplify "a/../b/d" to "b/d" but + * we cannot simplify "../b/d" (outside of reference resolution). */ removeSegment = URI_FALSE; } else if ((prev != NULL) && ((prev->text.afterLast - prev->text.first) == 2) && ((prev->text.first)[0] == _UT('.')) && ((prev->text.first)[1] == _UT('.'))) { + /* We need to protect against mis-simplifying "a/../../b" to "a/b". */ removeSegment = URI_FALSE; } } @@ -234,9 +241,14 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, /* Not first segment */ prevPrev = prev->reserved; if (prevPrev != NULL) { - /* Not even prev is the first one */ + /* Not even prev is the first one + * OLD: prevPrev -> prev -> walker -> (next|NULL) + * NEW: prevPrev -------------------> (next|NULL) */ prevPrev->next = walker->next; if (walker->next != NULL) { + /* Update parent relationship as well + * OLD: prevPrev <- prev <- walker <- next + * NEW: prevPrev <------------------- next */ walker->next->reserved = prevPrev; } else { /* Last segment -> insert "" segment to represent trailing slash, update tail */ @@ -302,29 +314,58 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, } } else { URI_TYPE(PathSegment) * const anotherNextBackup = walker->next; - /* First segment -> update head pointer */ - uri->pathHead = walker->next; + int freeWalker = URI_TRUE; + + /* First segment */ if (walker->next != NULL) { + /* First segment of multiple -> update head + * OLD: head -> walker -> next + * NEW: head -----------> next */ + uri->pathHead = walker->next; + + /* Update parent link as well + * OLD: head <- walker <- next + * NEW: head <----------- next */ walker->next->reserved = NULL; } else { - /* Last segment -> update tail */ - uri->pathTail = NULL; + if (uri->absolutePath) { + /* First and only segment -> update head + * OLD: head -> walker -> NULL + * NEW: head -----------> NULL */ + uri->pathHead = NULL; + + /* Last segment -> update tail + * OLD: tail -> walker + * NEW: tail -> NULL */ + uri->pathTail = NULL; + } else { + /* Re-use segment for "" path segment to represent trailing slash, + * then update head and tail */ + if (pathOwned && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + walker->text.first = URI_FUNC(SafeToPointTo); + walker->text.afterLast = URI_FUNC(SafeToPointTo); + freeWalker = URI_FALSE; + } } - if (pathOwned && (walker->text.first != walker->text.afterLast)) { - memory->free(memory, (URI_CHAR *)walker->text.first); + if (freeWalker) { + if (pathOwned && (walker->text.first != walker->text.afterLast)) { + memory->free(memory, (URI_CHAR *)walker->text.first); + } + memory->free(memory, walker); } - memory->free(memory, walker); walker = anotherNextBackup; } } } break; - - } + } /* end of switch */ if (!removeSegment) { + /* .. then let's move to the next element, and start again. */ if (walker->next != NULL) { walker->next->reserved = walker; } else { @@ -344,7 +385,10 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) { const UriBool ABSOLUTE = URI_FALSE; - return URI_FUNC(RemoveDotSegments)(uri, ABSOLUTE, memory); + if (uri == NULL) { + return URI_TRUE; + } + return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory); } |