1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Darin Fisher <darin@netscape.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef nsStandardURL_h__
40 : #define nsStandardURL_h__
41 :
42 : #include "nsString.h"
43 : #include "nsDependentString.h"
44 : #include "nsDependentSubstring.h"
45 : #include "nsISerializable.h"
46 : #include "nsIIPCSerializable.h"
47 : #include "nsIFileURL.h"
48 : #include "nsIStandardURL.h"
49 : #include "nsIFile.h"
50 : #include "nsIURLParser.h"
51 : #include "nsIUnicodeEncoder.h"
52 : #include "nsIObserver.h"
53 : #include "nsIIOService.h"
54 : #include "nsCOMPtr.h"
55 : #include "nsURLHelper.h"
56 : #include "nsIClassInfo.h"
57 : #include "nsISizeOf.h"
58 : #include "prclist.h"
59 :
60 : #ifdef NS_BUILD_REFCNT_LOGGING
61 : #define DEBUG_DUMP_URLS_AT_SHUTDOWN
62 : #endif
63 :
64 : class nsIBinaryInputStream;
65 : class nsIBinaryOutputStream;
66 : class nsIIDNService;
67 : class nsICharsetConverterManager;
68 : class nsIPrefBranch;
69 :
70 : //-----------------------------------------------------------------------------
71 : // standard URL implementation
72 : //-----------------------------------------------------------------------------
73 :
74 : class nsStandardURL : public nsIFileURL
75 : , public nsIStandardURL
76 : , public nsISerializable
77 : , public nsIIPCSerializable
78 : , public nsIClassInfo
79 : , public nsISizeOf
80 : {
81 : public:
82 : NS_DECL_ISUPPORTS
83 : NS_DECL_NSIURI
84 : NS_DECL_NSIURL
85 : NS_DECL_NSIFILEURL
86 : NS_DECL_NSISTANDARDURL
87 : NS_DECL_NSISERIALIZABLE
88 : NS_DECL_NSIIPCSERIALIZABLE
89 : NS_DECL_NSICLASSINFO
90 : NS_DECL_NSIMUTABLE
91 :
92 : // nsISizeOf
93 : virtual size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
94 : virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
95 :
96 : nsStandardURL(bool aSupportsFileURL = false);
97 : virtual ~nsStandardURL();
98 :
99 : static void InitGlobalObjects();
100 : static void ShutdownGlobalObjects();
101 :
102 : public: /* internal -- HPUX compiler can't handle this being private */
103 : //
104 : // location and length of an url segment relative to mSpec
105 : //
106 : struct URLSegment
107 : {
108 : PRUint32 mPos;
109 : PRInt32 mLen;
110 :
111 3590554 : URLSegment() : mPos(0), mLen(-1) {}
112 1336 : URLSegment(PRUint32 pos, PRInt32 len) : mPos(pos), mLen(len) {}
113 3204762 : void Reset() { mPos = 0; mLen = -1; }
114 : // Merge another segment following this one to it if they're contiguous
115 : // Assumes we have something like "foo;bar" where this object is 'foo' and right
116 : // is 'bar'.
117 0 : void Merge(const nsCString &spec, const char separator, const URLSegment &right) {
118 0 : if (mLen >= 0 &&
119 0 : *(spec.get() + mPos + mLen) == separator &&
120 : mPos + mLen + 1 == right.mPos) {
121 0 : mLen += 1 + right.mLen;
122 : }
123 0 : }
124 : };
125 :
126 : //
127 : // Pref observer
128 : //
129 : class nsPrefObserver : public nsIObserver
130 : {
131 : public:
132 : NS_DECL_ISUPPORTS
133 : NS_DECL_NSIOBSERVER
134 :
135 1419 : nsPrefObserver() { }
136 : };
137 : friend class nsPrefObserver;
138 :
139 : //
140 : // URL segment encoder : performs charset conversion and URL escaping.
141 : //
142 : class nsSegmentEncoder
143 583931 : {
144 : public:
145 : nsSegmentEncoder(const char *charset);
146 :
147 : // Encode the given segment if necessary, and return the length of
148 : // the encoded segment. The encoded segment is appended to |buf|
149 : // if and only if encoding is required.
150 : PRInt32 EncodeSegmentCount(const char *str,
151 : const URLSegment &segment,
152 : PRInt16 mask,
153 : nsAFlatCString &buf,
154 : bool& appended,
155 : PRUint32 extraLen = 0);
156 :
157 : // Encode the given string if necessary, and return a reference to
158 : // the encoded string. Returns a reference to |buf| if encoding
159 : // is required. Otherwise, a reference to |str| is returned.
160 : const nsACString &EncodeSegment(const nsASingleFragmentCString &str,
161 : PRInt16 mask,
162 : nsAFlatCString &buf);
163 : private:
164 : bool InitUnicodeEncoder();
165 :
166 : const char* mCharset; // Caller should keep this alive for
167 : // the life of the segment encoder
168 : nsCOMPtr<nsIUnicodeEncoder> mEncoder;
169 : };
170 : friend class nsSegmentEncoder;
171 :
172 : protected:
173 : // enum used in a few places to specify how .ref attribute should be handled
174 : enum RefHandlingEnum {
175 : eIgnoreRef,
176 : eHonorRef
177 : };
178 :
179 : // Helper to share code between Equals and EqualsExceptRef
180 : // NOTE: *not* virtual, because no one needs to override this so far...
181 : nsresult EqualsInternal(nsIURI* unknownOther,
182 : RefHandlingEnum refHandlingMode,
183 : bool* result);
184 :
185 : virtual nsStandardURL* StartClone();
186 :
187 : // Helper to share code between Clone methods.
188 : nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
189 : nsIURI** aClone);
190 :
191 : // Helper for subclass implementation of GetFile(). Subclasses that map
192 : // URIs to files in a special way should implement this method. It should
193 : // ensure that our mFile is initialized, if it's possible.
194 : // returns NS_ERROR_NO_INTERFACE if the url does not map to a file
195 : virtual nsresult EnsureFile();
196 :
197 : private:
198 42604 : PRInt32 Port() { return mPort == -1 ? mDefaultPort : mPort; }
199 :
200 : void Clear();
201 : void InvalidateCache(bool invalidateCachedFile = true);
202 :
203 : bool EscapeIPv6(const char *host, nsCString &result);
204 : bool NormalizeIDN(const nsCSubstring &host, nsCString &result);
205 : void CoalescePath(netCoalesceFlags coalesceFlag, char *path);
206 :
207 : PRUint32 AppendSegmentToBuf(char *, PRUint32, const char *, URLSegment &, const nsCString *esc=nsnull, bool useEsc = false);
208 : PRUint32 AppendToBuf(char *, PRUint32, const char *, PRUint32);
209 :
210 : nsresult BuildNormalizedSpec(const char *spec);
211 :
212 : bool SegmentIs(const URLSegment &s1, const char *val, bool ignoreCase = false);
213 : bool SegmentIs(const char* spec, const URLSegment &s1, const char *val, bool ignoreCase = false);
214 : bool SegmentIs(const URLSegment &s1, const char *val, const URLSegment &s2, bool ignoreCase = false);
215 :
216 : PRInt32 ReplaceSegment(PRUint32 pos, PRUint32 len, const char *val, PRUint32 valLen);
217 : PRInt32 ReplaceSegment(PRUint32 pos, PRUint32 len, const nsACString &val);
218 :
219 : nsresult ParseURL(const char *spec, PRInt32 specLen);
220 : nsresult ParsePath(const char *spec, PRUint32 pathPos, PRInt32 pathLen = -1);
221 :
222 : char *AppendToSubstring(PRUint32 pos, PRInt32 len, const char *tail);
223 :
224 : // dependent substring helpers
225 : const nsDependentCSubstring Segment(PRUint32 pos, PRInt32 len); // see below
226 459765 : const nsDependentCSubstring Segment(const URLSegment &s) { return Segment(s.mPos, s.mLen); }
227 :
228 : // dependent substring getters
229 : const nsDependentCSubstring Prepath(); // see below
230 301601 : const nsDependentCSubstring Scheme() { return Segment(mScheme); }
231 : const nsDependentCSubstring Userpass(bool includeDelim = false); // see below
232 302 : const nsDependentCSubstring Username() { return Segment(mUsername); }
233 260 : const nsDependentCSubstring Password() { return Segment(mPassword); }
234 : const nsDependentCSubstring Hostport(); // see below
235 : const nsDependentCSubstring Host(); // see below
236 134585 : const nsDependentCSubstring Path() { return Segment(mPath); }
237 770 : const nsDependentCSubstring Filepath() { return Segment(mFilepath); }
238 18941 : const nsDependentCSubstring Directory() { return Segment(mDirectory); }
239 : const nsDependentCSubstring Filename(); // see below
240 222 : const nsDependentCSubstring Basename() { return Segment(mBasename); }
241 1358 : const nsDependentCSubstring Extension() { return Segment(mExtension); }
242 472 : const nsDependentCSubstring Query() { return Segment(mQuery); }
243 1253 : const nsDependentCSubstring Ref() { return Segment(mRef); }
244 :
245 : // shift the URLSegments to the right by diff
246 0 : void ShiftFromAuthority(PRInt32 diff) { mAuthority.mPos += diff; ShiftFromUsername(diff); }
247 0 : void ShiftFromUsername(PRInt32 diff) { mUsername.mPos += diff; ShiftFromPassword(diff); }
248 0 : void ShiftFromPassword(PRInt32 diff) { mPassword.mPos += diff; ShiftFromHost(diff); }
249 0 : void ShiftFromHost(PRInt32 diff) { mHost.mPos += diff; ShiftFromPath(diff); }
250 7 : void ShiftFromPath(PRInt32 diff) { mPath.mPos += diff; ShiftFromFilepath(diff); }
251 7 : void ShiftFromFilepath(PRInt32 diff) { mFilepath.mPos += diff; ShiftFromDirectory(diff); }
252 7 : void ShiftFromDirectory(PRInt32 diff) { mDirectory.mPos += diff; ShiftFromBasename(diff); }
253 19 : void ShiftFromBasename(PRInt32 diff) { mBasename.mPos += diff; ShiftFromExtension(diff); }
254 19 : void ShiftFromExtension(PRInt32 diff) { mExtension.mPos += diff; ShiftFromQuery(diff); }
255 19 : void ShiftFromQuery(PRInt32 diff) { mQuery.mPos += diff; ShiftFromRef(diff); }
256 413 : void ShiftFromRef(PRInt32 diff) { mRef.mPos += diff; }
257 :
258 : // fastload helper functions
259 : nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);
260 : nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &);
261 :
262 : // ipc helper functions
263 : bool ReadSegment(const IPC::Message *, void **, URLSegment &);
264 : void WriteSegment(IPC::Message *, const URLSegment &);
265 :
266 : static void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
267 :
268 : // mSpec contains the normalized version of the URL spec (UTF-8 encoded).
269 : nsCString mSpec;
270 : PRInt32 mDefaultPort;
271 : PRInt32 mPort;
272 :
273 : // url parts (relative to mSpec)
274 : URLSegment mScheme;
275 : URLSegment mAuthority;
276 : URLSegment mUsername;
277 : URLSegment mPassword;
278 : URLSegment mHost;
279 : URLSegment mPath;
280 : URLSegment mFilepath;
281 : URLSegment mDirectory;
282 : URLSegment mBasename;
283 : URLSegment mExtension;
284 : URLSegment mQuery;
285 : URLSegment mRef;
286 :
287 : nsCString mOriginCharset;
288 : nsCOMPtr<nsIURLParser> mParser;
289 :
290 : // mFile is protected so subclasses can access it directly
291 : protected:
292 : nsCOMPtr<nsIFile> mFile; // cached result for nsIFileURL::GetFile
293 :
294 : private:
295 : char *mHostA; // cached result for nsIURI::GetHostA
296 :
297 : enum {
298 : eEncoding_Unknown,
299 : eEncoding_ASCII,
300 : eEncoding_UTF8
301 : };
302 :
303 : PRUint32 mHostEncoding : 2; // eEncoding_xxx
304 : PRUint32 mSpecEncoding : 2; // eEncoding_xxx
305 : PRUint32 mURLType : 2; // nsIStandardURL::URLTYPE_xxx
306 : PRUint32 mMutable : 1; // nsIStandardURL::mutable
307 : PRUint32 mSupportsFileURL : 1; // QI to nsIFileURL?
308 :
309 : // global objects. don't use COMPtr as its destructor will cause a
310 : // coredump if we leak it.
311 : static nsIIDNService *gIDN;
312 : static nsICharsetConverterManager *gCharsetMgr;
313 : static bool gInitialized;
314 : static bool gEscapeUTF8;
315 : static bool gAlwaysEncodeInUTF8;
316 : static bool gEncodeQueryInUTF8;
317 :
318 : public:
319 : #ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
320 : PRCList mDebugCList;
321 536 : void PrintSpec() const { printf(" %s\n", mSpec.get()); }
322 : #endif
323 : };
324 :
325 : #define NS_THIS_STANDARDURL_IMPL_CID \
326 : { /* b8e3e97b-1ccd-4b45-af5a-79596770f5d7 */ \
327 : 0xb8e3e97b, \
328 : 0x1ccd, \
329 : 0x4b45, \
330 : {0xaf, 0x5a, 0x79, 0x59, 0x67, 0x70, 0xf5, 0xd7} \
331 : }
332 :
333 : //-----------------------------------------------------------------------------
334 : // Dependent substring getters
335 : //-----------------------------------------------------------------------------
336 :
337 : inline const nsDependentCSubstring
338 459765 : nsStandardURL::Segment(PRUint32 pos, PRInt32 len)
339 : {
340 459765 : if (len < 0) {
341 3225 : pos = 0;
342 3225 : len = 0;
343 : }
344 459765 : return Substring(mSpec, pos, PRUint32(len));
345 : }
346 :
347 : inline const nsDependentCSubstring
348 576 : nsStandardURL::Prepath()
349 : {
350 576 : PRUint32 len = 0;
351 576 : if (mAuthority.mLen >= 0)
352 576 : len = mAuthority.mPos + mAuthority.mLen;
353 576 : return Substring(mSpec, 0, len);
354 : }
355 :
356 : inline const nsDependentCSubstring
357 253 : nsStandardURL::Userpass(bool includeDelim)
358 : {
359 253 : PRUint32 pos=0, len=0;
360 : // if there is no username, then there can be no password
361 253 : if (mUsername.mLen > 0) {
362 0 : pos = mUsername.mPos;
363 0 : len = mUsername.mLen;
364 0 : if (mPassword.mLen >= 0)
365 0 : len += (mPassword.mLen + 1);
366 0 : if (includeDelim)
367 0 : len++;
368 : }
369 253 : return Substring(mSpec, pos, len);
370 : }
371 :
372 : inline const nsDependentCSubstring
373 8324 : nsStandardURL::Hostport()
374 : {
375 8324 : PRUint32 pos=0, len=0;
376 8324 : if (mAuthority.mLen > 0) {
377 8324 : pos = mHost.mPos;
378 8324 : len = mAuthority.mPos + mAuthority.mLen - pos;
379 : }
380 8324 : return Substring(mSpec, pos, len);
381 : }
382 :
383 : inline const nsDependentCSubstring
384 176557 : nsStandardURL::Host()
385 : {
386 176557 : PRUint32 pos=0, len=0;
387 176557 : if (mHost.mLen > 0) {
388 172895 : pos = mHost.mPos;
389 172895 : len = mHost.mLen;
390 172895 : if (mSpec.CharAt(pos) == '[' && mSpec.CharAt(pos + len - 1) == ']') {
391 2 : pos++;
392 2 : len -= 2;
393 : }
394 : }
395 176557 : return Substring(mSpec, pos, len);
396 : }
397 :
398 : inline const nsDependentCSubstring
399 233 : nsStandardURL::Filename()
400 : {
401 233 : PRUint32 pos=0, len=0;
402 : // if there is no basename, then there can be no extension
403 233 : if (mBasename.mLen > 0) {
404 77 : pos = mBasename.mPos;
405 77 : len = mBasename.mLen;
406 77 : if (mExtension.mLen >= 0)
407 4 : len += (mExtension.mLen + 1);
408 : }
409 233 : return Substring(mSpec, pos, len);
410 : }
411 :
412 : #endif // nsStandardURL_h__
|