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