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 "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 "UriResolve.c"
47 #  undef URI_PASS_ANSI
48 # endif
49 # ifdef URI_ENABLE_UNICODE
50 #  define URI_PASS_UNICODE 1
51 #  include "UriResolve.c"
52 #  undef URI_PASS_UNICODE
53 # endif
54 #else
55 # ifdef URI_PASS_ANSI
56 #  include "UriDefsAnsi.h"
57 # else
58 #  include "UriDefsUnicode.h"
59 #  include <wchar.h>
60 # endif
61 
62 
63 
64 #ifndef URI_DOXYGEN
65 # include "Uri.h"
66 # include "UriCommon.h"
67 # include "UriMemory.h"
68 #endif
69 
70 
71 
72 /* Appends a relative URI to an absolute. The last path segment of
73  * the absolute URI is replaced. */
URI_FUNC(MergePath)74 static URI_INLINE UriBool URI_FUNC(MergePath)(URI_TYPE(Uri) * absWork,
75 		const URI_TYPE(Uri) * relAppend, UriMemoryManager * memory) {
76 	URI_TYPE(PathSegment) * sourceWalker;
77 	URI_TYPE(PathSegment) * destPrev;
78 	if (relAppend->pathHead == NULL) {
79 		return URI_TRUE;
80 	}
81 
82 	/* Replace last segment ("" if trailing slash) with first of append chain */
83 	if (absWork->pathHead == NULL) {
84 		URI_TYPE(PathSegment) * const dup = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
85 		if (dup == NULL) {
86 			return URI_FALSE; /* Raises malloc error */
87 		}
88 		dup->next = NULL;
89 		absWork->pathHead = dup;
90 		absWork->pathTail = dup;
91 	}
92 	absWork->pathTail->text.first = relAppend->pathHead->text.first;
93 	absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast;
94 
95 	/* Append all the others */
96 	sourceWalker = relAppend->pathHead->next;
97 	if (sourceWalker == NULL) {
98 		return URI_TRUE;
99 	}
100 	destPrev = absWork->pathTail;
101 
102 	for (;;) {
103 		URI_TYPE(PathSegment) * const dup = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
104 		if (dup == NULL) {
105 			destPrev->next = NULL;
106 			absWork->pathTail = destPrev;
107 			return URI_FALSE; /* Raises malloc error */
108 		}
109 		dup->text = sourceWalker->text;
110 		destPrev->next = dup;
111 
112 		if (sourceWalker->next == NULL) {
113 			absWork->pathTail = dup;
114 			absWork->pathTail->next = NULL;
115 			break;
116 		}
117 		destPrev = dup;
118 		sourceWalker = sourceWalker->next;
119 	}
120 
121 	return URI_TRUE;
122 }
123 
124 
URI_FUNC(ResolveAbsolutePathFlag)125 static int URI_FUNC(ResolveAbsolutePathFlag)(URI_TYPE(Uri) * absWork,
126 		UriMemoryManager * memory) {
127 	if (absWork == NULL) {
128 		return URI_ERROR_NULL;
129 	}
130 
131 	if (URI_FUNC(IsHostSet)(absWork) && absWork->absolutePath) {
132 		/* Empty segment needed, instead? */
133 		if (absWork->pathHead == NULL) {
134 			URI_TYPE(PathSegment) * const segment = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
135 			if (segment == NULL) {
136 				return URI_ERROR_MALLOC;
137 			}
138 			segment->text.first = URI_FUNC(SafeToPointTo);
139 			segment->text.afterLast = URI_FUNC(SafeToPointTo);
140 			segment->next = NULL;
141 
142 			absWork->pathHead = segment;
143 			absWork->pathTail = segment;
144 		}
145 
146 		absWork->absolutePath = URI_FALSE;
147 	}
148 
149 	return URI_SUCCESS;
150 }
151 
152 
URI_FUNC(AddBaseUriImpl)153 static int URI_FUNC(AddBaseUriImpl)(URI_TYPE(Uri) * absDest,
154 		const URI_TYPE(Uri) * relSource,
155 		const URI_TYPE(Uri) * absBase,
156 		UriResolutionOptions options, UriMemoryManager * memory) {
157 	UriBool relSourceHasScheme;
158 
159 	if (absDest == NULL) {
160 		return URI_ERROR_NULL;
161 	}
162 	URI_FUNC(ResetUri)(absDest);
163 
164 	if ((relSource == NULL) || (absBase == NULL)) {
165 		return URI_ERROR_NULL;
166 	}
167 
168 	/* absBase absolute? */
169 	if (absBase->scheme.first == NULL) {
170 		return URI_ERROR_ADDBASE_REL_BASE;
171 	}
172 
173 	/* [00/32] 	-- A non-strict parser may ignore a scheme in the reference */
174 	/* [00/32] 	-- if it is identical to the base URI's scheme. */
175 	/* [00/32] 	if ((not strict) and (R.scheme == Base.scheme)) then */
176 	relSourceHasScheme = (relSource->scheme.first != NULL) ? URI_TRUE : URI_FALSE;
177 	if ((options & URI_RESOLVE_IDENTICAL_SCHEME_COMPAT)
178 			&& (absBase->scheme.first != NULL)
179 			&& (relSource->scheme.first != NULL)
180 			&& (0 == URI_FUNC(CompareRange)(&(absBase->scheme), &(relSource->scheme)))) {
181 	/* [00/32] 		undefine(R.scheme); */
182 		relSourceHasScheme = URI_FALSE;
183 	/* [00/32] 	endif; */
184 	}
185 
186 	/* [01/32]	if defined(R.scheme) then */
187 				if (relSourceHasScheme) {
188 	/* [02/32]		T.scheme = R.scheme; */
189 					absDest->scheme = relSource->scheme;
190 	/* [03/32]		T.authority = R.authority; */
191 					if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) {
192 						return URI_ERROR_MALLOC;
193 					}
194 	/* [04/32]		T.path = remove_dot_segments(R.path); */
195 					if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
196 						return URI_ERROR_MALLOC;
197 					}
198 					if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
199 						return URI_ERROR_MALLOC;
200 					}
201 	/* [05/32]		T.query = R.query; */
202 					absDest->query = relSource->query;
203 	/* [06/32]	else */
204 				} else {
205 	/* [07/32]		if defined(R.authority) then */
206 					if (URI_FUNC(IsHostSet)(relSource)) {
207 	/* [08/32]			T.authority = R.authority; */
208 						if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) {
209 							return URI_ERROR_MALLOC;
210 						}
211 	/* [09/32]			T.path = remove_dot_segments(R.path); */
212 						if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
213 							return URI_ERROR_MALLOC;
214 						}
215 						if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
216 							return URI_ERROR_MALLOC;
217 						}
218 	/* [10/32]			T.query = R.query; */
219 						absDest->query = relSource->query;
220 	/* [11/32]		else */
221 					} else {
222 	/* [28/32]			T.authority = Base.authority; */
223 						if (!URI_FUNC(CopyAuthority)(absDest, absBase, memory)) {
224 							return URI_ERROR_MALLOC;
225 						}
226 	/* [12/32]			if (R.path == "") then */
227 						if (relSource->pathHead == NULL && !relSource->absolutePath) {
228 	/* [13/32]				T.path = Base.path; */
229 							if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) {
230 								return URI_ERROR_MALLOC;
231 							}
232 	/* [14/32]				if defined(R.query) then */
233 							if (relSource->query.first != NULL) {
234 	/* [15/32]					T.query = R.query; */
235 								absDest->query = relSource->query;
236 	/* [16/32]				else */
237 							} else {
238 	/* [17/32]					T.query = Base.query; */
239 								absDest->query = absBase->query;
240 	/* [18/32]				endif; */
241 							}
242 	/* [19/32]			else */
243 						} else {
244 	/* [20/32]				if (R.path starts-with "/") then */
245 							if (relSource->absolutePath) {
246 								int res;
247 	/* [21/32]					T.path = remove_dot_segments(R.path); */
248 								if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
249 									return URI_ERROR_MALLOC;
250 								}
251 								res = URI_FUNC(ResolveAbsolutePathFlag)(absDest, memory);
252 								if (res != URI_SUCCESS) {
253 									return res;
254 								}
255 								if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
256 									return URI_ERROR_MALLOC;
257 								}
258 	/* [22/32]				else */
259 							} else {
260 	/* [23/32]					T.path = merge(Base.path, R.path); */
261 								if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) {
262 									return URI_ERROR_MALLOC;
263 								}
264 								if (!URI_FUNC(MergePath)(absDest, relSource, memory)) {
265 									return URI_ERROR_MALLOC;
266 								}
267 	/* [24/32]					T.path = remove_dot_segments(T.path); */
268 								if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
269 									return URI_ERROR_MALLOC;
270 								}
271 
272 								if (!URI_FUNC(FixAmbiguity)(absDest, memory)) {
273 									return URI_ERROR_MALLOC;
274 								}
275 	/* [25/32]				endif; */
276 							}
277 	/* [26/32]				T.query = R.query; */
278 							absDest->query = relSource->query;
279 	/* [27/32]			endif; */
280 						}
281 						URI_FUNC(FixEmptyTrailSegment)(absDest, memory);
282 	/* [29/32]		endif; */
283 					}
284 	/* [30/32]		T.scheme = Base.scheme; */
285 					absDest->scheme = absBase->scheme;
286 	/* [31/32]	endif; */
287 				}
288 	/* [32/32]	T.fragment = R.fragment; */
289 				absDest->fragment = relSource->fragment;
290 
291 	return URI_SUCCESS;
292 
293 }
294 
295 
296 
URI_FUNC(AddBaseUri)297 int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest,
298 		const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase) {
299 	const UriResolutionOptions options = URI_RESOLVE_STRICTLY;
300 	return URI_FUNC(AddBaseUriEx)(absDest, relSource, absBase, options);
301 }
302 
303 
304 
URI_FUNC(AddBaseUriEx)305 int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absDest,
306 		const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase,
307 		UriResolutionOptions options) {
308 	return URI_FUNC(AddBaseUriExMm)(absDest, relSource, absBase, options, NULL);
309 }
310 
311 
312 
URI_FUNC(AddBaseUriExMm)313 int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absDest,
314 		const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase,
315 		UriResolutionOptions options, UriMemoryManager * memory) {
316 	int res;
317 
318 	URI_CHECK_MEMORY_MANAGER(memory);  /* may return */
319 
320 	res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, options, memory);
321 	if ((res != URI_SUCCESS) && (absDest != NULL)) {
322 		URI_FUNC(FreeUriMembersMm)(absDest, memory);
323 	}
324 	return res;
325 }
326 
327 
328 
329 #endif
330